diff --git a/app/Livewire/OnlineCalendar.php b/app/Livewire/OnlineCalendar.php index 57e65d30f..1e9a7c03d 100644 --- a/app/Livewire/OnlineCalendar.php +++ b/app/Livewire/OnlineCalendar.php @@ -33,16 +33,14 @@ public function mount() ->orderBy('start_date') ->get(['start_date']) ->groupBy(function ($event) { - $date = Carbon::parse($event->start_date); - - return $date->month.'/'.$date->year; + return $this->effectiveStart($event->start_date)->format('n/Y'); }) ->map(function ($group, $id) { - $date = Carbon::parse($group->first()->start_date); + [$month, $year] = explode('/', $id); return [ 'id' => $id, - 'name' => $date->format('F').' '.$date->year, + 'name' => Carbon::createFromDate((int) $year, (int) $month, 1)->format('F Y'), ]; }) ->values() @@ -68,11 +66,22 @@ public function render() $this->selectedMonth = (int) ($parts[0] ?: $this->selectedMonth); $this->selectedYear = (int) ($parts[1] ?? $this->selectedYear); - $query->whereMonth('start_date', $this->selectedMonth) - ->whereYear('start_date', $this->selectedYear); + $monthStart = Carbon::createFromDate($this->selectedYear, $this->selectedMonth, 1)->startOfMonth(); + + $query->where(function ($monthQuery) use ($monthStart) { + $monthQuery->whereBetween('start_date', [$monthStart, $monthStart->copy()->endOfMonth()]); + + if ($monthStart->isSameMonth(Carbon::now())) { + $monthQuery->orWhere('start_date', '<', $monthStart); + } + }); } - $events = $query->get(); + $events = $query->get() + ->sortBy(function ($event) { + return $this->effectiveStart($event->start_date)->getTimestamp(); + }) + ->values(); $events->each(function ($event) { $event->title = str_limit($event->title, 50); @@ -124,12 +133,24 @@ public function render() private function baseQuery() { + // Only the end date gates the list: an activity that began earlier but has not + // finished is still open to participants. return Event::where([ 'activity_type' => 'open-online', 'status' => 'APPROVED', - ]) - ->where('start_date', '>=', Carbon::now()->firstOfMonth()) - ->where('end_date', '>=', Carbon::now()); + ])->where('end_date', '>=', Carbon::now()); + } + + /** + * Activities already under way are listed under the current month rather than the + * month they originally started in, which may be long past. + */ + private function effectiveStart($startDate): Carbon + { + $start = Carbon::parse($startDate); + $currentMonth = Carbon::now()->firstOfMonth(); + + return $start->lessThan($currentMonth) ? $currentMonth : $start; } private function eventMatchesLanguage($event, string $selectedLanguage): bool diff --git a/tests/Feature/OnlineEventsWorkflowTest.php b/tests/Feature/OnlineEventsWorkflowTest.php index 53c764c09..4d366262c 100644 --- a/tests/Feature/OnlineEventsWorkflowTest.php +++ b/tests/Feature/OnlineEventsWorkflowTest.php @@ -317,6 +317,71 @@ public function featured_activities_month_filter_only_shows_events_for_selected_ ->assertDontSee($novemberEvent->title); } + #[Test] + public function featured_activities_page_lists_activities_already_under_way(): void + { + $this->seed('RolesAndPermissionsSeeder'); + + $ongoing = \App\Event::factory()->create([ + 'start_date' => Carbon::now()->subMonths(4), + 'end_date' => Carbon::now()->addMonths(6), + 'status' => 'APPROVED', + 'activity_type' => 'open-online', + 'highlighted_status' => 'NONE', + 'language' => ['en'], + 'title' => 'Still Running Open Online Activity', + ]); + + $finished = \App\Event::factory()->create([ + 'start_date' => Carbon::now()->subMonths(4), + 'end_date' => Carbon::now()->subMonth(), + 'status' => 'APPROVED', + 'activity_type' => 'open-online', + 'highlighted_status' => 'NONE', + 'language' => ['en'], + 'title' => 'Already Finished Open Online Activity', + ]); + + $this->get('/featured-activities') + ->assertStatus(200) + ->assertSee($ongoing->title) + ->assertDontSee($finished->title); + } + + #[Test] + public function activities_already_under_way_are_listed_under_the_current_month(): void + { + $this->seed('RolesAndPermissionsSeeder'); + + $startedFourMonthsAgo = Carbon::now()->subMonths(4); + + $ongoing = \App\Event::factory()->create([ + 'start_date' => $startedFourMonthsAgo, + 'end_date' => Carbon::now()->addMonths(6), + 'status' => 'APPROVED', + 'activity_type' => 'open-online', + 'highlighted_status' => 'NONE', + 'language' => ['en'], + 'title' => 'Ongoing Grouped Under Current Month', + ]); + + $now = Carbon::now(); + + \Livewire\Livewire::test(\App\Livewire\OnlineCalendar::class) + ->set('selectedDate', $now->month.'/'.$now->year) + ->assertSee($ongoing->title); + + $monthIds = collect(\Livewire\Livewire::test(\App\Livewire\OnlineCalendar::class)->get('months')) + ->pluck('id'); + + $this->assertContains($now->month.'/'.$now->year, $monthIds); + $this->assertNotContains( + $startedFourMonthsAgo->month.'/'.$startedFourMonthsAgo->year, + $monthIds, + 'The month filter should not offer a past month just because an ongoing activity started then.' + ); + } + #[Test] public function promoted_event_creates_notification_for_administrators(): void {