import { create } from 'zustand'; import { apiFetch } from '@/lib/browser-navigation'; import type { Resource, ResourceBooking } from '@/lib/resources/client'; interface ResourceState { resources: Resource[]; selectedResources: Resource[]; bookings: ResourceBooking[]; isLoading: boolean; bookingError: string | null; fetchResources: (type?: string) => Promise; searchResources: (query: string) => Resource[]; toggleResource: (resource: Resource) => void; selectResource: (resource: Resource) => void; deselectResource: (resourceId: string) => void; clearSelection: () => void; fetchEventBookings: (eventId: string) => Promise; bookSelectedResources: (start: string, end: string, eventId?: string) => Promise; cancelBooking: (bookingId: string) => Promise; cancelEventBookings: (eventId: string) => Promise; } export const useResourceStore = create()((set, get) => ({ resources: [], selectedResources: [], bookings: [], isLoading: false, bookingError: null, fetchResources: async (type?: string) => { set({ isLoading: true }); try { const params = new URLSearchParams(); if (type) params.set('type', type); const res = await apiFetch(`/api/resources?${params.toString()}`); if (!res.ok) throw new Error('Failed to fetch resources'); const data = await res.json(); set({ resources: data.resources, isLoading: false }); } catch { set({ isLoading: false }); } }, searchResources: (query: string) => { const { resources } = get(); if (!query.trim()) return resources; const lower = query.toLowerCase(); return resources.filter( (r) => r.name.toLowerCase().includes(lower) || (r.location && r.location.toLowerCase().includes(lower)) || (r.description && r.description.toLowerCase().includes(lower)) ); }, toggleResource: (resource: Resource) => { const { selectedResources } = get(); const exists = selectedResources.some((r) => r.id === resource.id); if (exists) { set({ selectedResources: selectedResources.filter((r) => r.id !== resource.id) }); } else { set({ selectedResources: [...selectedResources, resource] }); } }, selectResource: (resource: Resource) => { const { selectedResources } = get(); if (!selectedResources.some((r) => r.id === resource.id)) { set({ selectedResources: [...selectedResources, resource] }); } }, deselectResource: (resourceId: string) => { set({ selectedResources: get().selectedResources.filter((r) => r.id !== resourceId) }); }, clearSelection: () => { set({ selectedResources: [], bookingError: null }); }, fetchEventBookings: async (eventId: string) => { try { const res = await apiFetch(`/api/resources?eventId=${encodeURIComponent(eventId)}`); if (!res.ok) return; const data = await res.json(); set({ bookings: data.bookings || [] }); } catch { // silently fail } }, bookSelectedResources: async (start: string, end: string, eventId?: string) => { set({ bookingError: null }); const { selectedResources } = get(); const bookedIds: string[] = []; for (const resource of selectedResources) { try { const res = await apiFetch(`/api/resources/${resource.id}/book`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ start, end, eventId }), }); if (!res.ok) { const data = await res.json(); set({ bookingError: `${resource.name}: ${data.error}` }); continue; } const data = await res.json(); bookedIds.push(data.booking.id); } catch { set({ bookingError: `Failed to book ${resource.name}` }); } } return bookedIds; }, cancelBooking: async (bookingId: string) => { const { bookings } = get(); const booking = bookings.find((b) => b.id === bookingId); if (!booking) return; try { const res = await apiFetch( `/api/resources/${booking.resourceId}/book/${bookingId}`, { method: 'DELETE' } ); if (res.ok) { set({ bookings: bookings.filter((b) => b.id !== bookingId) }); } } catch { // silently fail } }, cancelEventBookings: async (_eventId: string) => { const { bookings } = get(); for (const booking of bookings) { try { const res = await apiFetch( `/api/resources/${booking.resourceId}/book/${booking.id}`, { method: 'DELETE' } ); if (res.ok) continue; } catch { // silently fail } } set({ bookings: [] }); }, }));