diff --git a/app/Livewire/PartnerFilterComponent.php b/app/Livewire/PartnerFilterComponent.php index 8a52e6d75..99f9406cb 100644 --- a/app/Livewire/PartnerFilterComponent.php +++ b/app/Livewire/PartnerFilterComponent.php @@ -12,8 +12,9 @@ class PartnerFilterComponent extends Component // This function will be triggered when a filter is selected public function selectFilter($filter) { - $this->selectedFilter = $filter; // Update the filter - $this->dispatch('filterChanged', filter: $filter); // Dispatch an event in Livewire v3 + $this->selectedFilter = $filter; + $this->dispatch('filterChanged', filter: $filter) + ->to(PartnerContentComponent::class); } public function render() diff --git a/resources/views/livewire/filter-component.blade.php b/resources/views/livewire/filter-component.blade.php index c31e69abd..5543d0070 100644 --- a/resources/views/livewire/filter-component.blade.php +++ b/resources/views/livewire/filter-component.blade.php @@ -1,9 +1,13 @@
diff --git a/resources/views/static/sponsors.blade.php b/resources/views/static/sponsors.blade.php index acde499af..454f2b5b8 100644 --- a/resources/views/static/sponsors.blade.php +++ b/resources/views/static/sponsors.blade.php @@ -17,7 +17,10 @@ } } -@section('content') +{{-- Must use non-vue-content: Vue mounts on #app and re-renders its DOM, which + detaches Livewire's bound elements and leaves unbound clones. Filter tabs + then look clickable but never fire wire:click / filterChanged. --}} +@section('non-vue-content')
diff --git a/tests/Feature/PartnersPageFilterTest.php b/tests/Feature/PartnersPageFilterTest.php new file mode 100644 index 000000000..ac846fbc4 --- /dev/null +++ b/tests/Feature/PartnersPageFilterTest.php @@ -0,0 +1,55 @@ +get(route('sponsors'))->assertOk()->getContent(); + + $appPos = strpos($html, 'id="app"'); + $nonVuePos = strpos($html, 'id="non-vue"'); + $sponsorsPos = strpos($html, 'id="codeweek-sponsors-page"'); + + $this->assertNotFalse($appPos); + $this->assertNotFalse($nonVuePos); + $this->assertNotFalse($sponsorsPos); + + // Vue mounts on #app and re-renders its DOM, which strips Livewire wire: bindings. + // Partner tabs must live in #non-vue so filter clicks keep working. + $this->assertGreaterThan( + $nonVuePos, + $sponsorsPos, + 'Partners page must render in #non-vue, not #app' + ); + } + + #[Test] + public function selecting_a_filter_updates_partner_content(): void + { + Livewire::test(PartnerFilterComponent::class) + ->call('selectFilter', 'Council Presidency') + ->assertSet('selectedFilter', 'Council Presidency') + ->assertDispatched('filterChanged', filter: 'Council Presidency'); + + Livewire::test(PartnerContentComponent::class) + ->dispatch('filterChanged', filter: 'Council Presidency') + ->assertSet('filter', 'Council Presidency') + ->assertSee('Council President'); + + Livewire::test(PartnerContentComponent::class) + ->dispatch('filterChanged', filter: 'EU Code Week Supporters') + ->assertSet('filter', 'EU Code Week Supporters'); + } +}