From e86cb6a897de9e28b3e6f99f1bcd4d7318959dbc Mon Sep 17 00:00:00 2001 From: Maurice Date: Fri, 9 Oct 2026 15:01:56 +0200 Subject: [PATCH] refactor(bookings): let the phone plugin slots use the reservation detail plugin hook ReservationPluginSlots in tabChrome repeated the plugin store selector that useReservationDetailPlugins already holds for the desktop panels. It now calls the hook, which gets its own test. --- .../useReservationDetailPlugins.test.ts | 34 +++++++++++++++++++ .../mobile/screens/trip/tabs/tabChrome.tsx | 4 +-- 2 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 client/src/components/Planner/bookings/useReservationDetailPlugins.test.ts diff --git a/client/src/components/Planner/bookings/useReservationDetailPlugins.test.ts b/client/src/components/Planner/bookings/useReservationDetailPlugins.test.ts new file mode 100644 index 000000000..a8ef76fcb --- /dev/null +++ b/client/src/components/Planner/bookings/useReservationDetailPlugins.test.ts @@ -0,0 +1,34 @@ +import { renderHook } from '@testing-library/react'; +import { afterEach, describe, expect, it } from 'vitest'; +import { usePluginStore } from '../../../store/pluginStore'; +import { useReservationDetailPlugins } from './useReservationDetailPlugins'; + +type Plugins = ReturnType['plugins']; + +function seedPlugins(plugins: Array<{ id: string; type: string; slot?: string }>) { + usePluginStore.setState({ plugins: plugins as unknown as Plugins }); +} + +afterEach(() => { + usePluginStore.setState({ plugins: [] }); +}); + +describe('useReservationDetailPlugins', () => { + it('keeps only the widgets that draw into a booking detail', () => { + seedPlugins([ + { id: 'flights', type: 'widget', slot: 'reservation-detail' }, + { id: 'side', type: 'widget' }, + { id: 'place', type: 'widget', slot: 'place-detail' }, + { id: 'page', type: 'page', slot: 'reservation-detail' }, + { id: 'seats', type: 'widget', slot: 'reservation-detail' }, + ]); + const { result } = renderHook(() => useReservationDetailPlugins()); + expect(result.current.map((p) => p.id)).toEqual(['flights', 'seats']); + }); + + it('is empty without any such plugin', () => { + seedPlugins([{ id: 'side', type: 'widget' }]); + const { result } = renderHook(() => useReservationDetailPlugins()); + expect(result.current).toEqual([]); + }); +}); diff --git a/client/src/mobile/screens/trip/tabs/tabChrome.tsx b/client/src/mobile/screens/trip/tabs/tabChrome.tsx index 274df40d2..855f8068d 100644 --- a/client/src/mobile/screens/trip/tabs/tabChrome.tsx +++ b/client/src/mobile/screens/trip/tabs/tabChrome.tsx @@ -4,7 +4,7 @@ import type { ReservationTraveler } from '@trek/shared' import { avatarSrc } from '../../../../utils/avatarSrc' import GuestBadge from '../../../../components/shared/GuestBadge' import PluginFrame from '../../../../components/Plugins/PluginFrame' -import { usePluginStore } from '../../../../store/pluginStore' +import { useReservationDetailPlugins } from '../../../../components/Planner/bookings/useReservationDetailPlugins' /** * Scroll body shared by the list-style trip tabs (transports, bookings, costs, @@ -133,7 +133,7 @@ export function StatusDot({ color }: { color: string }) { * kit plugin that goes dark with TREK keeps compositing transparently. */ export function ReservationPluginSlots({ tripId, reservationId }: { tripId: number; reservationId: number }) { - const plugins = usePluginStore(s => s.plugins).filter(p => p.type === 'widget' && p.slot === 'reservation-detail') + const plugins = useReservationDetailPlugins() if (plugins.length === 0) return null return (