Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions app/Livewire/OnlineCalendar.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,24 @@
use App\Country;
use App\Event;
use Carbon\Carbon;
use Livewire\Attributes\Url;
use Livewire\Component;
use Livewire\WithPagination;

class OnlineCalendar extends Component
{
use WithPagination;

// The pagination links are ordinary hrefs, so every page change is a fresh request.
// Both filters have to travel in the URL or the new page comes back unfiltered.
#[Url(as: 'language')]
public $selectedLanguage = '';

public $selectedYear;

public $selectedMonth;

#[Url(as: 'month')]
public $selectedDate = 'all';

public $months = [];
Expand All @@ -26,8 +31,6 @@ public function mount()
{
$this->selectedYear = Carbon::now()->year;
$this->selectedMonth = Carbon::now()->month;
$this->selectedDate = 'all';
$this->selectedLanguage = '';

$this->months = $this->baseQuery()
->orderBy('start_date')
Expand Down Expand Up @@ -114,13 +117,25 @@ public function render()
return view('livewire.online-calendar', [
'countryNames' => $this->getCountryNamesFromEvents($events),
'languages' => $languages,
'filteredEvents' => $filteredEvents->paginate(24),
'filteredEvents' => $filteredEvents->paginate(24)->appends($this->activeFilters()),
'totalUpcoming' => $totalUpcoming,
'visibleCount' => $filteredEvents->count(),
'monthLabel' => $monthLabel,
]);
}

/**
* The active filters under the names they use in the URL, so that the page links
* rebuilt by the paginator carry them over.
*/
private function activeFilters(): array
{
return array_filter([
'language' => $this->selectedLanguage,
'month' => $this->selectedDate === 'all' ? null : $this->selectedDate,
]);
}

private function baseQuery()
{
// The start date alone decides what is upcoming. Gating on the end date instead
Expand Down
6 changes: 3 additions & 3 deletions resources/views/livewire/online-calendar.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
wire:model.live="selectedDate"
class="w-full appearance-none rounded-full border border-slate-200 bg-white py-3 pl-12 pr-10 text-slate-500 font-semibold focus:outline-none focus:ring-2 focus:ring-[#1C4DA1]"
>
<option value="all">All months</option>
<option value="all" @selected($selectedDate === 'all')>All months</option>
@foreach($months as $month)
<option value="{{ $month['id'] }}">{{ $month['name'] }}</option>
<option value="{{ $month['id'] }}" @selected($month['id'] === $selectedDate)>{{ $month['name'] }}</option>
@endforeach
</select>
</div>
Expand All @@ -29,7 +29,7 @@ class="w-full appearance-none rounded-full border border-slate-200 bg-white py-3
class="w-full appearance-none rounded-full border border-slate-200 bg-white py-3 px-4 text-slate-500 font-semibold focus:outline-none focus:ring-2 focus:ring-[#1C4DA1]"
>
@foreach($languages as $language)
<option value="{{ $language['id'] }}">{{ $language['name'] }}</option>
<option value="{{ $language['id'] }}" @selected($language['id'] === $selectedLanguage)>{{ $language['name'] }}</option>
@endforeach
</select>
</div>
Expand Down
151 changes: 151 additions & 0 deletions tests/Feature/OnlineActivitiesFilterPaginationTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
<?php

namespace Tests\Feature;

use App\Event;
use App\Livewire\OnlineCalendar;
use Carbon\Carbon;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;
use PHPUnit\Framework\Attributes\Test;
use Tests\TestCase;

class OnlineActivitiesFilterPaginationTest extends TestCase
{
use RefreshDatabase;

private function makeActivity(string $title, array $languages): Event
{
return Event::factory()->create([
'start_date' => Carbon::now()->addWeek(),
'end_date' => Carbon::now()->addWeek()->addDay(),
'status' => 'APPROVED',
'activity_type' => 'open-online',
'highlighted_status' => 'NONE',
'language' => $languages,
'title' => $title,
]);
}

/**
* Reported by the ambassadors: pick a language, walk to page two and the list is
* back to every language, because the page link is an ordinary browser navigation
* and the chosen filter never reached the URL.
*/
#[Test]
public function the_language_filter_survives_a_jump_to_the_second_page(): void
{
$this->seed('RolesAndPermissionsSeeder');

// 25 English activities push the English-only list onto a second page.
for ($i = 1; $i <= 25; $i++) {
$this->makeActivity('English Activity Number '.$i, ['en']);
}

$german = $this->makeActivity('German Only Activity', ['de']);

$this->get('/online-activities?language=en&page=2')
->assertStatus(200)
->assertDontSee($german->title);
}

#[Test]
public function the_month_filter_survives_a_jump_to_the_second_page(): void
{
$this->seed('RolesAndPermissionsSeeder');

$nextMonth = Carbon::now()->addMonthNoOverflow()->startOfMonth();

for ($i = 1; $i <= 25; $i++) {
Event::factory()->create([
'start_date' => $nextMonth->copy()->addDays(2),
'end_date' => $nextMonth->copy()->addDays(3),
'status' => 'APPROVED',
'activity_type' => 'open-online',
'highlighted_status' => 'NONE',
'language' => ['en'],
'title' => 'Next Month Activity Number '.$i,
]);
}

$thisWeek = $this->makeActivity('Happening This Week Activity', ['en']);

$month = $nextMonth->month.'/'.$nextMonth->year;

$this->get('/online-activities?month='.urlencode($month).'&page=2')
->assertStatus(200)
->assertSee('for '.$nextMonth->format('F Y'))
->assertDontSee($thisWeek->title);
}

#[Test]
public function pagination_links_carry_the_active_filters(): void
{
$this->seed('RolesAndPermissionsSeeder');

for ($i = 1; $i <= 25; $i++) {
$this->makeActivity('English Activity Number '.$i, ['en']);
}

$html = $this->get('/online-activities?language=en')->getContent();

$this->assertMatchesRegularExpression(
'/href="[^"]*page=2[^"]*language=en|href="[^"]*language=en[^"]*page=2/',
$html,
'The link to page two must keep the chosen language.'
);
}

/**
* The order the ambassadors hit it in: pick the language from the dropdown, which is
* a Livewire round trip, then click page two, which is a browser navigation.
*/
#[Test]
public function choosing_a_language_then_paginating_keeps_the_language(): void
{
$this->seed('RolesAndPermissionsSeeder');

for ($i = 1; $i <= 25; $i++) {
$this->makeActivity('English Activity Number '.$i, ['en']);
}

$german = $this->makeActivity('German Only Activity', ['de']);

$html = Livewire::test(OnlineCalendar::class)
->set('selectedLanguage', 'en')
->html();

preg_match('/href="([^"]*page=2[^"]*)"/', $html, $matches);

$this->assertNotEmpty($matches, 'A link to page two should be rendered.');

$this->get($matches[1])
->assertStatus(200)
->assertDontSee($german->title);
}

#[Test]
public function the_dropdowns_show_the_filter_that_is_in_force(): void
{
$this->seed('RolesAndPermissionsSeeder');

$this->makeActivity('English Activity', ['en']);
$this->makeActivity('German Activity', ['de']);

$this->get('/online-activities?language=en')
->assertStatus(200)
->assertSee('<option value="en" selected>English</option>', false);
}

#[Test]
public function the_filters_are_read_from_the_query_string(): void
{
$this->seed('RolesAndPermissionsSeeder');

$this->makeActivity('English Activity', ['en']);

Livewire::withQueryParams(['language' => 'en'])
->test(OnlineCalendar::class)
->assertSet('selectedLanguage', 'en');
}
}
Loading