payload-reserve 2.1.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +58 -1
  2. package/dist/components/CalendarView/CalendarView.module.css +11 -0
  3. package/dist/components/CalendarView/LaneTimelineView.js +3 -1
  4. package/dist/components/CalendarView/LaneTimelineView.js.map +1 -1
  5. package/dist/components/CalendarView/index.js +8 -0
  6. package/dist/components/CalendarView/index.js.map +1 -1
  7. package/dist/defaults.js +1 -0
  8. package/dist/defaults.js.map +1 -1
  9. package/dist/endpoints/checkAvailability.js +1 -0
  10. package/dist/endpoints/checkAvailability.js.map +1 -1
  11. package/dist/endpoints/getSlots.js +1 -0
  12. package/dist/endpoints/getSlots.js.map +1 -1
  13. package/dist/endpoints/resourceAvailability.d.ts +6 -2
  14. package/dist/endpoints/resourceAvailability.js +19 -1
  15. package/dist/endpoints/resourceAvailability.js.map +1 -1
  16. package/dist/hooks/reservations/validateConflicts.js +1 -0
  17. package/dist/hooks/reservations/validateConflicts.js.map +1 -1
  18. package/dist/index.d.ts +1 -1
  19. package/dist/index.js.map +1 -1
  20. package/dist/services/AvailabilityService.d.ts +9 -2
  21. package/dist/services/AvailabilityService.js +26 -3
  22. package/dist/services/AvailabilityService.js.map +1 -1
  23. package/dist/translations/ar.json +1 -0
  24. package/dist/translations/de.json +1 -0
  25. package/dist/translations/en.json +1 -0
  26. package/dist/translations/es.json +1 -0
  27. package/dist/translations/fa.json +1 -0
  28. package/dist/translations/fr.json +1 -0
  29. package/dist/translations/hi.json +1 -0
  30. package/dist/translations/id.json +1 -0
  31. package/dist/translations/pl.json +1 -0
  32. package/dist/translations/ru.json +1 -0
  33. package/dist/translations/tr.json +1 -0
  34. package/dist/translations/zh.json +1 -0
  35. package/dist/types.d.ts +27 -0
  36. package/dist/types.js.map +1 -1
  37. package/dist/utilities/computeSlotStates.d.ts +2 -1
  38. package/dist/utilities/computeSlotStates.js +5 -1
  39. package/dist/utilities/computeSlotStates.js.map +1 -1
  40. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/CalendarView/index.tsx"],"sourcesContent":["'use client'\nimport type { AdminViewServerProps } from 'payload'\n\nimport { useConfig, useDocumentDrawer, useTranslation } from '@payloadcms/ui'\nimport React, { Fragment, useCallback, useEffect, useMemo, useRef, useState } from 'react'\n\nimport type { PluginT } from '../../translations/index.js'\nimport type { SlotInfo } from '../../utilities/computeSlotStates.js'\n\nimport { computeSlotStates } from '../../utilities/computeSlotStates.js'\nimport { statusToI18nKey } from '../../utilities/i18nUtils.js'\nimport { getDayKeyInTimezone, getHourInTimezone } from '../../utilities/timezoneUtils.js'\nimport { useTenantFilter } from '../../utilities/useTenantFilter.js'\nimport styles from './CalendarView.module.css'\nimport { LaneTimelineView } from './LaneTimelineView.js'\nimport { useResourceAvailability } from './useResourceAvailability.js'\n\ntype ViewMode = 'day' | 'lanes' | 'month' | 'pending' | 'week'\n\ntype ReservationItem = {\n endTime?: string\n guestCount?: number\n resource?: { id?: string; name?: string } | string\n service?: { name?: string } | string\n startTime?: string\n}\n\ntype Reservation = {\n customer?: { firstName?: string; lastName?: string; name?: string } | string\n endTime?: string\n id: string\n items?: ReservationItem[]\n resource?: { id?: string; name?: string } | string\n service?: { name?: string } | string\n startTime: string\n status: string\n}\n\ntype ResourceOption = {\n id: string\n name: string\n}\n\n// Built-in status → CSS class map (for known statuses; custom statuses use inline style)\nconst STATUS_CLASS_MAP: Record<string, string> = {\n cancelled: styles.statusCancelled,\n completed: styles.statusCompleted,\n confirmed: styles.statusConfirmed,\n 'no-show': styles.statusNoShow,\n pending: styles.statusPending,\n}\n\n// Built-in default colors for known statuses\nconst BUILTIN_STATUS_COLORS: Record<string, string> = {\n cancelled: '#e5e7eb',\n completed: '#d1fae5',\n confirmed: '#dbeafe',\n 'no-show': '#fee2e2',\n pending: '#fef3c7',\n}\n\n// Palette for auto-assigning colors to custom statuses\nconst CUSTOM_STATUS_PALETTE = ['#fde68a', '#c7d2fe', '#a7f3d0', '#fca5a5', '#fdba74']\n\n// Safe ceiling for list fetches; when totalDocs exceeds this we surface a\n// \"showing N of M\" notice rather than silently truncating (review D9).\nconst MAX_LIST_LIMIT = 2000\n\n// Default visible-hour window for the week/day/lane grids; the actual window\n// expands to include any booking outside it so nothing is hidden (review D8).\nconst DEFAULT_HOUR_START = 7\nconst DEFAULT_HOUR_END = 20\n\n/**\n * Visible-hour window covering `reservations` (in `timeZone`), never narrower\n * than the default business window. Every booking's start hour gets a row, so a\n * booking outside 7–20 is shown rather than silently dropped, and all three\n * time views share one window.\n */\nfunction computeHourWindow(\n reservations: Reservation[],\n timeZone: string,\n): { endHour: number; startHour: number } {\n let startHour = DEFAULT_HOUR_START\n let endHour = DEFAULT_HOUR_END\n for (const r of reservations) {\n if (!r.startTime) {continue}\n const sh = getHourInTimezone(new Date(r.startTime), timeZone)\n startHour = Math.min(startHour, sh)\n endHour = Math.max(endHour, sh + 1)\n if (r.endTime) {\n // round the ending hour up so a slot that ends mid-hour still has a row\n endHour = Math.max(endHour, getHourInTimezone(new Date(r.endTime), timeZone) + 1)\n }\n }\n return { endHour: Math.min(endHour, 24), startHour: Math.max(startHour, 0) }\n}\n\nexport const CalendarView: React.FC<AdminViewServerProps> = () => {\n const { config } = useConfig()\n const { t: _t } = useTranslation()\n const t = _t as PluginT\n\n const slugs = config.admin?.custom?.reservationSlugs\n const reservationSlug = slugs?.reservations ?? 'reservations'\n const apiUrl = `${config.serverURL ?? ''}${config.routes.api}/${reservationSlug}`\n const apiBase = `${config.serverURL ?? ''}${config.routes.api}`\n const resourceSlug = slugs?.resources ?? 'resources'\n const reservationTenantParams = useTenantFilter(reservationSlug)\n const resourceTenantParams = useTenantFilter(resourceSlug)\n\n // Day-boundary rendering uses the business timezone. In multiTenant mode that's\n // the SELECTED tenant's zone, resolved server-side from the tenant cookie (the\n // client can't map tenant→zone itself). Until that resolves — and for plain\n // installs — fall back to the static global zone baked into admin config.\n const staticReservationTimezone =\n ((config.admin?.custom as Record<string, unknown> | undefined)?.reservationTimezone as\n | string\n | undefined) ?? 'UTC'\n const [effectiveTimezone, setEffectiveTimezone] = useState<null | string>(null)\n const reservationTimezone = effectiveTimezone ?? staticReservationTimezone\n\n const tenantKey = JSON.stringify(reservationTenantParams)\n useEffect(() => {\n let cancelled = false\n void (async () => {\n try {\n const res = await fetch(`${apiBase}/reserve/effective-timezone`, {\n credentials: 'same-origin',\n })\n if (!res.ok) {\n return\n }\n const json = await res.json()\n if (!cancelled && typeof json?.timeZone === 'string') {\n setEffectiveTimezone(json.timeZone)\n }\n } catch {\n // keep the static fallback\n }\n })()\n return () => {\n cancelled = true\n }\n \n }, [apiBase, tenantKey])\n\n const statusMachine = config.admin?.custom?.reservationStatusMachine as\n | {\n blockingStatuses?: string[]\n defaultStatus?: string\n statuses?: string[]\n terminalStatuses?: string[]\n transitions?: Record<string, string[]>\n }\n | undefined\n\n // The initial/pending status (what \"pending\" view shows)\n const defaultStatus = statusMachine?.defaultStatus ?? 'pending'\n\n // Build STATUS_COLORS dynamically: built-ins first, then auto-assign palette for custom statuses\n const STATUS_COLORS = useMemo<Record<string, string>>(() => {\n const colors = { ...BUILTIN_STATUS_COLORS }\n const statuses = statusMachine?.statuses ?? []\n statuses.forEach((s, i) => {\n if (!colors[s]) {\n colors[s] = CUSTOM_STATUS_PALETTE[i % CUSTOM_STATUS_PALETTE.length]\n }\n })\n return colors\n }, [statusMachine])\n\n // Derive confirm/cancel target statuses from config transitions\n // \"confirm\" = first non-terminal transition from defaultStatus\n // \"cancel\" = first terminal transition from defaultStatus (or fallback: 'cancelled')\n const { cancelStatus, confirmStatus } = useMemo(() => {\n const terminalStatuses = statusMachine?.terminalStatuses ?? ['completed', 'cancelled', 'no-show']\n const transitions = statusMachine?.transitions ?? {}\n const defaultTransitions: string[] = transitions[defaultStatus] ?? []\n\n const nonTerminal = defaultTransitions.find((s) => !terminalStatuses.includes(s))\n const terminal = defaultTransitions.find((s) => terminalStatuses.includes(s))\n\n return {\n cancelStatus: terminal ?? 'cancelled',\n confirmStatus: nonTerminal ?? 'confirmed',\n }\n }, [statusMachine, defaultStatus])\n\n const STATUS_LABELS = useMemo<Record<string, string>>(() => {\n const statuses = statusMachine?.statuses ?? [\n 'pending',\n 'confirmed',\n 'completed',\n 'cancelled',\n 'no-show',\n ]\n const labels: Record<string, string> = {}\n for (const s of statuses) {\n // Attempt to look up a translation key, e.g. reservation:statusPending\n const key = statusToI18nKey(s)\n const translated = t(key)\n // If translation returns the key itself, it's missing — fall back to capitalized status name\n labels[s] = translated !== key ? translated : s.charAt(0).toUpperCase() + s.slice(1)\n }\n return labels\n }, [statusMachine, t])\n\n const [currentDate, setCurrentDate] = useState(() => new Date())\n const [viewMode, setViewMode] = useState<ViewMode>('month')\n const [reservations, setReservations] = useState<Reservation[]>([])\n const [loading, setLoading] = useState(true)\n // { shown, total } when a fetch hit its cap, else null — drives a non-silent notice (D9)\n const [truncation, setTruncation] = useState<{ shown: number; total: number } | null>(null)\n // Monotonic request counters so a slow earlier fetch can't overwrite a newer one (D5)\n const reservationsSeq = useRef(0)\n const pendingSeq = useRef(0)\n const [drawerDocId, setDrawerDocId] = useState<null | string>(null)\n const [initialData, setInitialData] = useState<Record<string, unknown> | undefined>(undefined)\n\n // Resource filter state\n const [resources, setResources] = useState<ResourceOption[]>([])\n const [selectedResourceId, setSelectedResourceId] = useState<string>('')\n\n // Pending tab state\n const [pendingReservations, setPendingReservations] = useState<Reservation[]>([])\n const [pendingCount, setPendingCount] = useState(0)\n const [selectedIds, setSelectedIds] = useState<Set<string>>(() => new Set())\n const [confirmingIds, setConfirmingIds] = useState<Set<string>>(() => new Set())\n const [actionFeedback, setActionFeedback] = useState<{\n message: string\n type: 'error' | 'success'\n } | null>(null)\n\n const [DocumentDrawer, , { openDrawer }] = useDocumentDrawer({\n id: drawerDocId ?? undefined,\n collectionSlug: reservationSlug,\n })\n\n const pendingDrawerOpen = useRef(false)\n\n useEffect(() => {\n if (pendingDrawerOpen.current) {\n pendingDrawerOpen.current = false\n openDrawer()\n }\n })\n\n // Fetch active resources for filter dropdown\n useEffect(() => {\n const fetchResources = async () => {\n try {\n const params = new URLSearchParams({\n depth: '0',\n limit: '100',\n sort: 'name',\n 'where[active][equals]': 'true',\n ...resourceTenantParams,\n })\n const url = `${config.serverURL ?? ''}${config.routes.api}/${resourceSlug}?${params}`\n const response = await fetch(url)\n const result = await response.json()\n const docs: Array<{ id: string; name?: string }> = result.docs ?? []\n setResources(docs.map((d) => ({ id: d.id, name: d.name ?? '' })))\n } catch {\n setResources([])\n }\n }\n void fetchResources()\n }, [config.routes.api, config.serverURL, resourceSlug, resourceTenantParams])\n\n const { rangeEnd, rangeStart } = useMemo(() => {\n const start = new Date(currentDate)\n const end = new Date(currentDate)\n\n if (viewMode === 'month') {\n start.setDate(1)\n start.setDate(start.getDate() - start.getDay())\n // The grid always renders 42 cells (6 weeks) from `start`; fetch the same\n // span so trailing weeks aren't silently empty (review D1).\n end.setTime(start.getTime())\n end.setDate(start.getDate() + 41)\n } else if (viewMode === 'week') {\n const dayOfWeek = start.getDay()\n start.setDate(start.getDate() - dayOfWeek)\n end.setDate(start.getDate() + 6)\n }\n start.setHours(0, 0, 0, 0)\n end.setHours(23, 59, 59, 999)\n\n return { rangeEnd: end, rangeStart: start }\n }, [currentDate, viewMode])\n\n // Availability data for the selected resource (null when no resource selected — grid unshaded)\n const { data: availability } = useResourceAvailability(\n apiBase,\n selectedResourceId || undefined,\n rangeStart,\n rangeEnd,\n )\n\n const fetchReservations = useCallback(async () => {\n const seq = ++reservationsSeq.current\n setLoading(true)\n try {\n const params = new URLSearchParams({\n depth: '1',\n limit: String(MAX_LIST_LIMIT),\n sort: 'startTime',\n 'where[startTime][greater_than_equal]': rangeStart.toISOString(),\n 'where[startTime][less_than_equal]': rangeEnd.toISOString(),\n ...reservationTenantParams,\n })\n const response = await fetch(`${apiUrl}?${params}`)\n const result = await response.json()\n if (seq !== reservationsSeq.current) {return} // a newer fetch superseded this one\n const docs = result.docs ?? []\n setReservations(docs)\n const total = result.totalDocs ?? docs.length\n setTruncation(total > docs.length ? { shown: docs.length, total } : null)\n } catch {\n if (seq !== reservationsSeq.current) {return}\n setReservations([])\n }\n if (seq === reservationsSeq.current) {setLoading(false)}\n }, [rangeStart, rangeEnd, apiUrl, reservationTenantParams])\n\n useEffect(() => {\n void fetchReservations()\n }, [fetchReservations])\n\n // Fetch pending count (always, for badge) — uses defaultStatus from config\n const fetchPendingCount = useCallback(async () => {\n try {\n // limit:1 + depth:0 returns totalDocs (the full count) without downloading\n // every pending doc — limit:0 in Payload means \"no limit\" (review D9).\n const params = new URLSearchParams({\n depth: '0',\n limit: '1',\n 'where[status][equals]': defaultStatus,\n ...reservationTenantParams,\n })\n const response = await fetch(`${apiUrl}?${params}`)\n const result = await response.json()\n setPendingCount(result.totalDocs ?? 0)\n } catch {\n // silently ignore\n }\n }, [apiUrl, defaultStatus, reservationTenantParams])\n\n useEffect(() => {\n void fetchPendingCount()\n }, [fetchPendingCount])\n\n // Fetch pending reservations when tab is active — uses defaultStatus from config\n const fetchPendingReservations = useCallback(async () => {\n const seq = ++pendingSeq.current\n try {\n const params = new URLSearchParams({\n depth: '1',\n limit: String(MAX_LIST_LIMIT),\n sort: 'startTime',\n 'where[status][equals]': defaultStatus,\n ...reservationTenantParams,\n })\n const response = await fetch(`${apiUrl}?${params}`)\n const result = await response.json()\n if (seq !== pendingSeq.current) {return}\n setPendingReservations(result.docs ?? [])\n } catch {\n if (seq !== pendingSeq.current) {return}\n setPendingReservations([])\n }\n }, [apiUrl, defaultStatus, reservationTenantParams])\n\n useEffect(() => {\n if (viewMode === 'pending') {\n void fetchPendingReservations()\n }\n }, [viewMode, fetchPendingReservations])\n\n // Client-side resource filtering\n const matchesResourceFilter = useCallback(\n (r: Reservation): boolean => {\n if (!selectedResourceId) {return true}\n // Check top-level resource\n const topId = typeof r.resource === 'string' ? r.resource : r.resource?.id\n if (topId === selectedResourceId) {return true}\n // Check items array for multi-resource bookings\n if (r.items && r.items.length > 0) {\n return r.items.some((item) => {\n const itemId =\n typeof item.resource === 'string' ? item.resource : item.resource?.id\n return itemId === selectedResourceId\n })\n }\n return false\n },\n [selectedResourceId],\n )\n\n const filteredReservations = useMemo(\n () => reservations.filter(matchesResourceFilter),\n [reservations, matchesResourceFilter],\n )\n\n const filteredPendingReservations = useMemo(\n () => pendingReservations.filter(matchesResourceFilter),\n [pendingReservations, matchesResourceFilter],\n )\n\n // Clear selection when leaving pending view or changing resource filter\n useEffect(() => {\n if (viewMode !== 'pending') {\n setSelectedIds(new Set())\n setActionFeedback(null)\n }\n }, [viewMode])\n\n useEffect(() => {\n setSelectedIds(new Set())\n }, [selectedResourceId])\n\n // Auto-clear feedback toast\n useEffect(() => {\n if (!actionFeedback) {return}\n const timer = setTimeout(() => setActionFeedback(null), 4000)\n return () => clearTimeout(timer)\n }, [actionFeedback])\n\n const patchReservation = useCallback(\n async (id: string, data: Record<string, unknown>): Promise<boolean> => {\n try {\n const response = await fetch(`${apiUrl}/${id}`, {\n body: JSON.stringify(data),\n headers: { 'Content-Type': 'application/json' },\n method: 'PATCH',\n })\n return response.ok\n } catch {\n return false\n }\n },\n [apiUrl],\n )\n\n // Uses confirmStatus derived from config transitions\n const handleQuickConfirm = useCallback(\n async (id: string) => {\n setConfirmingIds((prev) => new Set(prev).add(id))\n const ok = await patchReservation(id, { status: confirmStatus })\n setConfirmingIds((prev) => {\n const next = new Set(prev)\n next.delete(id)\n return next\n })\n setActionFeedback({\n type: ok ? 'success' : 'error',\n message: ok\n ? t('reservation:pendingConfirmSuccess')\n : t('reservation:pendingConfirmError'),\n })\n if (ok) {\n setSelectedIds((prev) => {\n const next = new Set(prev)\n next.delete(id)\n return next\n })\n void fetchPendingReservations()\n void fetchPendingCount()\n }\n },\n [patchReservation, fetchPendingReservations, fetchPendingCount, t, confirmStatus],\n )\n\n // Uses cancelStatus derived from config transitions\n const handleQuickCancel = useCallback(\n async (id: string) => {\n setConfirmingIds((prev) => new Set(prev).add(id))\n const ok = await patchReservation(id, { status: cancelStatus })\n setConfirmingIds((prev) => {\n const next = new Set(prev)\n next.delete(id)\n return next\n })\n setActionFeedback({\n type: ok ? 'success' : 'error',\n message: ok\n ? t('reservation:pendingCancelSuccess')\n : t('reservation:pendingCancelError'),\n })\n if (ok) {\n setSelectedIds((prev) => {\n const next = new Set(prev)\n next.delete(id)\n return next\n })\n void fetchPendingReservations()\n void fetchPendingCount()\n }\n },\n [patchReservation, fetchPendingReservations, fetchPendingCount, t, cancelStatus],\n )\n\n const confirmSelected = useCallback(async () => {\n const ids = Array.from(selectedIds)\n if (ids.length === 0) {return}\n\n setConfirmingIds((prev) => {\n const next = new Set(prev)\n for (const id of ids) {next.add(id)}\n return next\n })\n\n const results = await Promise.allSettled(\n ids.map((id) => patchReservation(id, { status: confirmStatus })),\n )\n\n setConfirmingIds((prev) => {\n const next = new Set(prev)\n for (const id of ids) {next.delete(id)}\n return next\n })\n\n const succeeded = results.filter(\n (r) => r.status === 'fulfilled' && r.value,\n ).length\n const failed = ids.length - succeeded\n\n if (failed === 0) {\n setActionFeedback({\n type: 'success',\n message: `${succeeded} ${t('reservation:pendingConfirmSuccess').toLowerCase()}`,\n })\n } else {\n setActionFeedback({\n type: failed === ids.length ? 'error' : 'success',\n message: t('reservation:pendingBulkConfirmSuccess')\n .replace('{{succeeded}}', String(succeeded))\n .replace('{{failed}}', String(failed)),\n })\n }\n\n setSelectedIds(new Set())\n void fetchPendingReservations()\n void fetchPendingCount()\n }, [selectedIds, patchReservation, fetchPendingReservations, fetchPendingCount, t, confirmStatus])\n\n const handleEventClick = useCallback((e: React.MouseEvent, id: string) => {\n e.stopPropagation()\n setDrawerDocId(id)\n setInitialData(undefined)\n pendingDrawerOpen.current = true\n }, [])\n\n const handleEventKeyDown = useCallback((e: React.KeyboardEvent, id: string) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n e.stopPropagation()\n setDrawerDocId(id)\n setInitialData(undefined)\n pendingDrawerOpen.current = true\n }\n }, [])\n\n const handleCreateNew = useCallback(() => {\n setDrawerDocId(null)\n setInitialData(undefined)\n pendingDrawerOpen.current = true\n }, [])\n\n const handleDateClick = useCallback((date: Date) => {\n setDrawerDocId(null)\n setInitialData({ startTime: date.toISOString() })\n pendingDrawerOpen.current = true\n }, [])\n\n // Click-to-book: open new-reservation drawer pre-filled with startTime + optional resource\n const handleSlotClick = useCallback(\n (startIso: string) => {\n setDrawerDocId(null)\n setInitialData({\n ...(selectedResourceId ? { resource: selectedResourceId } : {}),\n startTime: startIso,\n })\n pendingDrawerOpen.current = true\n },\n [selectedResourceId],\n )\n\n // Lane-specific book: pre-fills both the specific resource and startTime\n const handleLaneBook = useCallback((resourceId: string, startIso: string) => {\n setDrawerDocId(null)\n setInitialData({ resource: resourceId, startTime: startIso })\n pendingDrawerOpen.current = true\n }, [])\n\n const openDocDrawer = useCallback((id: string) => {\n setDrawerDocId(id)\n setInitialData(undefined)\n pendingDrawerOpen.current = true\n }, [])\n\n const navigate = useCallback(\n (direction: -1 | 1) => {\n setCurrentDate((prev) => {\n const next = new Date(prev)\n if (viewMode === 'month') {\n next.setMonth(next.getMonth() + direction)\n } else if (viewMode === 'week') {\n next.setDate(next.getDate() + 7 * direction)\n } else {\n // day, lanes: step one day at a time\n next.setDate(next.getDate() + direction)\n }\n return next\n })\n },\n [viewMode],\n )\n\n const goToToday = useCallback(() => setCurrentDate(new Date()), [])\n\n const getResName = (field: { name?: string } | string | undefined): string => {\n if (!field) {return ''}\n if (typeof field === 'string') {return ''}\n return field.name ?? ''\n }\n\n const getCustomerName = (field: Reservation['customer']): string => {\n if (!field) {return ''}\n if (typeof field === 'string') {return ''}\n const parts = [field.firstName, field.lastName].filter(Boolean)\n return parts.length > 0 ? parts.join(' ') : (field.name ?? '')\n }\n\n const getEventLabel = (r: Reservation, compact: boolean) => {\n const time = new Date(r.startTime).toLocaleTimeString([], {\n hour: '2-digit',\n minute: '2-digit',\n timeZone: reservationTimezone,\n })\n const serviceName = getResName(r.service)\n if (compact) {\n return `${time} ${serviceName}`.trim()\n }\n const customerName = getCustomerName(r.customer)\n const parts = [time, serviceName, customerName].filter(Boolean)\n return parts.join(' - ')\n }\n\n // Returns all resource names for a reservation — from items array if present, otherwise top-level resource\n const getResourceNames = (r: Reservation): string[] => {\n if (r.items && r.items.length > 0) {\n const names = r.items\n .map((item) => getResName(item.resource))\n .filter((name) => name.length > 0)\n if (names.length > 0) {return names}\n }\n const single = getResName(r.resource)\n return single ? [single] : []\n }\n\n const getEventTooltip = (r: Reservation): string => {\n const serviceName = getResName(r.service) || t('reservation:calendarUnknownService')\n const startStr = new Date(r.startTime).toLocaleTimeString([], {\n hour: '2-digit',\n minute: '2-digit',\n timeZone: reservationTimezone,\n })\n const endStr = r.endTime\n ? new Date(r.endTime).toLocaleTimeString([], {\n hour: '2-digit',\n minute: '2-digit',\n timeZone: reservationTimezone,\n })\n : '?'\n const customerName = getCustomerName(r.customer) || t('reservation:calendarUnknownCustomer')\n const resourceNames = getResourceNames(r)\n const resourceStr =\n resourceNames.length > 0\n ? resourceNames.join(', ')\n : t('reservation:calendarUnknownResource')\n const status = STATUS_LABELS[r.status] ?? r.status\n return [\n serviceName,\n `${startStr} - ${endStr}`,\n `${t('reservation:tooltipCustomer')} ${customerName}`,\n `${t('reservation:tooltipResource')} ${resourceStr}`,\n `${t('reservation:tooltipStatus')} ${status}`,\n ].join('\\n')\n }\n\n const renderEventItem = (r: Reservation, compact: boolean) => {\n // Use CSS class for built-in statuses; also apply inline background for custom statuses\n const cssClass = STATUS_CLASS_MAP[r.status] ?? ''\n const color = STATUS_COLORS[r.status]\n // Only apply inline style when there's no CSS class (custom statuses) or as a supplement\n const inlineStyle = cssClass ? undefined : { background: color }\n const hasItems = Array.isArray(r.items) && r.items.length > 0\n return (\n <div\n className={`${styles.eventItem} ${cssClass} ${hasItems && !compact ? styles.eventItemExpanded : ''}`}\n key={r.id}\n onClick={(e) => handleEventClick(e, r.id)}\n onKeyDown={(e) => handleEventKeyDown(e, r.id)}\n role=\"button\"\n style={inlineStyle}\n tabIndex={0}\n title={getEventTooltip(r)}\n >\n {getEventLabel(r, compact)}\n {hasItems && (\n <div className={styles.itemBadges}>\n {r.items!.map((it, i) => {\n const name = typeof it.resource === 'object' ? it.resource?.name : it.resource\n return (\n <span className={styles.itemBadge} key={i}>\n {String(name ?? '')}\n </span>\n )\n })}\n </div>\n )}\n </div>\n )\n }\n\n // Dynamic legend: iterates all statuses from the status machine config\n const renderStatusLegend = () => {\n const statuses = statusMachine?.statuses ?? Object.keys(BUILTIN_STATUS_COLORS)\n return (\n <div className={styles.statusLegend}>\n {statuses.map((key) => (\n <div className={styles.legendItem} key={key}>\n <span className={styles.legendDot} style={{ background: STATUS_COLORS[key] }} />\n {STATUS_LABELS[key] ?? key}\n </div>\n ))}\n </div>\n )\n }\n\n const renderCurrentTimeLine = (cellDate: Date, cellHour: number) => {\n const now = new Date()\n if (\n now.getFullYear() !== cellDate.getFullYear() ||\n now.getMonth() !== cellDate.getMonth() ||\n now.getDate() !== cellDate.getDate() ||\n now.getHours() !== cellHour\n ) {\n return null\n }\n const topPercent = (now.getMinutes() / 60) * 100\n return <div className={styles.currentTimeLine} style={{ top: `${topPercent}%` }} />\n }\n\n const renderMonthView = () => {\n const firstDay = new Date(currentDate.getFullYear(), currentDate.getMonth(), 1)\n const startDay = new Date(firstDay)\n startDay.setDate(startDay.getDate() - startDay.getDay())\n\n const days: Date[] = []\n const d = new Date(startDay)\n for (let i = 0; i < 42; i++) {\n days.push(new Date(d))\n d.setDate(d.getDate() + 1)\n }\n\n const today = new Date()\n const todayStr = getDayKeyInTimezone(today, reservationTimezone)\n\n return (\n <div className={styles.monthGrid}>\n {[\n t('reservation:dayShortSun'),\n t('reservation:dayShortMon'),\n t('reservation:dayShortTue'),\n t('reservation:dayShortWed'),\n t('reservation:dayShortThu'),\n t('reservation:dayShortFri'),\n t('reservation:dayShortSat'),\n ].map((d) => (\n <div className={styles.dayHeader} key={d}>\n {d}\n </div>\n ))}\n {days.map((day, i) => {\n const dayKey = getDayKeyInTimezone(day, reservationTimezone)\n const isToday = dayKey === todayStr\n const isOtherMonth =\n dayKey.slice(0, 7) !== getDayKeyInTimezone(currentDate, reservationTimezone).slice(0, 7)\n const dayReservations = filteredReservations.filter((r) => {\n const rKey = getDayKeyInTimezone(new Date(r.startTime), reservationTimezone)\n return rKey === dayKey\n })\n\n const clickDate = new Date(day)\n clickDate.setHours(9, 0, 0, 0)\n\n return (\n <div\n className={`${styles.dayCell} ${isOtherMonth ? styles.dayCellOtherMonth : ''} ${isToday ? styles.dayCellToday : ''}`}\n key={i}\n onClick={() => handleDateClick(clickDate)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n handleDateClick(clickDate)\n }\n }}\n role=\"button\"\n tabIndex={0}\n >\n <div className={styles.dayNumber}>{day.getDate()}</div>\n {dayReservations.map((r) => renderEventItem(r, true))}\n </div>\n )\n })}\n </div>\n )\n }\n\n const renderWeekView = () => {\n const startOfWeek = new Date(currentDate)\n startOfWeek.setDate(startOfWeek.getDate() - startOfWeek.getDay())\n startOfWeek.setHours(0, 0, 0, 0)\n\n const weekDays: Date[] = []\n for (let i = 0; i < 7; i++) {\n const d = new Date(startOfWeek)\n d.setDate(d.getDate() + i)\n weekDays.push(d)\n }\n\n // Visible-hour window derived from the week's bookings (review D8)\n const weekReservations = filteredReservations.filter((r) => {\n const k = getDayKeyInTimezone(new Date(r.startTime), reservationTimezone)\n return weekDays.some((d) => getDayKeyInTimezone(d, reservationTimezone) === k)\n })\n const { endHour: gridEndHour, startHour: gridStartHour } = computeHourWindow(\n weekReservations,\n reservationTimezone,\n )\n const hours = Array.from({ length: gridEndHour - gridStartHour }, (_, i) => i + gridStartHour)\n const gridStep = 60\n\n // Build per-day slot-state maps when a resource is selected\n const daySlotMaps = availability\n ? new Map(\n weekDays.map((day) => {\n const isoDay = getDayKeyInTimezone(day, reservationTimezone)\n const dayAvail = availability.days.find((d) => d.date === isoDay)\n const dayStart = new Date(day)\n dayStart.setHours(gridStartHour, 0, 0, 0)\n const dayEnd = new Date(day)\n dayEnd.setHours(gridEndHour, 0, 0, 0)\n const slots = dayAvail\n ? computeSlotStates({\n busy: availability.busy,\n capacityMode: availability.capacityMode,\n dayEnd,\n dayStart,\n quantity: availability.quantity,\n requiredPools: availability.requiredPools,\n shiftWindows: dayAvail.shiftWindows,\n step: gridStep,\n timeOff: dayAvail.timeOff,\n })\n : []\n // Index by slot start ISO for fast lookup\n const slotByStart = new Map(slots.map((s) => [s.start.toISOString(), s]))\n return [isoDay, slotByStart] as const\n }),\n )\n : null\n\n return (\n <div className={styles.weekView}>\n <div className={styles.dayHeader} />\n {weekDays.map((d, i) => (\n <div className={styles.dayHeader} key={i}>\n {d.toLocaleDateString([], {\n day: 'numeric',\n month: 'numeric',\n timeZone: reservationTimezone,\n weekday: 'short',\n })}\n </div>\n ))}\n {hours.map((hour) => (\n <Fragment key={`row-${hour}`}>\n <div className={styles.timeLabel}>\n {hour.toString().padStart(2, '0')}:00\n </div>\n {weekDays.map((day, di) => {\n const isoDay = getDayKeyInTimezone(day, reservationTimezone)\n const cellReservations = filteredReservations.filter((r) => {\n const rDate = new Date(r.startTime)\n return (\n getDayKeyInTimezone(rDate, reservationTimezone) === isoDay &&\n getHourInTimezone(rDate, reservationTimezone) === hour\n )\n })\n const clickDate = new Date(day)\n clickDate.setHours(hour, 0, 0, 0)\n\n // Slot state (only when a resource is selected)\n const slotMap = daySlotMaps?.get(isoDay)\n const slotInfo = slotMap?.get(clickDate.toISOString()) ?? null\n\n // Derive cell CSS class and interactivity based on slot state\n let slotClass = ''\n let isNonInteractive = false\n if (slotInfo) {\n if (slotInfo.state === 'off-shift') {\n slotClass = styles.slotOffShift\n isNonInteractive = true\n } else if (slotInfo.state === 'time-off') {\n slotClass = styles.slotTimeOff\n isNonInteractive = true\n } else if (slotInfo.state === 'full') {\n slotClass = styles.slotFull\n isNonInteractive = true\n } else {\n slotClass = styles.slotFree\n }\n }\n\n // Time-off label: show type/reason from dayAvail when in time-off state\n const dayAvail = availability?.days.find((d) => d.date === isoDay)\n const timeOffEntry =\n slotInfo?.state === 'time-off'\n ? dayAvail?.timeOff.find(\n (to) =>\n new Date(to.start) <= clickDate && clickDate < new Date(to.end),\n )\n : undefined\n const timeOffLabel = timeOffEntry?.type ?? timeOffEntry?.reason ?? null\n\n const handleClick = isNonInteractive\n ? undefined\n : availability\n ? () => handleSlotClick(clickDate.toISOString())\n : () => handleDateClick(clickDate)\n const handleKeyDown = isNonInteractive\n ? undefined\n : (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n if (availability) {\n handleSlotClick(clickDate.toISOString())\n } else {\n handleDateClick(clickDate)\n }\n }\n }\n\n return (\n <div\n className={`${styles.weekCell} ${slotClass}`}\n key={`cell-${hour}-${di}`}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n role=\"button\"\n tabIndex={isNonInteractive ? -1 : 0}\n >\n {renderCurrentTimeLine(day, hour)}\n {timeOffLabel && (\n <span className={styles.timeOffLabel}>{timeOffLabel}</span>\n )}\n {slotInfo && availability && availability.quantity > 1 && (\n <span className={styles.capacityBadge}>\n {slotInfo.occupancy}/{availability.quantity}\n </span>\n )}\n {cellReservations.map((r) => renderEventItem(r, false))}\n </div>\n )\n })}\n </Fragment>\n ))}\n </div>\n )\n }\n\n const renderDayView = () => {\n // Build slot-state map for the current day when a resource is selected\n const currentDayKey = getDayKeyInTimezone(currentDate, reservationTimezone)\n\n // Visible-hour window derived from this day's bookings (review D8)\n const dayReservations = filteredReservations.filter(\n (r) => getDayKeyInTimezone(new Date(r.startTime), reservationTimezone) === currentDayKey,\n )\n const { endHour: gridEndHour, startHour: gridStartHour } = computeHourWindow(\n dayReservations,\n reservationTimezone,\n )\n const hours = Array.from({ length: gridEndHour - gridStartHour }, (_, i) => i + gridStartHour)\n const gridStep = 60\n let daySlotMap: Map<string, SlotInfo> | null = null\n if (availability) {\n const isoDay = currentDayKey\n const dayAvail = availability.days.find((d) => d.date === isoDay)\n const dayStart = new Date(currentDate)\n dayStart.setHours(gridStartHour, 0, 0, 0)\n const dayEnd = new Date(currentDate)\n dayEnd.setHours(gridEndHour, 0, 0, 0)\n const slots = dayAvail\n ? computeSlotStates({\n busy: availability.busy,\n capacityMode: availability.capacityMode,\n dayEnd,\n dayStart,\n quantity: availability.quantity,\n requiredPools: availability.requiredPools,\n shiftWindows: dayAvail.shiftWindows,\n step: gridStep,\n timeOff: dayAvail.timeOff,\n })\n : []\n daySlotMap = new Map(slots.map((s) => [s.start.toISOString(), s]))\n }\n\n return (\n <div className={styles.dayView}>\n {hours.map((hour) => {\n const hourReservations = filteredReservations.filter((r) => {\n const rDate = new Date(r.startTime)\n return (\n getDayKeyInTimezone(rDate, reservationTimezone) === currentDayKey &&\n getHourInTimezone(rDate, reservationTimezone) === hour\n )\n })\n const clickDate = new Date(currentDate)\n clickDate.setHours(hour, 0, 0, 0)\n\n // Slot state (only when a resource is selected)\n const slotInfo = daySlotMap?.get(clickDate.toISOString()) ?? null\n\n // Derive cell CSS class and interactivity based on slot state\n let slotClass = ''\n let isNonInteractive = false\n if (slotInfo) {\n if (slotInfo.state === 'off-shift') {\n slotClass = styles.slotOffShift\n isNonInteractive = true\n } else if (slotInfo.state === 'time-off') {\n slotClass = styles.slotTimeOff\n isNonInteractive = true\n } else if (slotInfo.state === 'full') {\n slotClass = styles.slotFull\n isNonInteractive = true\n } else {\n slotClass = styles.slotFree\n }\n }\n\n // Time-off label\n const dayAvail = availability?.days.find((d) => d.date === currentDayKey)\n const timeOffEntry =\n slotInfo?.state === 'time-off'\n ? dayAvail?.timeOff.find(\n (to) => new Date(to.start) <= clickDate && clickDate < new Date(to.end),\n )\n : undefined\n const timeOffLabel = timeOffEntry?.type ?? timeOffEntry?.reason ?? null\n\n const handleClick = isNonInteractive\n ? undefined\n : availability\n ? () => handleSlotClick(clickDate.toISOString())\n : () => handleDateClick(clickDate)\n const handleKeyDown = isNonInteractive\n ? undefined\n : (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n if (availability) {\n handleSlotClick(clickDate.toISOString())\n } else {\n handleDateClick(clickDate)\n }\n }\n }\n\n return (\n <Fragment key={`row-${hour}`}>\n <div className={styles.timeLabel}>\n {hour.toString().padStart(2, '0')}:00\n </div>\n <div\n className={`${styles.dayViewCell} ${slotClass}`}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n role=\"button\"\n tabIndex={isNonInteractive ? -1 : 0}\n >\n {renderCurrentTimeLine(currentDate, hour)}\n {timeOffLabel && (\n <span className={styles.timeOffLabel}>{timeOffLabel}</span>\n )}\n {slotInfo && availability && availability.quantity > 1 && (\n <span className={styles.capacityBadge}>\n {slotInfo.occupancy}/{availability.quantity}\n </span>\n )}\n {hourReservations.map((r) => renderEventItem(r, false))}\n </div>\n </Fragment>\n )\n })}\n </div>\n )\n }\n\n const renderPendingView = () => {\n if (filteredPendingReservations.length === 0) {\n return <div className={styles.pendingEmpty}>{t('reservation:pendingEmpty')}</div>\n }\n\n const allSelected =\n filteredPendingReservations.length > 0 &&\n filteredPendingReservations.every((r) => selectedIds.has(r.id))\n\n const toggleSelectAll = () => {\n if (allSelected) {\n setSelectedIds(new Set())\n } else {\n setSelectedIds(new Set(filteredPendingReservations.map((r) => r.id)))\n }\n }\n\n const toggleSelect = (id: string) => {\n setSelectedIds((prev) => {\n const next = new Set(prev)\n if (next.has(id)) {\n next.delete(id)\n } else {\n next.add(id)\n }\n return next\n })\n }\n\n const formatDateTime = (iso: string) => {\n const d = new Date(iso)\n return d.toLocaleString([], {\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n month: 'short',\n timeZone: reservationTimezone,\n year: 'numeric',\n })\n }\n\n return (\n <div className={styles.pendingView}>\n <div className={styles.pendingToolbar}>\n <label className={styles.selectAllLabel}>\n <input\n aria-label={t('reservation:pendingSelectAll')}\n checked={allSelected}\n onChange={toggleSelectAll}\n type=\"checkbox\"\n />\n {t('reservation:pendingSelectAll')}\n </label>\n {selectedIds.size > 0 && (\n <button\n className={styles.bulkConfirmButton}\n disabled={confirmingIds.size > 0}\n onClick={() => void confirmSelected()}\n type=\"button\"\n >\n {confirmingIds.size > 0\n ? t('reservation:pendingConfirming')\n : t('reservation:pendingConfirmSelected').replace(\n '{{count}}',\n String(selectedIds.size),\n )}\n </button>\n )}\n </div>\n {actionFeedback && (\n <div\n className={`${styles.feedbackToast} ${actionFeedback.type === 'success' ? styles.feedbackSuccess : styles.feedbackError}`}\n >\n {actionFeedback.message}\n </div>\n )}\n <table className={styles.pendingTable}>\n <thead>\n <tr>\n <th aria-label={t('reservation:pendingSelectAll')} className={styles.pendingTh} />\n <th className={styles.pendingTh}>{t('reservation:fieldCustomer')}</th>\n <th className={styles.pendingTh}>{t('reservation:fieldService')}</th>\n <th className={styles.pendingTh}>{t('reservation:fieldResource')}</th>\n <th className={styles.pendingTh}>{t('reservation:pendingDateTime')}</th>\n <th className={styles.pendingTh}>{t('reservation:pendingActions')}</th>\n </tr>\n </thead>\n <tbody>\n {filteredPendingReservations.map((r) => {\n const isConfirming = confirmingIds.has(r.id)\n // Show all resources from items array if present, else top-level resource\n const resourceDisplay =\n getResourceNames(r).join(', ') || t('reservation:calendarUnknownResource')\n return (\n <tr className={styles.pendingRow} key={r.id}>\n <td className={styles.pendingTd}>\n <input\n aria-label={getCustomerName(r.customer) || r.id}\n checked={selectedIds.has(r.id)}\n onChange={() => toggleSelect(r.id)}\n type=\"checkbox\"\n />\n </td>\n <td className={styles.pendingTd}>\n <span\n className={styles.pendingCustomerLink}\n onClick={() => openDocDrawer(r.id)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n openDocDrawer(r.id)\n }\n }}\n role=\"button\"\n tabIndex={0}\n >\n {getCustomerName(r.customer) || t('reservation:calendarUnknownCustomer')}\n </span>\n </td>\n <td className={styles.pendingTd}>\n {getResName(r.service) || t('reservation:calendarUnknownService')}\n </td>\n <td className={styles.pendingTd}>{resourceDisplay}</td>\n <td className={styles.pendingTd}>{formatDateTime(r.startTime)}</td>\n <td className={styles.pendingTd}>\n <button\n className={styles.confirmButton}\n disabled={isConfirming}\n onClick={() => void handleQuickConfirm(r.id)}\n title={t('reservation:pendingConfirm')}\n type=\"button\"\n >\n &#x2713;\n </button>\n <button\n className={styles.cancelButton}\n disabled={isConfirming}\n onClick={() => void handleQuickCancel(r.id)}\n title={t('reservation:pendingCancel')}\n type=\"button\"\n >\n &#x2717;\n </button>\n </td>\n </tr>\n )\n })}\n </tbody>\n </table>\n </div>\n )\n }\n\n const dateLabel = useMemo(() => {\n if (viewMode === 'month') {\n return currentDate.toLocaleDateString([], { month: 'long', year: 'numeric' })\n }\n if (viewMode === 'week') {\n const startOfWeek = new Date(currentDate)\n startOfWeek.setDate(startOfWeek.getDate() - startOfWeek.getDay())\n const endOfWeek = new Date(startOfWeek)\n endOfWeek.setDate(endOfWeek.getDate() + 6)\n return `${startOfWeek.toLocaleDateString([], { day: 'numeric', month: 'short', timeZone: reservationTimezone })} - ${endOfWeek.toLocaleDateString([], { day: 'numeric', month: 'short', timeZone: reservationTimezone, year: 'numeric' })}`\n }\n return currentDate.toLocaleDateString([], {\n day: 'numeric',\n month: 'long',\n timeZone: reservationTimezone,\n weekday: 'long',\n year: 'numeric',\n })\n }, [currentDate, reservationTimezone, viewMode])\n\n const handleDrawerSave = useCallback(() => {\n void fetchReservations()\n void fetchPendingCount()\n if (viewMode === 'pending') {\n void fetchPendingReservations()\n }\n }, [fetchReservations, fetchPendingCount, fetchPendingReservations, viewMode])\n\n return (\n <div className={styles.wrapper}>\n <div className={styles.header}>\n {viewMode !== 'pending' && (\n <div className={styles.navButtons}>\n <button className={styles.navButton} onClick={() => navigate(-1)} type=\"button\">\n &larr;\n </button>\n <button className={styles.navButton} onClick={goToToday} type=\"button\">\n {t('reservation:calendarToday')}\n </button>\n <button className={styles.navButton} onClick={() => navigate(1)} type=\"button\">\n &rarr;\n </button>\n <span className={styles.currentDate}>{dateLabel}</span>\n </div>\n )}\n {viewMode === 'pending' && <div />}\n <div className={styles.viewToggle}>\n <button className={styles.createButton} onClick={handleCreateNew} type=\"button\">\n {t('reservation:calendarCreateNew')}\n </button>\n {([\n { key: 'month' as ViewMode, label: t('reservation:calendarMonth') },\n { key: 'week' as ViewMode, label: t('reservation:calendarWeek') },\n { key: 'day' as ViewMode, label: t('reservation:calendarDay') },\n { key: 'lanes' as ViewMode, label: t('reservation:calendarLanes') },\n { key: 'pending' as ViewMode, label: t('reservation:calendarPending') },\n ]).map(({ key, label }) => (\n <button\n className={`${styles.viewToggleButton} ${viewMode === key ? styles.viewToggleButtonActive : ''}`}\n key={key}\n onClick={() => setViewMode(key)}\n type=\"button\"\n >\n {label}\n {key === 'pending' && pendingCount > 0 && (\n <span className={styles.pendingBadge}>\n {selectedResourceId ? filteredPendingReservations.length : pendingCount}\n </span>\n )}\n </button>\n ))}\n </div>\n </div>\n {viewMode !== 'pending' && renderStatusLegend()}\n {viewMode !== 'pending' && truncation && (\n <div className={styles.truncationNotice} role=\"status\">\n {t('reservation:calendarShowingNofM', {\n shown: String(truncation.shown),\n total: String(truncation.total),\n })}\n </div>\n )}\n {resources.length > 1 && (\n <div className={styles.filterBar}>\n <select\n aria-label={t('reservation:filterByResource')}\n className={styles.resourceFilter}\n onChange={(e) => setSelectedResourceId(e.target.value)}\n value={selectedResourceId}\n >\n <option value=\"\">{t('reservation:filterAllResources')}</option>\n {resources.map((r) => (\n <option key={r.id} value={r.id}>\n {r.name}\n </option>\n ))}\n </select>\n </div>\n )}\n {loading && viewMode !== 'pending' && viewMode !== 'lanes' ? (\n <div className={styles.loading}>{t('reservation:calendarLoading')}</div>\n ) : (\n <>\n {viewMode === 'month' && renderMonthView()}\n {viewMode === 'week' && renderWeekView()}\n {viewMode === 'day' && renderDayView()}\n {viewMode === 'lanes' &&\n (() => {\n const laneDayKey = getDayKeyInTimezone(currentDate, reservationTimezone)\n const { endHour, startHour } = computeHourWindow(\n filteredReservations.filter(\n (r) =>\n getDayKeyInTimezone(new Date(r.startTime), reservationTimezone) === laneDayKey,\n ),\n reservationTimezone,\n )\n return (\n <LaneTimelineView\n apiBase={apiBase}\n day={currentDate}\n endHour={endHour}\n onBook={handleLaneBook}\n resources={\n selectedResourceId\n ? resources.filter((r) => r.id === selectedResourceId)\n : resources\n }\n startHour={startHour}\n timeZone={reservationTimezone}\n />\n )\n })()}\n </>\n )}\n {viewMode === 'pending' && renderPendingView()}\n <DocumentDrawer initialData={initialData} onSave={handleDrawerSave} />\n </div>\n )\n}\n"],"names":["useConfig","useDocumentDrawer","useTranslation","React","Fragment","useCallback","useEffect","useMemo","useRef","useState","computeSlotStates","statusToI18nKey","getDayKeyInTimezone","getHourInTimezone","useTenantFilter","styles","LaneTimelineView","useResourceAvailability","STATUS_CLASS_MAP","cancelled","statusCancelled","completed","statusCompleted","confirmed","statusConfirmed","statusNoShow","pending","statusPending","BUILTIN_STATUS_COLORS","CUSTOM_STATUS_PALETTE","MAX_LIST_LIMIT","DEFAULT_HOUR_START","DEFAULT_HOUR_END","computeHourWindow","reservations","timeZone","startHour","endHour","r","startTime","sh","Date","Math","min","max","endTime","CalendarView","config","t","_t","slugs","admin","custom","reservationSlugs","reservationSlug","apiUrl","serverURL","routes","api","apiBase","resourceSlug","resources","reservationTenantParams","resourceTenantParams","staticReservationTimezone","reservationTimezone","effectiveTimezone","setEffectiveTimezone","tenantKey","JSON","stringify","res","fetch","credentials","ok","json","statusMachine","reservationStatusMachine","defaultStatus","STATUS_COLORS","colors","statuses","forEach","s","i","length","cancelStatus","confirmStatus","terminalStatuses","transitions","defaultTransitions","nonTerminal","find","includes","terminal","STATUS_LABELS","labels","key","translated","charAt","toUpperCase","slice","currentDate","setCurrentDate","viewMode","setViewMode","setReservations","loading","setLoading","truncation","setTruncation","reservationsSeq","pendingSeq","drawerDocId","setDrawerDocId","initialData","setInitialData","undefined","setResources","selectedResourceId","setSelectedResourceId","pendingReservations","setPendingReservations","pendingCount","setPendingCount","selectedIds","setSelectedIds","Set","confirmingIds","setConfirmingIds","actionFeedback","setActionFeedback","DocumentDrawer","openDrawer","id","collectionSlug","pendingDrawerOpen","current","fetchResources","params","URLSearchParams","depth","limit","sort","url","response","result","docs","map","d","name","rangeEnd","rangeStart","start","end","setDate","getDate","getDay","setTime","getTime","dayOfWeek","setHours","data","availability","fetchReservations","seq","String","toISOString","total","totalDocs","shown","fetchPendingCount","fetchPendingReservations","matchesResourceFilter","topId","resource","items","some","item","itemId","filteredReservations","filter","filteredPendingReservations","timer","setTimeout","clearTimeout","patchReservation","body","headers","method","handleQuickConfirm","prev","add","status","next","delete","type","message","handleQuickCancel","confirmSelected","ids","Array","from","results","Promise","allSettled","succeeded","value","failed","toLowerCase","replace","handleEventClick","e","stopPropagation","handleEventKeyDown","preventDefault","handleCreateNew","handleDateClick","date","handleSlotClick","startIso","handleLaneBook","resourceId","openDocDrawer","navigate","direction","setMonth","getMonth","goToToday","getResName","field","getCustomerName","parts","firstName","lastName","Boolean","join","getEventLabel","compact","time","toLocaleTimeString","hour","minute","serviceName","service","trim","customerName","customer","getResourceNames","names","single","getEventTooltip","startStr","endStr","resourceNames","resourceStr","renderEventItem","cssClass","color","inlineStyle","background","hasItems","isArray","div","className","eventItem","eventItemExpanded","onClick","onKeyDown","role","style","tabIndex","title","itemBadges","it","span","itemBadge","renderStatusLegend","Object","keys","statusLegend","legendItem","legendDot","renderCurrentTimeLine","cellDate","cellHour","now","getFullYear","getHours","topPercent","getMinutes","currentTimeLine","top","renderMonthView","firstDay","startDay","days","push","today","todayStr","monthGrid","dayHeader","day","dayKey","isToday","isOtherMonth","dayReservations","rKey","clickDate","dayCell","dayCellOtherMonth","dayCellToday","dayNumber","renderWeekView","startOfWeek","weekDays","weekReservations","k","gridEndHour","gridStartHour","hours","_","gridStep","daySlotMaps","Map","isoDay","dayAvail","dayStart","dayEnd","slots","busy","capacityMode","quantity","requiredPools","shiftWindows","step","timeOff","slotByStart","weekView","toLocaleDateString","month","weekday","timeLabel","toString","padStart","di","cellReservations","rDate","slotMap","get","slotInfo","slotClass","isNonInteractive","state","slotOffShift","slotTimeOff","slotFull","slotFree","timeOffEntry","to","timeOffLabel","reason","handleClick","handleKeyDown","weekCell","capacityBadge","occupancy","renderDayView","currentDayKey","daySlotMap","dayView","hourReservations","dayViewCell","renderPendingView","pendingEmpty","allSelected","every","has","toggleSelectAll","toggleSelect","formatDateTime","iso","toLocaleString","year","pendingView","pendingToolbar","label","selectAllLabel","input","aria-label","checked","onChange","size","button","bulkConfirmButton","disabled","feedbackToast","feedbackSuccess","feedbackError","table","pendingTable","thead","tr","th","pendingTh","tbody","isConfirming","resourceDisplay","pendingRow","td","pendingTd","pendingCustomerLink","confirmButton","cancelButton","dateLabel","endOfWeek","handleDrawerSave","wrapper","header","navButtons","navButton","viewToggle","createButton","viewToggleButton","viewToggleButtonActive","pendingBadge","truncationNotice","filterBar","select","resourceFilter","target","option","laneDayKey","onBook","onSave"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/components/CalendarView/index.tsx"],"sourcesContent":["'use client'\nimport type { AdminViewServerProps } from 'payload'\n\nimport { useConfig, useDocumentDrawer, useTranslation } from '@payloadcms/ui'\nimport React, { Fragment, useCallback, useEffect, useMemo, useRef, useState } from 'react'\n\nimport type { PluginT } from '../../translations/index.js'\nimport type { SlotInfo } from '../../utilities/computeSlotStates.js'\n\nimport { computeSlotStates } from '../../utilities/computeSlotStates.js'\nimport { statusToI18nKey } from '../../utilities/i18nUtils.js'\nimport { getDayKeyInTimezone, getHourInTimezone } from '../../utilities/timezoneUtils.js'\nimport { useTenantFilter } from '../../utilities/useTenantFilter.js'\nimport styles from './CalendarView.module.css'\nimport { LaneTimelineView } from './LaneTimelineView.js'\nimport { useResourceAvailability } from './useResourceAvailability.js'\n\ntype ViewMode = 'day' | 'lanes' | 'month' | 'pending' | 'week'\n\ntype ReservationItem = {\n endTime?: string\n guestCount?: number\n resource?: { id?: string; name?: string } | string\n service?: { name?: string } | string\n startTime?: string\n}\n\ntype Reservation = {\n customer?: { firstName?: string; lastName?: string; name?: string } | string\n endTime?: string\n id: string\n items?: ReservationItem[]\n resource?: { id?: string; name?: string } | string\n service?: { name?: string } | string\n startTime: string\n status: string\n}\n\ntype ResourceOption = {\n id: string\n name: string\n}\n\n// Built-in status → CSS class map (for known statuses; custom statuses use inline style)\nconst STATUS_CLASS_MAP: Record<string, string> = {\n cancelled: styles.statusCancelled,\n completed: styles.statusCompleted,\n confirmed: styles.statusConfirmed,\n 'no-show': styles.statusNoShow,\n pending: styles.statusPending,\n}\n\n// Built-in default colors for known statuses\nconst BUILTIN_STATUS_COLORS: Record<string, string> = {\n cancelled: '#e5e7eb',\n completed: '#d1fae5',\n confirmed: '#dbeafe',\n 'no-show': '#fee2e2',\n pending: '#fef3c7',\n}\n\n// Palette for auto-assigning colors to custom statuses\nconst CUSTOM_STATUS_PALETTE = ['#fde68a', '#c7d2fe', '#a7f3d0', '#fca5a5', '#fdba74']\n\n// Safe ceiling for list fetches; when totalDocs exceeds this we surface a\n// \"showing N of M\" notice rather than silently truncating (review D9).\nconst MAX_LIST_LIMIT = 2000\n\n// Default visible-hour window for the week/day/lane grids; the actual window\n// expands to include any booking outside it so nothing is hidden (review D8).\nconst DEFAULT_HOUR_START = 7\nconst DEFAULT_HOUR_END = 20\n\n/**\n * Visible-hour window covering `reservations` (in `timeZone`), never narrower\n * than the default business window. Every booking's start hour gets a row, so a\n * booking outside 7–20 is shown rather than silently dropped, and all three\n * time views share one window.\n */\nfunction computeHourWindow(\n reservations: Reservation[],\n timeZone: string,\n): { endHour: number; startHour: number } {\n let startHour = DEFAULT_HOUR_START\n let endHour = DEFAULT_HOUR_END\n for (const r of reservations) {\n if (!r.startTime) {continue}\n const sh = getHourInTimezone(new Date(r.startTime), timeZone)\n startHour = Math.min(startHour, sh)\n endHour = Math.max(endHour, sh + 1)\n if (r.endTime) {\n // round the ending hour up so a slot that ends mid-hour still has a row\n endHour = Math.max(endHour, getHourInTimezone(new Date(r.endTime), timeZone) + 1)\n }\n }\n return { endHour: Math.min(endHour, 24), startHour: Math.max(startHour, 0) }\n}\n\nexport const CalendarView: React.FC<AdminViewServerProps> = () => {\n const { config } = useConfig()\n const { t: _t } = useTranslation()\n const t = _t as PluginT\n\n const slugs = config.admin?.custom?.reservationSlugs\n const reservationSlug = slugs?.reservations ?? 'reservations'\n const apiUrl = `${config.serverURL ?? ''}${config.routes.api}/${reservationSlug}`\n const apiBase = `${config.serverURL ?? ''}${config.routes.api}`\n const resourceSlug = slugs?.resources ?? 'resources'\n const reservationTenantParams = useTenantFilter(reservationSlug)\n const resourceTenantParams = useTenantFilter(resourceSlug)\n\n // Day-boundary rendering uses the business timezone. In multiTenant mode that's\n // the SELECTED tenant's zone, resolved server-side from the tenant cookie (the\n // client can't map tenant→zone itself). Until that resolves — and for plain\n // installs — fall back to the static global zone baked into admin config.\n const staticReservationTimezone =\n ((config.admin?.custom as Record<string, unknown> | undefined)?.reservationTimezone as\n | string\n | undefined) ?? 'UTC'\n const [effectiveTimezone, setEffectiveTimezone] = useState<null | string>(null)\n const reservationTimezone = effectiveTimezone ?? staticReservationTimezone\n\n const tenantKey = JSON.stringify(reservationTenantParams)\n useEffect(() => {\n let cancelled = false\n void (async () => {\n try {\n const res = await fetch(`${apiBase}/reserve/effective-timezone`, {\n credentials: 'same-origin',\n })\n if (!res.ok) {\n return\n }\n const json = await res.json()\n if (!cancelled && typeof json?.timeZone === 'string') {\n setEffectiveTimezone(json.timeZone)\n }\n } catch {\n // keep the static fallback\n }\n })()\n return () => {\n cancelled = true\n }\n \n }, [apiBase, tenantKey])\n\n const statusMachine = config.admin?.custom?.reservationStatusMachine as\n | {\n blockingStatuses?: string[]\n defaultStatus?: string\n statuses?: string[]\n terminalStatuses?: string[]\n transitions?: Record<string, string[]>\n }\n | undefined\n\n // The initial/pending status (what \"pending\" view shows)\n const defaultStatus = statusMachine?.defaultStatus ?? 'pending'\n\n // Build STATUS_COLORS dynamically: built-ins first, then auto-assign palette for custom statuses\n const STATUS_COLORS = useMemo<Record<string, string>>(() => {\n const colors = { ...BUILTIN_STATUS_COLORS }\n const statuses = statusMachine?.statuses ?? []\n statuses.forEach((s, i) => {\n if (!colors[s]) {\n colors[s] = CUSTOM_STATUS_PALETTE[i % CUSTOM_STATUS_PALETTE.length]\n }\n })\n return colors\n }, [statusMachine])\n\n // Derive confirm/cancel target statuses from config transitions\n // \"confirm\" = first non-terminal transition from defaultStatus\n // \"cancel\" = first terminal transition from defaultStatus (or fallback: 'cancelled')\n const { cancelStatus, confirmStatus } = useMemo(() => {\n const terminalStatuses = statusMachine?.terminalStatuses ?? ['completed', 'cancelled', 'no-show']\n const transitions = statusMachine?.transitions ?? {}\n const defaultTransitions: string[] = transitions[defaultStatus] ?? []\n\n const nonTerminal = defaultTransitions.find((s) => !terminalStatuses.includes(s))\n const terminal = defaultTransitions.find((s) => terminalStatuses.includes(s))\n\n return {\n cancelStatus: terminal ?? 'cancelled',\n confirmStatus: nonTerminal ?? 'confirmed',\n }\n }, [statusMachine, defaultStatus])\n\n const STATUS_LABELS = useMemo<Record<string, string>>(() => {\n const statuses = statusMachine?.statuses ?? [\n 'pending',\n 'confirmed',\n 'completed',\n 'cancelled',\n 'no-show',\n ]\n const labels: Record<string, string> = {}\n for (const s of statuses) {\n // Attempt to look up a translation key, e.g. reservation:statusPending\n const key = statusToI18nKey(s)\n const translated = t(key)\n // If translation returns the key itself, it's missing — fall back to capitalized status name\n labels[s] = translated !== key ? translated : s.charAt(0).toUpperCase() + s.slice(1)\n }\n return labels\n }, [statusMachine, t])\n\n const [currentDate, setCurrentDate] = useState(() => new Date())\n const [viewMode, setViewMode] = useState<ViewMode>('month')\n const [reservations, setReservations] = useState<Reservation[]>([])\n const [loading, setLoading] = useState(true)\n // { shown, total } when a fetch hit its cap, else null — drives a non-silent notice (D9)\n const [truncation, setTruncation] = useState<{ shown: number; total: number } | null>(null)\n // Monotonic request counters so a slow earlier fetch can't overwrite a newer one (D5)\n const reservationsSeq = useRef(0)\n const pendingSeq = useRef(0)\n const [drawerDocId, setDrawerDocId] = useState<null | string>(null)\n const [initialData, setInitialData] = useState<Record<string, unknown> | undefined>(undefined)\n\n // Resource filter state\n const [resources, setResources] = useState<ResourceOption[]>([])\n const [selectedResourceId, setSelectedResourceId] = useState<string>('')\n\n // Pending tab state\n const [pendingReservations, setPendingReservations] = useState<Reservation[]>([])\n const [pendingCount, setPendingCount] = useState(0)\n const [selectedIds, setSelectedIds] = useState<Set<string>>(() => new Set())\n const [confirmingIds, setConfirmingIds] = useState<Set<string>>(() => new Set())\n const [actionFeedback, setActionFeedback] = useState<{\n message: string\n type: 'error' | 'success'\n } | null>(null)\n\n const [DocumentDrawer, , { openDrawer }] = useDocumentDrawer({\n id: drawerDocId ?? undefined,\n collectionSlug: reservationSlug,\n })\n\n const pendingDrawerOpen = useRef(false)\n\n useEffect(() => {\n if (pendingDrawerOpen.current) {\n pendingDrawerOpen.current = false\n openDrawer()\n }\n })\n\n // Fetch active resources for filter dropdown\n useEffect(() => {\n const fetchResources = async () => {\n try {\n const params = new URLSearchParams({\n depth: '0',\n limit: '100',\n sort: 'name',\n 'where[active][equals]': 'true',\n ...resourceTenantParams,\n })\n const url = `${config.serverURL ?? ''}${config.routes.api}/${resourceSlug}?${params}`\n const response = await fetch(url)\n const result = await response.json()\n const docs: Array<{ id: string; name?: string }> = result.docs ?? []\n setResources(docs.map((d) => ({ id: d.id, name: d.name ?? '' })))\n } catch {\n setResources([])\n }\n }\n void fetchResources()\n }, [config.routes.api, config.serverURL, resourceSlug, resourceTenantParams])\n\n const { rangeEnd, rangeStart } = useMemo(() => {\n const start = new Date(currentDate)\n const end = new Date(currentDate)\n\n if (viewMode === 'month') {\n start.setDate(1)\n start.setDate(start.getDate() - start.getDay())\n // The grid always renders 42 cells (6 weeks) from `start`; fetch the same\n // span so trailing weeks aren't silently empty (review D1).\n end.setTime(start.getTime())\n end.setDate(start.getDate() + 41)\n } else if (viewMode === 'week') {\n const dayOfWeek = start.getDay()\n start.setDate(start.getDate() - dayOfWeek)\n end.setDate(start.getDate() + 6)\n }\n start.setHours(0, 0, 0, 0)\n end.setHours(23, 59, 59, 999)\n\n return { rangeEnd: end, rangeStart: start }\n }, [currentDate, viewMode])\n\n // Availability data for the selected resource (null when no resource selected — grid unshaded)\n const { data: availability } = useResourceAvailability(\n apiBase,\n selectedResourceId || undefined,\n rangeStart,\n rangeEnd,\n )\n\n const fetchReservations = useCallback(async () => {\n const seq = ++reservationsSeq.current\n setLoading(true)\n try {\n const params = new URLSearchParams({\n depth: '1',\n limit: String(MAX_LIST_LIMIT),\n sort: 'startTime',\n 'where[startTime][greater_than_equal]': rangeStart.toISOString(),\n 'where[startTime][less_than_equal]': rangeEnd.toISOString(),\n ...reservationTenantParams,\n })\n const response = await fetch(`${apiUrl}?${params}`)\n const result = await response.json()\n if (seq !== reservationsSeq.current) {return} // a newer fetch superseded this one\n const docs = result.docs ?? []\n setReservations(docs)\n const total = result.totalDocs ?? docs.length\n setTruncation(total > docs.length ? { shown: docs.length, total } : null)\n } catch {\n if (seq !== reservationsSeq.current) {return}\n setReservations([])\n }\n if (seq === reservationsSeq.current) {setLoading(false)}\n }, [rangeStart, rangeEnd, apiUrl, reservationTenantParams])\n\n useEffect(() => {\n void fetchReservations()\n }, [fetchReservations])\n\n // Fetch pending count (always, for badge) — uses defaultStatus from config\n const fetchPendingCount = useCallback(async () => {\n try {\n // limit:1 + depth:0 returns totalDocs (the full count) without downloading\n // every pending doc — limit:0 in Payload means \"no limit\" (review D9).\n const params = new URLSearchParams({\n depth: '0',\n limit: '1',\n 'where[status][equals]': defaultStatus,\n ...reservationTenantParams,\n })\n const response = await fetch(`${apiUrl}?${params}`)\n const result = await response.json()\n setPendingCount(result.totalDocs ?? 0)\n } catch {\n // silently ignore\n }\n }, [apiUrl, defaultStatus, reservationTenantParams])\n\n useEffect(() => {\n void fetchPendingCount()\n }, [fetchPendingCount])\n\n // Fetch pending reservations when tab is active — uses defaultStatus from config\n const fetchPendingReservations = useCallback(async () => {\n const seq = ++pendingSeq.current\n try {\n const params = new URLSearchParams({\n depth: '1',\n limit: String(MAX_LIST_LIMIT),\n sort: 'startTime',\n 'where[status][equals]': defaultStatus,\n ...reservationTenantParams,\n })\n const response = await fetch(`${apiUrl}?${params}`)\n const result = await response.json()\n if (seq !== pendingSeq.current) {return}\n setPendingReservations(result.docs ?? [])\n } catch {\n if (seq !== pendingSeq.current) {return}\n setPendingReservations([])\n }\n }, [apiUrl, defaultStatus, reservationTenantParams])\n\n useEffect(() => {\n if (viewMode === 'pending') {\n void fetchPendingReservations()\n }\n }, [viewMode, fetchPendingReservations])\n\n // Client-side resource filtering\n const matchesResourceFilter = useCallback(\n (r: Reservation): boolean => {\n if (!selectedResourceId) {return true}\n // Check top-level resource\n const topId = typeof r.resource === 'string' ? r.resource : r.resource?.id\n if (topId === selectedResourceId) {return true}\n // Check items array for multi-resource bookings\n if (r.items && r.items.length > 0) {\n return r.items.some((item) => {\n const itemId =\n typeof item.resource === 'string' ? item.resource : item.resource?.id\n return itemId === selectedResourceId\n })\n }\n return false\n },\n [selectedResourceId],\n )\n\n const filteredReservations = useMemo(\n () => reservations.filter(matchesResourceFilter),\n [reservations, matchesResourceFilter],\n )\n\n const filteredPendingReservations = useMemo(\n () => pendingReservations.filter(matchesResourceFilter),\n [pendingReservations, matchesResourceFilter],\n )\n\n // Clear selection when leaving pending view or changing resource filter\n useEffect(() => {\n if (viewMode !== 'pending') {\n setSelectedIds(new Set())\n setActionFeedback(null)\n }\n }, [viewMode])\n\n useEffect(() => {\n setSelectedIds(new Set())\n }, [selectedResourceId])\n\n // Auto-clear feedback toast\n useEffect(() => {\n if (!actionFeedback) {return}\n const timer = setTimeout(() => setActionFeedback(null), 4000)\n return () => clearTimeout(timer)\n }, [actionFeedback])\n\n const patchReservation = useCallback(\n async (id: string, data: Record<string, unknown>): Promise<boolean> => {\n try {\n const response = await fetch(`${apiUrl}/${id}`, {\n body: JSON.stringify(data),\n headers: { 'Content-Type': 'application/json' },\n method: 'PATCH',\n })\n return response.ok\n } catch {\n return false\n }\n },\n [apiUrl],\n )\n\n // Uses confirmStatus derived from config transitions\n const handleQuickConfirm = useCallback(\n async (id: string) => {\n setConfirmingIds((prev) => new Set(prev).add(id))\n const ok = await patchReservation(id, { status: confirmStatus })\n setConfirmingIds((prev) => {\n const next = new Set(prev)\n next.delete(id)\n return next\n })\n setActionFeedback({\n type: ok ? 'success' : 'error',\n message: ok\n ? t('reservation:pendingConfirmSuccess')\n : t('reservation:pendingConfirmError'),\n })\n if (ok) {\n setSelectedIds((prev) => {\n const next = new Set(prev)\n next.delete(id)\n return next\n })\n void fetchPendingReservations()\n void fetchPendingCount()\n }\n },\n [patchReservation, fetchPendingReservations, fetchPendingCount, t, confirmStatus],\n )\n\n // Uses cancelStatus derived from config transitions\n const handleQuickCancel = useCallback(\n async (id: string) => {\n setConfirmingIds((prev) => new Set(prev).add(id))\n const ok = await patchReservation(id, { status: cancelStatus })\n setConfirmingIds((prev) => {\n const next = new Set(prev)\n next.delete(id)\n return next\n })\n setActionFeedback({\n type: ok ? 'success' : 'error',\n message: ok\n ? t('reservation:pendingCancelSuccess')\n : t('reservation:pendingCancelError'),\n })\n if (ok) {\n setSelectedIds((prev) => {\n const next = new Set(prev)\n next.delete(id)\n return next\n })\n void fetchPendingReservations()\n void fetchPendingCount()\n }\n },\n [patchReservation, fetchPendingReservations, fetchPendingCount, t, cancelStatus],\n )\n\n const confirmSelected = useCallback(async () => {\n const ids = Array.from(selectedIds)\n if (ids.length === 0) {return}\n\n setConfirmingIds((prev) => {\n const next = new Set(prev)\n for (const id of ids) {next.add(id)}\n return next\n })\n\n const results = await Promise.allSettled(\n ids.map((id) => patchReservation(id, { status: confirmStatus })),\n )\n\n setConfirmingIds((prev) => {\n const next = new Set(prev)\n for (const id of ids) {next.delete(id)}\n return next\n })\n\n const succeeded = results.filter(\n (r) => r.status === 'fulfilled' && r.value,\n ).length\n const failed = ids.length - succeeded\n\n if (failed === 0) {\n setActionFeedback({\n type: 'success',\n message: `${succeeded} ${t('reservation:pendingConfirmSuccess').toLowerCase()}`,\n })\n } else {\n setActionFeedback({\n type: failed === ids.length ? 'error' : 'success',\n message: t('reservation:pendingBulkConfirmSuccess')\n .replace('{{succeeded}}', String(succeeded))\n .replace('{{failed}}', String(failed)),\n })\n }\n\n setSelectedIds(new Set())\n void fetchPendingReservations()\n void fetchPendingCount()\n }, [selectedIds, patchReservation, fetchPendingReservations, fetchPendingCount, t, confirmStatus])\n\n const handleEventClick = useCallback((e: React.MouseEvent, id: string) => {\n e.stopPropagation()\n setDrawerDocId(id)\n setInitialData(undefined)\n pendingDrawerOpen.current = true\n }, [])\n\n const handleEventKeyDown = useCallback((e: React.KeyboardEvent, id: string) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n e.stopPropagation()\n setDrawerDocId(id)\n setInitialData(undefined)\n pendingDrawerOpen.current = true\n }\n }, [])\n\n const handleCreateNew = useCallback(() => {\n setDrawerDocId(null)\n setInitialData(undefined)\n pendingDrawerOpen.current = true\n }, [])\n\n const handleDateClick = useCallback((date: Date) => {\n setDrawerDocId(null)\n setInitialData({ startTime: date.toISOString() })\n pendingDrawerOpen.current = true\n }, [])\n\n // Click-to-book: open new-reservation drawer pre-filled with startTime + optional resource\n const handleSlotClick = useCallback(\n (startIso: string) => {\n setDrawerDocId(null)\n setInitialData({\n ...(selectedResourceId ? { resource: selectedResourceId } : {}),\n startTime: startIso,\n })\n pendingDrawerOpen.current = true\n },\n [selectedResourceId],\n )\n\n // Lane-specific book: pre-fills both the specific resource and startTime\n const handleLaneBook = useCallback((resourceId: string, startIso: string) => {\n setDrawerDocId(null)\n setInitialData({ resource: resourceId, startTime: startIso })\n pendingDrawerOpen.current = true\n }, [])\n\n const openDocDrawer = useCallback((id: string) => {\n setDrawerDocId(id)\n setInitialData(undefined)\n pendingDrawerOpen.current = true\n }, [])\n\n const navigate = useCallback(\n (direction: -1 | 1) => {\n setCurrentDate((prev) => {\n const next = new Date(prev)\n if (viewMode === 'month') {\n next.setMonth(next.getMonth() + direction)\n } else if (viewMode === 'week') {\n next.setDate(next.getDate() + 7 * direction)\n } else {\n // day, lanes: step one day at a time\n next.setDate(next.getDate() + direction)\n }\n return next\n })\n },\n [viewMode],\n )\n\n const goToToday = useCallback(() => setCurrentDate(new Date()), [])\n\n const getResName = (field: { name?: string } | string | undefined): string => {\n if (!field) {return ''}\n if (typeof field === 'string') {return ''}\n return field.name ?? ''\n }\n\n const getCustomerName = (field: Reservation['customer']): string => {\n if (!field) {return ''}\n if (typeof field === 'string') {return ''}\n const parts = [field.firstName, field.lastName].filter(Boolean)\n return parts.length > 0 ? parts.join(' ') : (field.name ?? '')\n }\n\n const getEventLabel = (r: Reservation, compact: boolean) => {\n const time = new Date(r.startTime).toLocaleTimeString([], {\n hour: '2-digit',\n minute: '2-digit',\n timeZone: reservationTimezone,\n })\n const serviceName = getResName(r.service)\n if (compact) {\n return `${time} ${serviceName}`.trim()\n }\n const customerName = getCustomerName(r.customer)\n const parts = [time, serviceName, customerName].filter(Boolean)\n return parts.join(' - ')\n }\n\n // Returns all resource names for a reservation — from items array if present, otherwise top-level resource\n const getResourceNames = (r: Reservation): string[] => {\n if (r.items && r.items.length > 0) {\n const names = r.items\n .map((item) => getResName(item.resource))\n .filter((name) => name.length > 0)\n if (names.length > 0) {return names}\n }\n const single = getResName(r.resource)\n return single ? [single] : []\n }\n\n const getEventTooltip = (r: Reservation): string => {\n const serviceName = getResName(r.service) || t('reservation:calendarUnknownService')\n const startStr = new Date(r.startTime).toLocaleTimeString([], {\n hour: '2-digit',\n minute: '2-digit',\n timeZone: reservationTimezone,\n })\n const endStr = r.endTime\n ? new Date(r.endTime).toLocaleTimeString([], {\n hour: '2-digit',\n minute: '2-digit',\n timeZone: reservationTimezone,\n })\n : '?'\n const customerName = getCustomerName(r.customer) || t('reservation:calendarUnknownCustomer')\n const resourceNames = getResourceNames(r)\n const resourceStr =\n resourceNames.length > 0\n ? resourceNames.join(', ')\n : t('reservation:calendarUnknownResource')\n const status = STATUS_LABELS[r.status] ?? r.status\n return [\n serviceName,\n `${startStr} - ${endStr}`,\n `${t('reservation:tooltipCustomer')} ${customerName}`,\n `${t('reservation:tooltipResource')} ${resourceStr}`,\n `${t('reservation:tooltipStatus')} ${status}`,\n ].join('\\n')\n }\n\n const renderEventItem = (r: Reservation, compact: boolean) => {\n // Use CSS class for built-in statuses; also apply inline background for custom statuses\n const cssClass = STATUS_CLASS_MAP[r.status] ?? ''\n const color = STATUS_COLORS[r.status]\n // Only apply inline style when there's no CSS class (custom statuses) or as a supplement\n const inlineStyle = cssClass ? undefined : { background: color }\n const hasItems = Array.isArray(r.items) && r.items.length > 0\n return (\n <div\n className={`${styles.eventItem} ${cssClass} ${hasItems && !compact ? styles.eventItemExpanded : ''}`}\n key={r.id}\n onClick={(e) => handleEventClick(e, r.id)}\n onKeyDown={(e) => handleEventKeyDown(e, r.id)}\n role=\"button\"\n style={inlineStyle}\n tabIndex={0}\n title={getEventTooltip(r)}\n >\n {getEventLabel(r, compact)}\n {hasItems && (\n <div className={styles.itemBadges}>\n {r.items!.map((it, i) => {\n const name = typeof it.resource === 'object' ? it.resource?.name : it.resource\n return (\n <span className={styles.itemBadge} key={i}>\n {String(name ?? '')}\n </span>\n )\n })}\n </div>\n )}\n </div>\n )\n }\n\n // Dynamic legend: iterates all statuses from the status machine config\n const renderStatusLegend = () => {\n const statuses = statusMachine?.statuses ?? Object.keys(BUILTIN_STATUS_COLORS)\n return (\n <div className={styles.statusLegend}>\n {statuses.map((key) => (\n <div className={styles.legendItem} key={key}>\n <span className={styles.legendDot} style={{ background: STATUS_COLORS[key] }} />\n {STATUS_LABELS[key] ?? key}\n </div>\n ))}\n </div>\n )\n }\n\n const renderCurrentTimeLine = (cellDate: Date, cellHour: number) => {\n const now = new Date()\n if (\n now.getFullYear() !== cellDate.getFullYear() ||\n now.getMonth() !== cellDate.getMonth() ||\n now.getDate() !== cellDate.getDate() ||\n now.getHours() !== cellHour\n ) {\n return null\n }\n const topPercent = (now.getMinutes() / 60) * 100\n return <div className={styles.currentTimeLine} style={{ top: `${topPercent}%` }} />\n }\n\n const renderMonthView = () => {\n const firstDay = new Date(currentDate.getFullYear(), currentDate.getMonth(), 1)\n const startDay = new Date(firstDay)\n startDay.setDate(startDay.getDate() - startDay.getDay())\n\n const days: Date[] = []\n const d = new Date(startDay)\n for (let i = 0; i < 42; i++) {\n days.push(new Date(d))\n d.setDate(d.getDate() + 1)\n }\n\n const today = new Date()\n const todayStr = getDayKeyInTimezone(today, reservationTimezone)\n\n return (\n <div className={styles.monthGrid}>\n {[\n t('reservation:dayShortSun'),\n t('reservation:dayShortMon'),\n t('reservation:dayShortTue'),\n t('reservation:dayShortWed'),\n t('reservation:dayShortThu'),\n t('reservation:dayShortFri'),\n t('reservation:dayShortSat'),\n ].map((d) => (\n <div className={styles.dayHeader} key={d}>\n {d}\n </div>\n ))}\n {days.map((day, i) => {\n const dayKey = getDayKeyInTimezone(day, reservationTimezone)\n const isToday = dayKey === todayStr\n const isOtherMonth =\n dayKey.slice(0, 7) !== getDayKeyInTimezone(currentDate, reservationTimezone).slice(0, 7)\n const dayReservations = filteredReservations.filter((r) => {\n const rKey = getDayKeyInTimezone(new Date(r.startTime), reservationTimezone)\n return rKey === dayKey\n })\n\n const clickDate = new Date(day)\n clickDate.setHours(9, 0, 0, 0)\n\n return (\n <div\n className={`${styles.dayCell} ${isOtherMonth ? styles.dayCellOtherMonth : ''} ${isToday ? styles.dayCellToday : ''}`}\n key={i}\n onClick={() => handleDateClick(clickDate)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n handleDateClick(clickDate)\n }\n }}\n role=\"button\"\n tabIndex={0}\n >\n <div className={styles.dayNumber}>{day.getDate()}</div>\n {dayReservations.map((r) => renderEventItem(r, true))}\n </div>\n )\n })}\n </div>\n )\n }\n\n const renderWeekView = () => {\n const startOfWeek = new Date(currentDate)\n startOfWeek.setDate(startOfWeek.getDate() - startOfWeek.getDay())\n startOfWeek.setHours(0, 0, 0, 0)\n\n const weekDays: Date[] = []\n for (let i = 0; i < 7; i++) {\n const d = new Date(startOfWeek)\n d.setDate(d.getDate() + i)\n weekDays.push(d)\n }\n\n // Visible-hour window derived from the week's bookings (review D8)\n const weekReservations = filteredReservations.filter((r) => {\n const k = getDayKeyInTimezone(new Date(r.startTime), reservationTimezone)\n return weekDays.some((d) => getDayKeyInTimezone(d, reservationTimezone) === k)\n })\n const { endHour: gridEndHour, startHour: gridStartHour } = computeHourWindow(\n weekReservations,\n reservationTimezone,\n )\n const hours = Array.from({ length: gridEndHour - gridStartHour }, (_, i) => i + gridStartHour)\n const gridStep = 60\n\n // Build per-day slot-state maps when a resource is selected\n const daySlotMaps = availability\n ? new Map(\n weekDays.map((day) => {\n const isoDay = getDayKeyInTimezone(day, reservationTimezone)\n const dayAvail = availability.days.find((d) => d.date === isoDay)\n const dayStart = new Date(day)\n dayStart.setHours(gridStartHour, 0, 0, 0)\n const dayEnd = new Date(day)\n dayEnd.setHours(gridEndHour, 0, 0, 0)\n const slots = dayAvail\n ? computeSlotStates({\n busy: availability.busy,\n capacityMode: availability.capacityMode,\n dayEnd,\n dayStart,\n external: availability.external,\n quantity: availability.quantity,\n requiredPools: availability.requiredPools,\n shiftWindows: dayAvail.shiftWindows,\n step: gridStep,\n timeOff: dayAvail.timeOff,\n })\n : []\n // Index by slot start ISO for fast lookup\n const slotByStart = new Map(slots.map((s) => [s.start.toISOString(), s]))\n return [isoDay, slotByStart] as const\n }),\n )\n : null\n\n return (\n <div className={styles.weekView}>\n <div className={styles.dayHeader} />\n {weekDays.map((d, i) => (\n <div className={styles.dayHeader} key={i}>\n {d.toLocaleDateString([], {\n day: 'numeric',\n month: 'numeric',\n timeZone: reservationTimezone,\n weekday: 'short',\n })}\n </div>\n ))}\n {hours.map((hour) => (\n <Fragment key={`row-${hour}`}>\n <div className={styles.timeLabel}>\n {hour.toString().padStart(2, '0')}:00\n </div>\n {weekDays.map((day, di) => {\n const isoDay = getDayKeyInTimezone(day, reservationTimezone)\n const cellReservations = filteredReservations.filter((r) => {\n const rDate = new Date(r.startTime)\n return (\n getDayKeyInTimezone(rDate, reservationTimezone) === isoDay &&\n getHourInTimezone(rDate, reservationTimezone) === hour\n )\n })\n const clickDate = new Date(day)\n clickDate.setHours(hour, 0, 0, 0)\n\n // Slot state (only when a resource is selected)\n const slotMap = daySlotMaps?.get(isoDay)\n const slotInfo = slotMap?.get(clickDate.toISOString()) ?? null\n\n // Derive cell CSS class and interactivity based on slot state\n let slotClass = ''\n let isNonInteractive = false\n if (slotInfo) {\n if (slotInfo.state === 'off-shift') {\n slotClass = styles.slotOffShift\n isNonInteractive = true\n } else if (slotInfo.state === 'time-off') {\n slotClass = styles.slotTimeOff\n isNonInteractive = true\n } else if (slotInfo.state === 'external') {\n slotClass = styles.slotExternal\n isNonInteractive = true\n } else if (slotInfo.state === 'full') {\n slotClass = styles.slotFull\n isNonInteractive = true\n } else {\n slotClass = styles.slotFree\n }\n }\n\n // Time-off label: show type/reason from dayAvail when in time-off state\n const dayAvail = availability?.days.find((d) => d.date === isoDay)\n const timeOffEntry =\n slotInfo?.state === 'time-off'\n ? dayAvail?.timeOff.find(\n (to) =>\n new Date(to.start) <= clickDate && clickDate < new Date(to.end),\n )\n : undefined\n const timeOffLabel = timeOffEntry?.type ?? timeOffEntry?.reason ?? null\n\n const handleClick = isNonInteractive\n ? undefined\n : availability\n ? () => handleSlotClick(clickDate.toISOString())\n : () => handleDateClick(clickDate)\n const handleKeyDown = isNonInteractive\n ? undefined\n : (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n if (availability) {\n handleSlotClick(clickDate.toISOString())\n } else {\n handleDateClick(clickDate)\n }\n }\n }\n\n return (\n <div\n className={`${styles.weekCell} ${slotClass}`}\n key={`cell-${hour}-${di}`}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n role=\"button\"\n tabIndex={isNonInteractive ? -1 : 0}\n >\n {renderCurrentTimeLine(day, hour)}\n {timeOffLabel && (\n <span className={styles.timeOffLabel}>{timeOffLabel}</span>\n )}\n {slotInfo && availability && availability.quantity > 1 && (\n <span className={styles.capacityBadge}>\n {slotInfo.occupancy}/{availability.quantity}\n </span>\n )}\n {cellReservations.map((r) => renderEventItem(r, false))}\n </div>\n )\n })}\n </Fragment>\n ))}\n </div>\n )\n }\n\n const renderDayView = () => {\n // Build slot-state map for the current day when a resource is selected\n const currentDayKey = getDayKeyInTimezone(currentDate, reservationTimezone)\n\n // Visible-hour window derived from this day's bookings (review D8)\n const dayReservations = filteredReservations.filter(\n (r) => getDayKeyInTimezone(new Date(r.startTime), reservationTimezone) === currentDayKey,\n )\n const { endHour: gridEndHour, startHour: gridStartHour } = computeHourWindow(\n dayReservations,\n reservationTimezone,\n )\n const hours = Array.from({ length: gridEndHour - gridStartHour }, (_, i) => i + gridStartHour)\n const gridStep = 60\n let daySlotMap: Map<string, SlotInfo> | null = null\n if (availability) {\n const isoDay = currentDayKey\n const dayAvail = availability.days.find((d) => d.date === isoDay)\n const dayStart = new Date(currentDate)\n dayStart.setHours(gridStartHour, 0, 0, 0)\n const dayEnd = new Date(currentDate)\n dayEnd.setHours(gridEndHour, 0, 0, 0)\n const slots = dayAvail\n ? computeSlotStates({\n busy: availability.busy,\n capacityMode: availability.capacityMode,\n dayEnd,\n dayStart,\n external: availability.external,\n quantity: availability.quantity,\n requiredPools: availability.requiredPools,\n shiftWindows: dayAvail.shiftWindows,\n step: gridStep,\n timeOff: dayAvail.timeOff,\n })\n : []\n daySlotMap = new Map(slots.map((s) => [s.start.toISOString(), s]))\n }\n\n return (\n <div className={styles.dayView}>\n {hours.map((hour) => {\n const hourReservations = filteredReservations.filter((r) => {\n const rDate = new Date(r.startTime)\n return (\n getDayKeyInTimezone(rDate, reservationTimezone) === currentDayKey &&\n getHourInTimezone(rDate, reservationTimezone) === hour\n )\n })\n const clickDate = new Date(currentDate)\n clickDate.setHours(hour, 0, 0, 0)\n\n // Slot state (only when a resource is selected)\n const slotInfo = daySlotMap?.get(clickDate.toISOString()) ?? null\n\n // Derive cell CSS class and interactivity based on slot state\n let slotClass = ''\n let isNonInteractive = false\n if (slotInfo) {\n if (slotInfo.state === 'off-shift') {\n slotClass = styles.slotOffShift\n isNonInteractive = true\n } else if (slotInfo.state === 'time-off') {\n slotClass = styles.slotTimeOff\n isNonInteractive = true\n } else if (slotInfo.state === 'external') {\n slotClass = styles.slotExternal\n isNonInteractive = true\n } else if (slotInfo.state === 'full') {\n slotClass = styles.slotFull\n isNonInteractive = true\n } else {\n slotClass = styles.slotFree\n }\n }\n\n // Time-off label\n const dayAvail = availability?.days.find((d) => d.date === currentDayKey)\n const timeOffEntry =\n slotInfo?.state === 'time-off'\n ? dayAvail?.timeOff.find(\n (to) => new Date(to.start) <= clickDate && clickDate < new Date(to.end),\n )\n : undefined\n const timeOffLabel = timeOffEntry?.type ?? timeOffEntry?.reason ?? null\n\n const handleClick = isNonInteractive\n ? undefined\n : availability\n ? () => handleSlotClick(clickDate.toISOString())\n : () => handleDateClick(clickDate)\n const handleKeyDown = isNonInteractive\n ? undefined\n : (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n if (availability) {\n handleSlotClick(clickDate.toISOString())\n } else {\n handleDateClick(clickDate)\n }\n }\n }\n\n return (\n <Fragment key={`row-${hour}`}>\n <div className={styles.timeLabel}>\n {hour.toString().padStart(2, '0')}:00\n </div>\n <div\n className={`${styles.dayViewCell} ${slotClass}`}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n role=\"button\"\n tabIndex={isNonInteractive ? -1 : 0}\n >\n {renderCurrentTimeLine(currentDate, hour)}\n {timeOffLabel && (\n <span className={styles.timeOffLabel}>{timeOffLabel}</span>\n )}\n {slotInfo && availability && availability.quantity > 1 && (\n <span className={styles.capacityBadge}>\n {slotInfo.occupancy}/{availability.quantity}\n </span>\n )}\n {hourReservations.map((r) => renderEventItem(r, false))}\n </div>\n </Fragment>\n )\n })}\n </div>\n )\n }\n\n const renderPendingView = () => {\n if (filteredPendingReservations.length === 0) {\n return <div className={styles.pendingEmpty}>{t('reservation:pendingEmpty')}</div>\n }\n\n const allSelected =\n filteredPendingReservations.length > 0 &&\n filteredPendingReservations.every((r) => selectedIds.has(r.id))\n\n const toggleSelectAll = () => {\n if (allSelected) {\n setSelectedIds(new Set())\n } else {\n setSelectedIds(new Set(filteredPendingReservations.map((r) => r.id)))\n }\n }\n\n const toggleSelect = (id: string) => {\n setSelectedIds((prev) => {\n const next = new Set(prev)\n if (next.has(id)) {\n next.delete(id)\n } else {\n next.add(id)\n }\n return next\n })\n }\n\n const formatDateTime = (iso: string) => {\n const d = new Date(iso)\n return d.toLocaleString([], {\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n month: 'short',\n timeZone: reservationTimezone,\n year: 'numeric',\n })\n }\n\n return (\n <div className={styles.pendingView}>\n <div className={styles.pendingToolbar}>\n <label className={styles.selectAllLabel}>\n <input\n aria-label={t('reservation:pendingSelectAll')}\n checked={allSelected}\n onChange={toggleSelectAll}\n type=\"checkbox\"\n />\n {t('reservation:pendingSelectAll')}\n </label>\n {selectedIds.size > 0 && (\n <button\n className={styles.bulkConfirmButton}\n disabled={confirmingIds.size > 0}\n onClick={() => void confirmSelected()}\n type=\"button\"\n >\n {confirmingIds.size > 0\n ? t('reservation:pendingConfirming')\n : t('reservation:pendingConfirmSelected').replace(\n '{{count}}',\n String(selectedIds.size),\n )}\n </button>\n )}\n </div>\n {actionFeedback && (\n <div\n className={`${styles.feedbackToast} ${actionFeedback.type === 'success' ? styles.feedbackSuccess : styles.feedbackError}`}\n >\n {actionFeedback.message}\n </div>\n )}\n <table className={styles.pendingTable}>\n <thead>\n <tr>\n <th aria-label={t('reservation:pendingSelectAll')} className={styles.pendingTh} />\n <th className={styles.pendingTh}>{t('reservation:fieldCustomer')}</th>\n <th className={styles.pendingTh}>{t('reservation:fieldService')}</th>\n <th className={styles.pendingTh}>{t('reservation:fieldResource')}</th>\n <th className={styles.pendingTh}>{t('reservation:pendingDateTime')}</th>\n <th className={styles.pendingTh}>{t('reservation:pendingActions')}</th>\n </tr>\n </thead>\n <tbody>\n {filteredPendingReservations.map((r) => {\n const isConfirming = confirmingIds.has(r.id)\n // Show all resources from items array if present, else top-level resource\n const resourceDisplay =\n getResourceNames(r).join(', ') || t('reservation:calendarUnknownResource')\n return (\n <tr className={styles.pendingRow} key={r.id}>\n <td className={styles.pendingTd}>\n <input\n aria-label={getCustomerName(r.customer) || r.id}\n checked={selectedIds.has(r.id)}\n onChange={() => toggleSelect(r.id)}\n type=\"checkbox\"\n />\n </td>\n <td className={styles.pendingTd}>\n <span\n className={styles.pendingCustomerLink}\n onClick={() => openDocDrawer(r.id)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n openDocDrawer(r.id)\n }\n }}\n role=\"button\"\n tabIndex={0}\n >\n {getCustomerName(r.customer) || t('reservation:calendarUnknownCustomer')}\n </span>\n </td>\n <td className={styles.pendingTd}>\n {getResName(r.service) || t('reservation:calendarUnknownService')}\n </td>\n <td className={styles.pendingTd}>{resourceDisplay}</td>\n <td className={styles.pendingTd}>{formatDateTime(r.startTime)}</td>\n <td className={styles.pendingTd}>\n <button\n className={styles.confirmButton}\n disabled={isConfirming}\n onClick={() => void handleQuickConfirm(r.id)}\n title={t('reservation:pendingConfirm')}\n type=\"button\"\n >\n &#x2713;\n </button>\n <button\n className={styles.cancelButton}\n disabled={isConfirming}\n onClick={() => void handleQuickCancel(r.id)}\n title={t('reservation:pendingCancel')}\n type=\"button\"\n >\n &#x2717;\n </button>\n </td>\n </tr>\n )\n })}\n </tbody>\n </table>\n </div>\n )\n }\n\n const dateLabel = useMemo(() => {\n if (viewMode === 'month') {\n return currentDate.toLocaleDateString([], { month: 'long', year: 'numeric' })\n }\n if (viewMode === 'week') {\n const startOfWeek = new Date(currentDate)\n startOfWeek.setDate(startOfWeek.getDate() - startOfWeek.getDay())\n const endOfWeek = new Date(startOfWeek)\n endOfWeek.setDate(endOfWeek.getDate() + 6)\n return `${startOfWeek.toLocaleDateString([], { day: 'numeric', month: 'short', timeZone: reservationTimezone })} - ${endOfWeek.toLocaleDateString([], { day: 'numeric', month: 'short', timeZone: reservationTimezone, year: 'numeric' })}`\n }\n return currentDate.toLocaleDateString([], {\n day: 'numeric',\n month: 'long',\n timeZone: reservationTimezone,\n weekday: 'long',\n year: 'numeric',\n })\n }, [currentDate, reservationTimezone, viewMode])\n\n const handleDrawerSave = useCallback(() => {\n void fetchReservations()\n void fetchPendingCount()\n if (viewMode === 'pending') {\n void fetchPendingReservations()\n }\n }, [fetchReservations, fetchPendingCount, fetchPendingReservations, viewMode])\n\n return (\n <div className={styles.wrapper}>\n <div className={styles.header}>\n {viewMode !== 'pending' && (\n <div className={styles.navButtons}>\n <button className={styles.navButton} onClick={() => navigate(-1)} type=\"button\">\n &larr;\n </button>\n <button className={styles.navButton} onClick={goToToday} type=\"button\">\n {t('reservation:calendarToday')}\n </button>\n <button className={styles.navButton} onClick={() => navigate(1)} type=\"button\">\n &rarr;\n </button>\n <span className={styles.currentDate}>{dateLabel}</span>\n </div>\n )}\n {viewMode === 'pending' && <div />}\n <div className={styles.viewToggle}>\n <button className={styles.createButton} onClick={handleCreateNew} type=\"button\">\n {t('reservation:calendarCreateNew')}\n </button>\n {([\n { key: 'month' as ViewMode, label: t('reservation:calendarMonth') },\n { key: 'week' as ViewMode, label: t('reservation:calendarWeek') },\n { key: 'day' as ViewMode, label: t('reservation:calendarDay') },\n { key: 'lanes' as ViewMode, label: t('reservation:calendarLanes') },\n { key: 'pending' as ViewMode, label: t('reservation:calendarPending') },\n ]).map(({ key, label }) => (\n <button\n className={`${styles.viewToggleButton} ${viewMode === key ? styles.viewToggleButtonActive : ''}`}\n key={key}\n onClick={() => setViewMode(key)}\n type=\"button\"\n >\n {label}\n {key === 'pending' && pendingCount > 0 && (\n <span className={styles.pendingBadge}>\n {selectedResourceId ? filteredPendingReservations.length : pendingCount}\n </span>\n )}\n </button>\n ))}\n </div>\n </div>\n {viewMode !== 'pending' && renderStatusLegend()}\n {viewMode !== 'pending' && truncation && (\n <div className={styles.truncationNotice} role=\"status\">\n {t('reservation:calendarShowingNofM', {\n shown: String(truncation.shown),\n total: String(truncation.total),\n })}\n </div>\n )}\n {resources.length > 1 && (\n <div className={styles.filterBar}>\n <select\n aria-label={t('reservation:filterByResource')}\n className={styles.resourceFilter}\n onChange={(e) => setSelectedResourceId(e.target.value)}\n value={selectedResourceId}\n >\n <option value=\"\">{t('reservation:filterAllResources')}</option>\n {resources.map((r) => (\n <option key={r.id} value={r.id}>\n {r.name}\n </option>\n ))}\n </select>\n </div>\n )}\n {loading && viewMode !== 'pending' && viewMode !== 'lanes' ? (\n <div className={styles.loading}>{t('reservation:calendarLoading')}</div>\n ) : (\n <>\n {viewMode === 'month' && renderMonthView()}\n {viewMode === 'week' && renderWeekView()}\n {viewMode === 'day' && renderDayView()}\n {viewMode === 'lanes' &&\n (() => {\n const laneDayKey = getDayKeyInTimezone(currentDate, reservationTimezone)\n const { endHour, startHour } = computeHourWindow(\n filteredReservations.filter(\n (r) =>\n getDayKeyInTimezone(new Date(r.startTime), reservationTimezone) === laneDayKey,\n ),\n reservationTimezone,\n )\n return (\n <LaneTimelineView\n apiBase={apiBase}\n day={currentDate}\n endHour={endHour}\n onBook={handleLaneBook}\n resources={\n selectedResourceId\n ? resources.filter((r) => r.id === selectedResourceId)\n : resources\n }\n startHour={startHour}\n timeZone={reservationTimezone}\n />\n )\n })()}\n </>\n )}\n {viewMode === 'pending' && renderPendingView()}\n <DocumentDrawer initialData={initialData} onSave={handleDrawerSave} />\n </div>\n )\n}\n"],"names":["useConfig","useDocumentDrawer","useTranslation","React","Fragment","useCallback","useEffect","useMemo","useRef","useState","computeSlotStates","statusToI18nKey","getDayKeyInTimezone","getHourInTimezone","useTenantFilter","styles","LaneTimelineView","useResourceAvailability","STATUS_CLASS_MAP","cancelled","statusCancelled","completed","statusCompleted","confirmed","statusConfirmed","statusNoShow","pending","statusPending","BUILTIN_STATUS_COLORS","CUSTOM_STATUS_PALETTE","MAX_LIST_LIMIT","DEFAULT_HOUR_START","DEFAULT_HOUR_END","computeHourWindow","reservations","timeZone","startHour","endHour","r","startTime","sh","Date","Math","min","max","endTime","CalendarView","config","t","_t","slugs","admin","custom","reservationSlugs","reservationSlug","apiUrl","serverURL","routes","api","apiBase","resourceSlug","resources","reservationTenantParams","resourceTenantParams","staticReservationTimezone","reservationTimezone","effectiveTimezone","setEffectiveTimezone","tenantKey","JSON","stringify","res","fetch","credentials","ok","json","statusMachine","reservationStatusMachine","defaultStatus","STATUS_COLORS","colors","statuses","forEach","s","i","length","cancelStatus","confirmStatus","terminalStatuses","transitions","defaultTransitions","nonTerminal","find","includes","terminal","STATUS_LABELS","labels","key","translated","charAt","toUpperCase","slice","currentDate","setCurrentDate","viewMode","setViewMode","setReservations","loading","setLoading","truncation","setTruncation","reservationsSeq","pendingSeq","drawerDocId","setDrawerDocId","initialData","setInitialData","undefined","setResources","selectedResourceId","setSelectedResourceId","pendingReservations","setPendingReservations","pendingCount","setPendingCount","selectedIds","setSelectedIds","Set","confirmingIds","setConfirmingIds","actionFeedback","setActionFeedback","DocumentDrawer","openDrawer","id","collectionSlug","pendingDrawerOpen","current","fetchResources","params","URLSearchParams","depth","limit","sort","url","response","result","docs","map","d","name","rangeEnd","rangeStart","start","end","setDate","getDate","getDay","setTime","getTime","dayOfWeek","setHours","data","availability","fetchReservations","seq","String","toISOString","total","totalDocs","shown","fetchPendingCount","fetchPendingReservations","matchesResourceFilter","topId","resource","items","some","item","itemId","filteredReservations","filter","filteredPendingReservations","timer","setTimeout","clearTimeout","patchReservation","body","headers","method","handleQuickConfirm","prev","add","status","next","delete","type","message","handleQuickCancel","confirmSelected","ids","Array","from","results","Promise","allSettled","succeeded","value","failed","toLowerCase","replace","handleEventClick","e","stopPropagation","handleEventKeyDown","preventDefault","handleCreateNew","handleDateClick","date","handleSlotClick","startIso","handleLaneBook","resourceId","openDocDrawer","navigate","direction","setMonth","getMonth","goToToday","getResName","field","getCustomerName","parts","firstName","lastName","Boolean","join","getEventLabel","compact","time","toLocaleTimeString","hour","minute","serviceName","service","trim","customerName","customer","getResourceNames","names","single","getEventTooltip","startStr","endStr","resourceNames","resourceStr","renderEventItem","cssClass","color","inlineStyle","background","hasItems","isArray","div","className","eventItem","eventItemExpanded","onClick","onKeyDown","role","style","tabIndex","title","itemBadges","it","span","itemBadge","renderStatusLegend","Object","keys","statusLegend","legendItem","legendDot","renderCurrentTimeLine","cellDate","cellHour","now","getFullYear","getHours","topPercent","getMinutes","currentTimeLine","top","renderMonthView","firstDay","startDay","days","push","today","todayStr","monthGrid","dayHeader","day","dayKey","isToday","isOtherMonth","dayReservations","rKey","clickDate","dayCell","dayCellOtherMonth","dayCellToday","dayNumber","renderWeekView","startOfWeek","weekDays","weekReservations","k","gridEndHour","gridStartHour","hours","_","gridStep","daySlotMaps","Map","isoDay","dayAvail","dayStart","dayEnd","slots","busy","capacityMode","external","quantity","requiredPools","shiftWindows","step","timeOff","slotByStart","weekView","toLocaleDateString","month","weekday","timeLabel","toString","padStart","di","cellReservations","rDate","slotMap","get","slotInfo","slotClass","isNonInteractive","state","slotOffShift","slotTimeOff","slotExternal","slotFull","slotFree","timeOffEntry","to","timeOffLabel","reason","handleClick","handleKeyDown","weekCell","capacityBadge","occupancy","renderDayView","currentDayKey","daySlotMap","dayView","hourReservations","dayViewCell","renderPendingView","pendingEmpty","allSelected","every","has","toggleSelectAll","toggleSelect","formatDateTime","iso","toLocaleString","year","pendingView","pendingToolbar","label","selectAllLabel","input","aria-label","checked","onChange","size","button","bulkConfirmButton","disabled","feedbackToast","feedbackSuccess","feedbackError","table","pendingTable","thead","tr","th","pendingTh","tbody","isConfirming","resourceDisplay","pendingRow","td","pendingTd","pendingCustomerLink","confirmButton","cancelButton","dateLabel","endOfWeek","handleDrawerSave","wrapper","header","navButtons","navButton","viewToggle","createButton","viewToggleButton","viewToggleButtonActive","pendingBadge","truncationNotice","filterBar","select","resourceFilter","target","option","laneDayKey","onBook","onSave"],"mappings":"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"}
package/dist/defaults.js CHANGED
@@ -119,6 +119,7 @@ export function resolveConfig(pluginOptions) {
119
119
  defaultBufferTime: pluginOptions.defaultBufferTime ?? DEFAULT_BUFFER_TIME,
120
120
  disabled: pluginOptions.disabled ?? false,
121
121
  extraReservationFields: pluginOptions.extraReservationFields ?? [],
122
+ getExternalBusy: pluginOptions.getExternalBusy,
122
123
  // Real value is set by the plugin once config.collections is known (C8)
123
124
  hasMediaCollection: false,
124
125
  hooks: pluginOptions.hooks ?? {},
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/defaults.ts"],"sourcesContent":["import type {\n ReservationPluginConfig,\n ResolvedReservationPluginConfig,\n ResolvedStaffProvisioningConfig,\n StatusMachineConfig,\n} from './types.js'\n\nimport { DEFAULT_STATUS_MACHINE } from './types.js'\nimport { validateTimezone } from './utilities/timezoneUtils.js'\n\nfunction validateStatusMachine(sm: StatusMachineConfig): void {\n if (!sm.statuses.includes(sm.defaultStatus)) {\n throw new Error(`statusMachine.defaultStatus \"${sm.defaultStatus}\" is not in statuses array`)\n }\n for (const s of sm.blockingStatuses) {\n if (!sm.statuses.includes(s)) {\n throw new Error(`statusMachine.blockingStatuses contains \"${s}\" which is not in statuses array`)\n }\n }\n for (const s of sm.terminalStatuses) {\n if (!sm.statuses.includes(s)) {\n throw new Error(`statusMachine.terminalStatuses contains \"${s}\" which is not in statuses array`)\n }\n }\n for (const [from, targets] of Object.entries(sm.transitions)) {\n if (!sm.statuses.includes(from)) {\n throw new Error(`statusMachine.transitions has key \"${from}\" which is not in statuses array`)\n }\n for (const to of targets) {\n if (!sm.statuses.includes(to)) {\n throw new Error(`statusMachine.transitions[\"${from}\"] targets \"${to}\" which is not in statuses array`)\n }\n }\n }\n // A terminal status must have no outgoing transitions — otherwise the config\n // contradicts itself (the status is declared terminal but can be left).\n for (const s of sm.terminalStatuses) {\n if ((sm.transitions[s]?.length ?? 0) > 0) {\n throw new Error(\n `statusMachine.terminalStatuses contains \"${s}\" but transitions[\"${s}\"] is non-empty — a terminal status cannot have outgoing transitions`,\n )\n }\n }\n // A reservation is born in defaultStatus, so it must not be terminal.\n if (sm.terminalStatuses.includes(sm.defaultStatus)) {\n throw new Error(`statusMachine.defaultStatus \"${sm.defaultStatus}\" cannot be a terminal status`)\n }\n if (!sm.statuses.includes(sm.confirmStatus)) {\n throw new Error(`statusMachine.confirmStatus \"${sm.confirmStatus}\" is not in statuses array`)\n }\n if (!sm.statuses.includes(sm.cancelStatus)) {\n throw new Error(`statusMachine.cancelStatus \"${sm.cancelStatus}\" is not in statuses array`)\n }\n}\n\nexport const DEFAULT_RESOURCE_TYPES = ['staff', 'equipment', 'room']\nexport const DEFAULT_LEAVE_TYPES = ['vacation', 'sick', 'personal', 'closure', 'other']\n\nfunction resolveStaffProvisioning(\n pluginOptions: ReservationPluginConfig,\n resourceTypes: string[],\n): ResolvedStaffProvisioningConfig | undefined {\n const sp = pluginOptions.staffProvisioning\n if (!sp) {\n return undefined\n }\n\n if (!pluginOptions.resourceOwnerMode) {\n throw new Error('staffProvisioning requires resourceOwnerMode to be enabled')\n }\n if (sp.staffRoles.length === 0) {\n throw new Error('staffProvisioning.staffRoles must be a non-empty array')\n }\n const resourceType = sp.resourceType ?? 'staff'\n if (!resourceTypes.includes(resourceType)) {\n throw new Error(\n `staffProvisioning.resourceType \"${resourceType}\" is not in resourceTypes [${resourceTypes.join(', ')}]`,\n )\n }\n const userCollection = sp.userCollection ?? pluginOptions.userCollection\n if (!userCollection) {\n throw new Error(\n 'staffProvisioning.userCollection is required when top-level userCollection is unset',\n )\n }\n\n return {\n beforeCreate: sp.beforeCreate,\n nameFrom: sp.nameFrom ?? 'name',\n resourceType,\n roleField: sp.roleField ?? 'role',\n staffRoles: sp.staffRoles,\n userCollection,\n }\n}\n\nexport const DEFAULT_SLUGS = {\n customers: 'customers',\n media: 'media',\n reservations: 'reservations',\n resources: 'resources',\n schedules: 'schedules',\n services: 'services',\n} as const\n\nexport const DEFAULT_ADMIN_GROUP = 'Reservations'\nexport const DEFAULT_ALLOW_GUEST_BOOKING = false\nexport const DEFAULT_BUFFER_TIME = 0\nexport const DEFAULT_CANCELLATION_NOTICE_PERIOD = 24\n\nexport function resolveConfig(\n pluginOptions: ReservationPluginConfig,\n): ResolvedReservationPluginConfig {\n // A disabled plugin still resolves (so collections register with the right\n // slugs for schema stability) but skips all config validation — temporarily\n // disabling a misconfigured plugin should not throw at boot (review C3).\n const disabled = pluginOptions.disabled ?? false\n\n if (!disabled) {\n if (pluginOptions.resourceTypes !== undefined && pluginOptions.resourceTypes.length === 0) {\n throw new Error('resourceTypes must be a non-empty array')\n }\n if (pluginOptions.leaveTypes !== undefined && pluginOptions.leaveTypes.length === 0) {\n throw new Error('leaveTypes must be a non-empty array')\n }\n }\n\n const resourceTypes = pluginOptions.resourceTypes ?? DEFAULT_RESOURCE_TYPES\n const userStatusMachine = pluginOptions.statusMachine\n const rom = pluginOptions.resourceOwnerMode\n const resolved: ResolvedReservationPluginConfig = {\n access: pluginOptions.access ?? {},\n adminGroup: pluginOptions.adminGroup ?? DEFAULT_ADMIN_GROUP,\n allowGuestBooking: pluginOptions.allowGuestBooking ?? DEFAULT_ALLOW_GUEST_BOOKING,\n cancellationNoticePeriod:\n pluginOptions.cancellationNoticePeriod ?? DEFAULT_CANCELLATION_NOTICE_PERIOD,\n collectionOverrides: pluginOptions.collectionOverrides ?? {},\n defaultBufferTime: pluginOptions.defaultBufferTime ?? DEFAULT_BUFFER_TIME,\n disabled: pluginOptions.disabled ?? false,\n extraReservationFields: pluginOptions.extraReservationFields ?? [],\n // Real value is set by the plugin once config.collections is known (C8)\n hasMediaCollection: false,\n hooks: pluginOptions.hooks ?? {},\n leaveTypes: pluginOptions.leaveTypes ?? DEFAULT_LEAVE_TYPES,\n localized: false,\n multiTenant: {\n cookieName: pluginOptions.multiTenant?.cookieName ?? 'payload-tenant',\n tenantField: pluginOptions.multiTenant?.tenantField ?? 'tenant',\n timezoneField: pluginOptions.multiTenant?.timezoneField ?? 'timezone',\n },\n resourceOwnerMode: rom\n ? {\n adminRoles: rom.adminRoles ?? [],\n ownedServices: rom.ownedServices ?? false,\n ownerCollection: rom.ownerCollection,\n ownerField: rom.ownerField ?? 'owner',\n roleField: rom.roleField ?? pluginOptions.staffProvisioning?.roleField ?? 'role',\n }\n : undefined,\n resourceTypes,\n slugs: {\n customers: pluginOptions.slugs?.customers ?? DEFAULT_SLUGS.customers,\n media: pluginOptions.slugs?.media ?? DEFAULT_SLUGS.media,\n reservations: pluginOptions.slugs?.reservations ?? DEFAULT_SLUGS.reservations,\n resources: pluginOptions.slugs?.resources ?? DEFAULT_SLUGS.resources,\n schedules: pluginOptions.slugs?.schedules ?? DEFAULT_SLUGS.schedules,\n services: pluginOptions.slugs?.services ?? DEFAULT_SLUGS.services,\n },\n staffProvisioning: disabled\n ? undefined\n : resolveStaffProvisioning(pluginOptions, resourceTypes),\n statusMachine: userStatusMachine\n ? {\n blockingStatuses:\n userStatusMachine.blockingStatuses ?? DEFAULT_STATUS_MACHINE.blockingStatuses,\n cancelStatus: userStatusMachine.cancelStatus ?? DEFAULT_STATUS_MACHINE.cancelStatus,\n confirmStatus: userStatusMachine.confirmStatus ?? DEFAULT_STATUS_MACHINE.confirmStatus,\n defaultStatus: userStatusMachine.defaultStatus ?? DEFAULT_STATUS_MACHINE.defaultStatus,\n statuses: userStatusMachine.statuses ?? DEFAULT_STATUS_MACHINE.statuses,\n terminalStatuses:\n userStatusMachine.terminalStatuses ?? DEFAULT_STATUS_MACHINE.terminalStatuses,\n transitions: userStatusMachine.transitions ?? DEFAULT_STATUS_MACHINE.transitions,\n }\n : { ...DEFAULT_STATUS_MACHINE },\n timezone: pluginOptions.timezone ?? 'UTC',\n userCollection: pluginOptions.userCollection ?? undefined,\n }\n\n if (!disabled) {\n validateStatusMachine(resolved.statusMachine)\n validateTimezone(resolved.timezone)\n }\n\n return resolved\n}\n"],"names":["DEFAULT_STATUS_MACHINE","validateTimezone","validateStatusMachine","sm","statuses","includes","defaultStatus","Error","s","blockingStatuses","terminalStatuses","from","targets","Object","entries","transitions","to","length","confirmStatus","cancelStatus","DEFAULT_RESOURCE_TYPES","DEFAULT_LEAVE_TYPES","resolveStaffProvisioning","pluginOptions","resourceTypes","sp","staffProvisioning","undefined","resourceOwnerMode","staffRoles","resourceType","join","userCollection","beforeCreate","nameFrom","roleField","DEFAULT_SLUGS","customers","media","reservations","resources","schedules","services","DEFAULT_ADMIN_GROUP","DEFAULT_ALLOW_GUEST_BOOKING","DEFAULT_BUFFER_TIME","DEFAULT_CANCELLATION_NOTICE_PERIOD","resolveConfig","disabled","leaveTypes","userStatusMachine","statusMachine","rom","resolved","access","adminGroup","allowGuestBooking","cancellationNoticePeriod","collectionOverrides","defaultBufferTime","extraReservationFields","hasMediaCollection","hooks","localized","multiTenant","cookieName","tenantField","timezoneField","adminRoles","ownedServices","ownerCollection","ownerField","slugs","timezone"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/defaults.ts"],"sourcesContent":["import type {\n ReservationPluginConfig,\n ResolvedReservationPluginConfig,\n ResolvedStaffProvisioningConfig,\n StatusMachineConfig,\n} from './types.js'\n\nimport { DEFAULT_STATUS_MACHINE } from './types.js'\nimport { validateTimezone } from './utilities/timezoneUtils.js'\n\nfunction validateStatusMachine(sm: StatusMachineConfig): void {\n if (!sm.statuses.includes(sm.defaultStatus)) {\n throw new Error(`statusMachine.defaultStatus \"${sm.defaultStatus}\" is not in statuses array`)\n }\n for (const s of sm.blockingStatuses) {\n if (!sm.statuses.includes(s)) {\n throw new Error(`statusMachine.blockingStatuses contains \"${s}\" which is not in statuses array`)\n }\n }\n for (const s of sm.terminalStatuses) {\n if (!sm.statuses.includes(s)) {\n throw new Error(`statusMachine.terminalStatuses contains \"${s}\" which is not in statuses array`)\n }\n }\n for (const [from, targets] of Object.entries(sm.transitions)) {\n if (!sm.statuses.includes(from)) {\n throw new Error(`statusMachine.transitions has key \"${from}\" which is not in statuses array`)\n }\n for (const to of targets) {\n if (!sm.statuses.includes(to)) {\n throw new Error(`statusMachine.transitions[\"${from}\"] targets \"${to}\" which is not in statuses array`)\n }\n }\n }\n // A terminal status must have no outgoing transitions — otherwise the config\n // contradicts itself (the status is declared terminal but can be left).\n for (const s of sm.terminalStatuses) {\n if ((sm.transitions[s]?.length ?? 0) > 0) {\n throw new Error(\n `statusMachine.terminalStatuses contains \"${s}\" but transitions[\"${s}\"] is non-empty — a terminal status cannot have outgoing transitions`,\n )\n }\n }\n // A reservation is born in defaultStatus, so it must not be terminal.\n if (sm.terminalStatuses.includes(sm.defaultStatus)) {\n throw new Error(`statusMachine.defaultStatus \"${sm.defaultStatus}\" cannot be a terminal status`)\n }\n if (!sm.statuses.includes(sm.confirmStatus)) {\n throw new Error(`statusMachine.confirmStatus \"${sm.confirmStatus}\" is not in statuses array`)\n }\n if (!sm.statuses.includes(sm.cancelStatus)) {\n throw new Error(`statusMachine.cancelStatus \"${sm.cancelStatus}\" is not in statuses array`)\n }\n}\n\nexport const DEFAULT_RESOURCE_TYPES = ['staff', 'equipment', 'room']\nexport const DEFAULT_LEAVE_TYPES = ['vacation', 'sick', 'personal', 'closure', 'other']\n\nfunction resolveStaffProvisioning(\n pluginOptions: ReservationPluginConfig,\n resourceTypes: string[],\n): ResolvedStaffProvisioningConfig | undefined {\n const sp = pluginOptions.staffProvisioning\n if (!sp) {\n return undefined\n }\n\n if (!pluginOptions.resourceOwnerMode) {\n throw new Error('staffProvisioning requires resourceOwnerMode to be enabled')\n }\n if (sp.staffRoles.length === 0) {\n throw new Error('staffProvisioning.staffRoles must be a non-empty array')\n }\n const resourceType = sp.resourceType ?? 'staff'\n if (!resourceTypes.includes(resourceType)) {\n throw new Error(\n `staffProvisioning.resourceType \"${resourceType}\" is not in resourceTypes [${resourceTypes.join(', ')}]`,\n )\n }\n const userCollection = sp.userCollection ?? pluginOptions.userCollection\n if (!userCollection) {\n throw new Error(\n 'staffProvisioning.userCollection is required when top-level userCollection is unset',\n )\n }\n\n return {\n beforeCreate: sp.beforeCreate,\n nameFrom: sp.nameFrom ?? 'name',\n resourceType,\n roleField: sp.roleField ?? 'role',\n staffRoles: sp.staffRoles,\n userCollection,\n }\n}\n\nexport const DEFAULT_SLUGS = {\n customers: 'customers',\n media: 'media',\n reservations: 'reservations',\n resources: 'resources',\n schedules: 'schedules',\n services: 'services',\n} as const\n\nexport const DEFAULT_ADMIN_GROUP = 'Reservations'\nexport const DEFAULT_ALLOW_GUEST_BOOKING = false\nexport const DEFAULT_BUFFER_TIME = 0\nexport const DEFAULT_CANCELLATION_NOTICE_PERIOD = 24\n\nexport function resolveConfig(\n pluginOptions: ReservationPluginConfig,\n): ResolvedReservationPluginConfig {\n // A disabled plugin still resolves (so collections register with the right\n // slugs for schema stability) but skips all config validation — temporarily\n // disabling a misconfigured plugin should not throw at boot (review C3).\n const disabled = pluginOptions.disabled ?? false\n\n if (!disabled) {\n if (pluginOptions.resourceTypes !== undefined && pluginOptions.resourceTypes.length === 0) {\n throw new Error('resourceTypes must be a non-empty array')\n }\n if (pluginOptions.leaveTypes !== undefined && pluginOptions.leaveTypes.length === 0) {\n throw new Error('leaveTypes must be a non-empty array')\n }\n }\n\n const resourceTypes = pluginOptions.resourceTypes ?? DEFAULT_RESOURCE_TYPES\n const userStatusMachine = pluginOptions.statusMachine\n const rom = pluginOptions.resourceOwnerMode\n const resolved: ResolvedReservationPluginConfig = {\n access: pluginOptions.access ?? {},\n adminGroup: pluginOptions.adminGroup ?? DEFAULT_ADMIN_GROUP,\n allowGuestBooking: pluginOptions.allowGuestBooking ?? DEFAULT_ALLOW_GUEST_BOOKING,\n cancellationNoticePeriod:\n pluginOptions.cancellationNoticePeriod ?? DEFAULT_CANCELLATION_NOTICE_PERIOD,\n collectionOverrides: pluginOptions.collectionOverrides ?? {},\n defaultBufferTime: pluginOptions.defaultBufferTime ?? DEFAULT_BUFFER_TIME,\n disabled: pluginOptions.disabled ?? false,\n extraReservationFields: pluginOptions.extraReservationFields ?? [],\n getExternalBusy: pluginOptions.getExternalBusy,\n // Real value is set by the plugin once config.collections is known (C8)\n hasMediaCollection: false,\n hooks: pluginOptions.hooks ?? {},\n leaveTypes: pluginOptions.leaveTypes ?? DEFAULT_LEAVE_TYPES,\n localized: false,\n multiTenant: {\n cookieName: pluginOptions.multiTenant?.cookieName ?? 'payload-tenant',\n tenantField: pluginOptions.multiTenant?.tenantField ?? 'tenant',\n timezoneField: pluginOptions.multiTenant?.timezoneField ?? 'timezone',\n },\n resourceOwnerMode: rom\n ? {\n adminRoles: rom.adminRoles ?? [],\n ownedServices: rom.ownedServices ?? false,\n ownerCollection: rom.ownerCollection,\n ownerField: rom.ownerField ?? 'owner',\n roleField: rom.roleField ?? pluginOptions.staffProvisioning?.roleField ?? 'role',\n }\n : undefined,\n resourceTypes,\n slugs: {\n customers: pluginOptions.slugs?.customers ?? DEFAULT_SLUGS.customers,\n media: pluginOptions.slugs?.media ?? DEFAULT_SLUGS.media,\n reservations: pluginOptions.slugs?.reservations ?? DEFAULT_SLUGS.reservations,\n resources: pluginOptions.slugs?.resources ?? DEFAULT_SLUGS.resources,\n schedules: pluginOptions.slugs?.schedules ?? DEFAULT_SLUGS.schedules,\n services: pluginOptions.slugs?.services ?? DEFAULT_SLUGS.services,\n },\n staffProvisioning: disabled\n ? undefined\n : resolveStaffProvisioning(pluginOptions, resourceTypes),\n statusMachine: userStatusMachine\n ? {\n blockingStatuses:\n userStatusMachine.blockingStatuses ?? DEFAULT_STATUS_MACHINE.blockingStatuses,\n cancelStatus: userStatusMachine.cancelStatus ?? DEFAULT_STATUS_MACHINE.cancelStatus,\n confirmStatus: userStatusMachine.confirmStatus ?? DEFAULT_STATUS_MACHINE.confirmStatus,\n defaultStatus: userStatusMachine.defaultStatus ?? DEFAULT_STATUS_MACHINE.defaultStatus,\n statuses: userStatusMachine.statuses ?? DEFAULT_STATUS_MACHINE.statuses,\n terminalStatuses:\n userStatusMachine.terminalStatuses ?? DEFAULT_STATUS_MACHINE.terminalStatuses,\n transitions: userStatusMachine.transitions ?? DEFAULT_STATUS_MACHINE.transitions,\n }\n : { ...DEFAULT_STATUS_MACHINE },\n timezone: pluginOptions.timezone ?? 'UTC',\n userCollection: pluginOptions.userCollection ?? undefined,\n }\n\n if (!disabled) {\n validateStatusMachine(resolved.statusMachine)\n validateTimezone(resolved.timezone)\n }\n\n return resolved\n}\n"],"names":["DEFAULT_STATUS_MACHINE","validateTimezone","validateStatusMachine","sm","statuses","includes","defaultStatus","Error","s","blockingStatuses","terminalStatuses","from","targets","Object","entries","transitions","to","length","confirmStatus","cancelStatus","DEFAULT_RESOURCE_TYPES","DEFAULT_LEAVE_TYPES","resolveStaffProvisioning","pluginOptions","resourceTypes","sp","staffProvisioning","undefined","resourceOwnerMode","staffRoles","resourceType","join","userCollection","beforeCreate","nameFrom","roleField","DEFAULT_SLUGS","customers","media","reservations","resources","schedules","services","DEFAULT_ADMIN_GROUP","DEFAULT_ALLOW_GUEST_BOOKING","DEFAULT_BUFFER_TIME","DEFAULT_CANCELLATION_NOTICE_PERIOD","resolveConfig","disabled","leaveTypes","userStatusMachine","statusMachine","rom","resolved","access","adminGroup","allowGuestBooking","cancellationNoticePeriod","collectionOverrides","defaultBufferTime","extraReservationFields","getExternalBusy","hasMediaCollection","hooks","localized","multiTenant","cookieName","tenantField","timezoneField","adminRoles","ownedServices","ownerCollection","ownerField","slugs","timezone"],"mappings":"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"}
@@ -88,6 +88,7 @@ export function createCheckAvailabilityEndpoint(config) {
88
88
  const slots = await getAvailableSlots({
89
89
  blockingStatuses: config.statusMachine.blockingStatuses,
90
90
  date: dayKey,
91
+ getExternalBusy: config.getExternalBusy,
91
92
  guestCount,
92
93
  payload: req.payload,
93
94
  req,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/endpoints/checkAvailability.ts"],"sourcesContent":["import type { Endpoint } from 'payload'\n\nimport type { ResolvedReservationPluginConfig } from '../types.js'\n\nimport { getAvailableSlots } from '../services/AvailabilityService.js'\nimport { extractId, mergeResourceIds } from '../utilities/resolveRequiredResources.js'\nimport { getDayKeyInTimezone, isValidDayKey } from '../utilities/timezoneUtils.js'\n\nexport function createCheckAvailabilityEndpoint(\n config: ResolvedReservationPluginConfig,\n): Endpoint {\n return {\n handler: async (req) => {\n const url = new URL(req.url!)\n const date = url.searchParams.get('date')\n const resource = url.searchParams.get('resource')\n const service = url.searchParams.get('service')\n\n if (!date || !resource || !service) {\n return Response.json(\n { message: 'Missing required query params: resource, date, service' },\n { status: 400 },\n )\n }\n\n // YYYY-MM-DD is taken as a business-TZ calendar day verbatim; any other\n // parseable date is re-keyed into the business timezone. Never\n // `new Date('YYYY-MM-DD')` — that pins the day to UTC midnight.\n let dayKey: string\n if (/^\\d{4}-\\d{2}-\\d{2}$/.test(date)) {\n if (!isValidDayKey(date)) {\n return Response.json(\n { error: 'Invalid date format. Expected YYYY-MM-DD' },\n { status: 400 },\n )\n }\n dayKey = date\n } else {\n const parsed = new Date(date)\n if (isNaN(parsed.getTime())) {\n return Response.json(\n { error: 'Invalid date format. Expected YYYY-MM-DD' },\n { status: 400 },\n )\n }\n dayKey = getDayKeyInTimezone(parsed, config.timezone)\n }\n\n const guestCountRaw = Number(url.searchParams.get('guestCount') ?? '1')\n if (!Number.isFinite(guestCountRaw)) {\n return Response.json({ error: 'Invalid guestCount' }, { status: 400 })\n }\n const guestCount = Math.max(Math.floor(guestCountRaw), 1)\n\n // Resolve required resource set: caller resource(s) ∪ service.requiredResources\n const explicit = url.searchParams.get('resources')\n const callerIds = explicit ? explicit.split(',').map((s) => s.trim()).filter(Boolean) : [resource]\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const svcDoc = await (req.payload.findByID as any)({\n id: service,\n collection: config.slugs.services,\n depth: 0,\n req,\n }).catch(() => null)\n if (!svcDoc) {\n return Response.json({ error: 'Service not found' }, { status: 404 })\n }\n\n // Validate the primary resource id up front — a malformed id in a query\n // surfaces as an adapter cast error (500) instead of a clean 404.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const resourceDoc = await (req.payload.findByID as any)({\n id: resource,\n collection: config.slugs.resources,\n depth: 0,\n req,\n }).catch(() => null)\n if (!resourceDoc) {\n return Response.json({ error: 'Resource not found' }, { status: 404 })\n }\n const requiredIds = ((svcDoc?.requiredResources as unknown[]) ?? [])\n .map((r) => extractId(r))\n .filter((r): r is number | string => r !== undefined)\n const resourceIds = mergeResourceIds(callerIds, requiredIds)\n\n const slots = await getAvailableSlots({\n blockingStatuses: config.statusMachine.blockingStatuses,\n date: dayKey,\n guestCount,\n payload: req.payload,\n req,\n reservationSlug: config.slugs.reservations,\n resourceIds,\n resourceSlug: config.slugs.resources,\n scheduleSlug: config.slugs.schedules,\n serviceId: service,\n serviceSlug: config.slugs.services,\n timeZone: config.timezone,\n })\n\n return Response.json({ slots })\n },\n method: 'get',\n path: '/reserve/availability',\n }\n}\n"],"names":["getAvailableSlots","extractId","mergeResourceIds","getDayKeyInTimezone","isValidDayKey","createCheckAvailabilityEndpoint","config","handler","req","url","URL","date","searchParams","get","resource","service","Response","json","message","status","dayKey","test","error","parsed","Date","isNaN","getTime","timezone","guestCountRaw","Number","isFinite","guestCount","Math","max","floor","explicit","callerIds","split","map","s","trim","filter","Boolean","svcDoc","payload","findByID","id","collection","slugs","services","depth","catch","resourceDoc","resources","requiredIds","requiredResources","r","undefined","resourceIds","slots","blockingStatuses","statusMachine","reservationSlug","reservations","resourceSlug","scheduleSlug","schedules","serviceId","serviceSlug","timeZone","method","path"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/endpoints/checkAvailability.ts"],"sourcesContent":["import type { Endpoint } from 'payload'\n\nimport type { ResolvedReservationPluginConfig } from '../types.js'\n\nimport { getAvailableSlots } from '../services/AvailabilityService.js'\nimport { extractId, mergeResourceIds } from '../utilities/resolveRequiredResources.js'\nimport { getDayKeyInTimezone, isValidDayKey } from '../utilities/timezoneUtils.js'\n\nexport function createCheckAvailabilityEndpoint(\n config: ResolvedReservationPluginConfig,\n): Endpoint {\n return {\n handler: async (req) => {\n const url = new URL(req.url!)\n const date = url.searchParams.get('date')\n const resource = url.searchParams.get('resource')\n const service = url.searchParams.get('service')\n\n if (!date || !resource || !service) {\n return Response.json(\n { message: 'Missing required query params: resource, date, service' },\n { status: 400 },\n )\n }\n\n // YYYY-MM-DD is taken as a business-TZ calendar day verbatim; any other\n // parseable date is re-keyed into the business timezone. Never\n // `new Date('YYYY-MM-DD')` — that pins the day to UTC midnight.\n let dayKey: string\n if (/^\\d{4}-\\d{2}-\\d{2}$/.test(date)) {\n if (!isValidDayKey(date)) {\n return Response.json(\n { error: 'Invalid date format. Expected YYYY-MM-DD' },\n { status: 400 },\n )\n }\n dayKey = date\n } else {\n const parsed = new Date(date)\n if (isNaN(parsed.getTime())) {\n return Response.json(\n { error: 'Invalid date format. Expected YYYY-MM-DD' },\n { status: 400 },\n )\n }\n dayKey = getDayKeyInTimezone(parsed, config.timezone)\n }\n\n const guestCountRaw = Number(url.searchParams.get('guestCount') ?? '1')\n if (!Number.isFinite(guestCountRaw)) {\n return Response.json({ error: 'Invalid guestCount' }, { status: 400 })\n }\n const guestCount = Math.max(Math.floor(guestCountRaw), 1)\n\n // Resolve required resource set: caller resource(s) ∪ service.requiredResources\n const explicit = url.searchParams.get('resources')\n const callerIds = explicit ? explicit.split(',').map((s) => s.trim()).filter(Boolean) : [resource]\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const svcDoc = await (req.payload.findByID as any)({\n id: service,\n collection: config.slugs.services,\n depth: 0,\n req,\n }).catch(() => null)\n if (!svcDoc) {\n return Response.json({ error: 'Service not found' }, { status: 404 })\n }\n\n // Validate the primary resource id up front — a malformed id in a query\n // surfaces as an adapter cast error (500) instead of a clean 404.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const resourceDoc = await (req.payload.findByID as any)({\n id: resource,\n collection: config.slugs.resources,\n depth: 0,\n req,\n }).catch(() => null)\n if (!resourceDoc) {\n return Response.json({ error: 'Resource not found' }, { status: 404 })\n }\n const requiredIds = ((svcDoc?.requiredResources as unknown[]) ?? [])\n .map((r) => extractId(r))\n .filter((r): r is number | string => r !== undefined)\n const resourceIds = mergeResourceIds(callerIds, requiredIds)\n\n const slots = await getAvailableSlots({\n blockingStatuses: config.statusMachine.blockingStatuses,\n date: dayKey,\n getExternalBusy: config.getExternalBusy,\n guestCount,\n payload: req.payload,\n req,\n reservationSlug: config.slugs.reservations,\n resourceIds,\n resourceSlug: config.slugs.resources,\n scheduleSlug: config.slugs.schedules,\n serviceId: service,\n serviceSlug: config.slugs.services,\n timeZone: config.timezone,\n })\n\n return Response.json({ slots })\n },\n method: 'get',\n path: '/reserve/availability',\n }\n}\n"],"names":["getAvailableSlots","extractId","mergeResourceIds","getDayKeyInTimezone","isValidDayKey","createCheckAvailabilityEndpoint","config","handler","req","url","URL","date","searchParams","get","resource","service","Response","json","message","status","dayKey","test","error","parsed","Date","isNaN","getTime","timezone","guestCountRaw","Number","isFinite","guestCount","Math","max","floor","explicit","callerIds","split","map","s","trim","filter","Boolean","svcDoc","payload","findByID","id","collection","slugs","services","depth","catch","resourceDoc","resources","requiredIds","requiredResources","r","undefined","resourceIds","slots","blockingStatuses","statusMachine","getExternalBusy","reservationSlug","reservations","resourceSlug","scheduleSlug","schedules","serviceId","serviceSlug","timeZone","method","path"],"mappings":"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"}