@fayz-ai/plugin-reservations 0.1.1

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 (44) hide show
  1. package/LICENSE +21 -0
  2. package/dist/ReservationsPage-5RF5SYZT.js +1157 -0
  3. package/dist/ReservationsPage-5RF5SYZT.js.map +1 -0
  4. package/dist/chunk-7KXGSUHT.js +335 -0
  5. package/dist/chunk-7KXGSUHT.js.map +1 -0
  6. package/dist/components/CapacityStrip.d.ts +25 -0
  7. package/dist/components/CapacityStrip.d.ts.map +1 -0
  8. package/dist/components/ReservationModal.d.ts +23 -0
  9. package/dist/components/ReservationModal.d.ts.map +1 -0
  10. package/dist/components/SeatDialog.d.ts +16 -0
  11. package/dist/components/SeatDialog.d.ts.map +1 -0
  12. package/dist/context.d.ts +49 -0
  13. package/dist/context.d.ts.map +1 -0
  14. package/dist/data/core-supabase.d.ts +32 -0
  15. package/dist/data/core-supabase.d.ts.map +1 -0
  16. package/dist/data/mock.d.ts +3 -0
  17. package/dist/data/mock.d.ts.map +1 -0
  18. package/dist/data/types.d.ts +37 -0
  19. package/dist/data/types.d.ts.map +1 -0
  20. package/dist/index.d.ts +43 -0
  21. package/dist/index.d.ts.map +1 -0
  22. package/dist/index.js +870 -0
  23. package/dist/index.js.map +1 -0
  24. package/dist/locales/en.d.ts +2 -0
  25. package/dist/locales/en.d.ts.map +1 -0
  26. package/dist/locales/index.d.ts +2 -0
  27. package/dist/locales/index.d.ts.map +1 -0
  28. package/dist/locales/pt-BR.d.ts +2 -0
  29. package/dist/locales/pt-BR.d.ts.map +1 -0
  30. package/dist/migrations/index.d.ts +6 -0
  31. package/dist/migrations/index.d.ts.map +1 -0
  32. package/dist/store.d.ts +48 -0
  33. package/dist/store.d.ts.map +1 -0
  34. package/dist/types.d.ts +174 -0
  35. package/dist/types.d.ts.map +1 -0
  36. package/dist/views/CapacitySettingsView.d.ts +3 -0
  37. package/dist/views/CapacitySettingsView.d.ts.map +1 -0
  38. package/dist/views/ReservationsListView.d.ts +5 -0
  39. package/dist/views/ReservationsListView.d.ts.map +1 -0
  40. package/dist/views/ReservationsPage.d.ts +27 -0
  41. package/dist/views/ReservationsPage.d.ts.map +1 -0
  42. package/dist/views/ServiceDayView.d.ts +15 -0
  43. package/dist/views/ServiceDayView.d.ts.map +1 -0
  44. package/package.json +62 -0
@@ -0,0 +1,1157 @@
1
+ import { DEFAULT_SETTINGS } from './chunk-7KXGSUHT.js';
2
+ import React2, { useState, useEffect, useMemo, useCallback } from 'react';
3
+ import { CalendarClock, List, Plus, AlertTriangle, CalendarOff, Users, Phone, Check, Armchair, X, Pencil, Trash2 } from 'lucide-react';
4
+ import { PageTabs, TooltipProvider, PageHeaderActions, Button, MiniCalendar, toLocalISODate, FilterCheckList, StatTiles, Skeleton, SearchField, Input, DotBadge, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, formatPhone, Modal, ModalContent, ModalHeader, ModalTitle, ModalBody, TimePicker, ModalFooter, Switch, Tooltip, TooltipTrigger, TooltipContent } from '@fayz-ai/ui';
5
+ import { createPluginContext, PermissionGate, createArchetypeLookup, ContactPicker } from '@fayz-ai/admin';
6
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
+
8
+ var ctx = createPluginContext("ReservationsPage");
9
+ var ReservationsContextProvider = ctx.ContextProvider;
10
+ var useReservationsConfig = ctx.useConfig;
11
+ ctx.useProvider;
12
+ var useReservationsStore = ctx.useStore;
13
+ function CapacityStrip({ slots, loading, error, onPickSlot }) {
14
+ if (loading) {
15
+ return /* @__PURE__ */ jsx("div", { className: "grid gap-2 sm:grid-cols-2", children: [0, 1].map((i) => /* @__PURE__ */ jsx(Skeleton, { className: "h-[72px] w-full rounded-lg" }, i)) });
16
+ }
17
+ if (error) {
18
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3 rounded-lg border border-destructive/30 bg-destructive/5 p-4", children: [
19
+ /* @__PURE__ */ jsx(AlertTriangle, { className: "mt-0.5 h-4 w-4 shrink-0 text-destructive" }),
20
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
21
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-destructive", children: "N\xE3o foi poss\xEDvel ler a grade de capacidade" }),
22
+ /* @__PURE__ */ jsx("p", { className: "mt-0.5 break-words text-xs text-muted-foreground", children: error })
23
+ ] })
24
+ ] });
25
+ }
26
+ if (!slots.length) {
27
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 rounded-lg border border-dashed p-4", children: [
28
+ /* @__PURE__ */ jsx(CalendarOff, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
29
+ /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground", children: [
30
+ "Nenhuma faixa aberta neste dia. A grade semanal e as exce\xE7\xF5es ficam em",
31
+ " ",
32
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-foreground", children: "Configura\xE7\xF5es \u2192 Reservas" }),
33
+ "."
34
+ ] })
35
+ ] });
36
+ }
37
+ return /* @__PURE__ */ jsx("div", { className: "grid gap-2 sm:grid-cols-2", children: slots.map((slot, i) => {
38
+ const pct = slot.capacity > 0 ? Math.min(slot.booked / slot.capacity * 100, 100) : 0;
39
+ const full = slot.remaining === 0;
40
+ const tone = full ? "bg-destructive" : pct >= 80 ? "bg-accent" : "bg-primary";
41
+ const Row = onPickSlot ? "button" : "div";
42
+ return /* @__PURE__ */ jsxs(
43
+ Row,
44
+ {
45
+ ...onPickSlot ? { onClick: () => onPickSlot(slot), type: "button" } : {},
46
+ className: `rounded-lg border bg-card p-3 text-left transition-colors ${onPickSlot ? "hover:bg-muted/50" : ""}`,
47
+ children: [
48
+ /* @__PURE__ */ jsxs("div", { className: "flex items-baseline justify-between gap-2", children: [
49
+ /* @__PURE__ */ jsxs("span", { className: "text-sm font-medium tabular-nums", children: [
50
+ slot.startTime,
51
+ " \u2013 ",
52
+ slot.endTime
53
+ ] }),
54
+ /* @__PURE__ */ jsxs("span", { className: `text-sm tabular-nums ${full ? "font-semibold text-destructive" : "text-muted-foreground"}`, children: [
55
+ slot.booked,
56
+ "/",
57
+ slot.capacity
58
+ ] })
59
+ ] }),
60
+ /* @__PURE__ */ jsxs("div", { className: "mt-1.5 flex items-center gap-2", children: [
61
+ slot.zoneColor && /* @__PURE__ */ jsx("span", { className: "h-2 w-2 shrink-0 rounded-full", style: { backgroundColor: slot.zoneColor } }),
62
+ /* @__PURE__ */ jsx("span", { className: "truncate text-xs text-muted-foreground", children: slot.zoneName ?? "Restaurante" }),
63
+ slot.isException && /* @__PURE__ */ jsx("span", { className: "shrink-0 rounded-full bg-accent/15 px-1.5 py-px text-[10px] font-medium text-accent", children: "exce\xE7\xE3o" })
64
+ ] }),
65
+ /* @__PURE__ */ jsx("div", { className: "mt-2 h-1.5 w-full overflow-hidden rounded-full bg-muted", children: /* @__PURE__ */ jsx("div", { className: `h-full rounded-full transition-all ${tone}`, style: { width: `${pct}%` } }) }),
66
+ /* @__PURE__ */ jsx("p", { className: "mt-1.5 text-xs text-muted-foreground", children: full ? "Lota\xE7\xE3o cheia" : `${slot.remaining} ${slot.remaining === 1 ? "lugar" : "lugares"} livres` })
67
+ ]
68
+ },
69
+ `${slot.zoneId ?? "all"}-${slot.startTime}-${i}`
70
+ );
71
+ }) });
72
+ }
73
+ function requireContactFields(def, phone, email) {
74
+ if (!def || !phone && !email) return def;
75
+ return {
76
+ ...def,
77
+ fields: def.fields.map((f) => f.key === "phone" && phone || f.key === "email" && email ? { ...f, required: true } : f)
78
+ };
79
+ }
80
+ function ReservationModal({ open, onClose, date, reservation, defaultSlot }) {
81
+ const config = useReservationsConfig();
82
+ const zones = useReservationsStore((s) => s.zones);
83
+ const tables = useReservationsStore((s) => s.tables);
84
+ const slots = useReservationsStore((s) => s.slots);
85
+ const settings = useReservationsStore((s) => s.settings);
86
+ const create = useReservationsStore((s) => s.create);
87
+ const update = useReservationsStore((s) => s.update);
88
+ const [form, setForm] = useState(() => blank(date, defaultSlot));
89
+ const [saving, setSaving] = useState(false);
90
+ const [personPhone, setPersonPhone] = useState(void 0);
91
+ const requirePhone = !!settings?.requirePhone;
92
+ const requireEmail = !!settings?.requireEmail;
93
+ const baseLookup = useMemo(
94
+ () => config.contactLookup ?? createArchetypeLookup({ archetype: "person", kind: config.clientKind }),
95
+ [config.contactLookup, config.clientKind]
96
+ );
97
+ const clientLookup = useMemo(() => {
98
+ const def = requireContactFields(baseLookup.entityDef, requirePhone, requireEmail);
99
+ return def === baseLookup.entityDef ? baseLookup : { ...baseLookup, entityDef: def };
100
+ }, [baseLookup, requirePhone, requireEmail]);
101
+ const clientEntityDef = useMemo(
102
+ () => requireContactFields(config.clientEntityDef, requirePhone, requireEmail),
103
+ [config.clientEntityDef, requirePhone, requireEmail]
104
+ );
105
+ useEffect(() => {
106
+ if (!open) return;
107
+ setForm(reservation ? {
108
+ personId: reservation.personId,
109
+ guestName: reservation.guestName,
110
+ phone: reservation.phone,
111
+ email: reservation.email,
112
+ zoneId: reservation.zoneId,
113
+ tableId: reservation.tableId,
114
+ reservedOn: reservation.reservedOn,
115
+ startTime: reservation.startTime,
116
+ endTime: reservation.endTime,
117
+ partySize: reservation.partySize,
118
+ occasion: reservation.occasion,
119
+ notes: reservation.notes,
120
+ status: reservation.status
121
+ } : blank(date, defaultSlot));
122
+ setPersonPhone(reservation?.phone || void 0);
123
+ }, [open, reservation, date, defaultSlot]);
124
+ const slot = useMemo(() => {
125
+ const candidates = slots.filter((s) => (!s.zoneId || !form.zoneId || s.zoneId === form.zoneId) && form.startTime >= s.startTime && form.startTime < s.endTime);
126
+ return candidates[0] ?? null;
127
+ }, [slots, form.startTime, form.zoneId]);
128
+ useEffect(() => {
129
+ if (!open || form.zoneId) return;
130
+ const covering = slots.filter((s) => s.zoneId && form.startTime >= s.startTime && form.startTime < s.endTime);
131
+ const unique = new Set(covering.map((s) => s.zoneId));
132
+ if (unique.size === 1) setForm((f) => f.zoneId ? f : { ...f, zoneId: covering[0].zoneId });
133
+ }, [open, slots, form.startTime, form.zoneId]);
134
+ const zonedWindows = slots.filter((s) => s.zoneId && form.startTime >= s.startTime && form.startTime < s.endTime);
135
+ const unzonedInAZonedHouse = !form.zoneId && zonedWindows.length > 0;
136
+ const remainingAfter = useMemo(() => {
137
+ if (!slot) return null;
138
+ const own = reservation && reservation.startTime >= slot.startTime && reservation.startTime < slot.endTime ? reservation.partySize : 0;
139
+ return slot.capacity - (slot.booked - own) - (form.partySize || 0);
140
+ }, [slot, form.partySize, reservation]);
141
+ const zoneTables = tables.filter((t) => !form.zoneId || t.zoneId === form.zoneId);
142
+ const missing = [];
143
+ if (!form.personId) missing.push("o cliente que reservou");
144
+ if (requirePhone && !form.phone?.trim()) missing.push("o telefone do cliente");
145
+ if (requireEmail && !form.email?.trim()) missing.push("o e-mail do cliente");
146
+ if (!form.partySize || form.partySize < 1) missing.push("quantas pessoas");
147
+ if (unzonedInAZonedHouse) missing.push("a pra\xE7a \u2014 sem ela a reserva n\xE3o entra em nenhuma lota\xE7\xE3o");
148
+ async function submit() {
149
+ if (missing.length) return;
150
+ setSaving(true);
151
+ try {
152
+ if (reservation) await update(reservation.id, form);
153
+ else await create(form);
154
+ onClose();
155
+ } finally {
156
+ setSaving(false);
157
+ }
158
+ }
159
+ return /* @__PURE__ */ jsx(Modal, { open, onOpenChange: (v) => !v && onClose(), children: /* @__PURE__ */ jsxs(ModalContent, { size: "lg", children: [
160
+ /* @__PURE__ */ jsx(ModalHeader, { children: /* @__PURE__ */ jsx(ModalTitle, { children: reservation ? "Editar reserva" : config.labels.newReservation }) }),
161
+ /* @__PURE__ */ jsx(ModalBody, { children: /* @__PURE__ */ jsxs("div", { className: "fz-container space-y-4", children: [
162
+ /* @__PURE__ */ jsx(
163
+ ContactPicker,
164
+ {
165
+ value: form.personId || form.guestName ? { id: form.personId, name: form.guestName, phone: form.phone, email: form.email } : null,
166
+ onChange: (c) => {
167
+ setPersonPhone(c?.phone || void 0);
168
+ setForm({
169
+ ...form,
170
+ personId: c?.id,
171
+ guestName: c?.name ?? "",
172
+ phone: c?.phone ?? "",
173
+ email: c?.email ?? ""
174
+ });
175
+ },
176
+ kind: config.clientKind,
177
+ lookup: clientLookup,
178
+ createEntityDef: clientEntityDef,
179
+ label: "Cliente *",
180
+ placeholder: "Quem reservou",
181
+ createLabel: "Cadastrar cliente",
182
+ autoFocus: true,
183
+ required: true,
184
+ ...form.personId ? {
185
+ handleField: {
186
+ label: "telefone",
187
+ fieldLabel: "Telefone",
188
+ placeholder: "(00) 00000-0000",
189
+ derived: personPhone,
190
+ value: form.phone ?? "",
191
+ onChange: (v) => setForm({ ...form, phone: v })
192
+ }
193
+ } : {}
194
+ }
195
+ ),
196
+ reservation && !form.personId && form.guestName && /* @__PURE__ */ jsxs("p", { className: "text-xs text-amber-600 dark:text-amber-500", children: [
197
+ "Em nome de ",
198
+ /* @__PURE__ */ jsx("strong", { children: form.guestName }),
199
+ ", sem cliente vinculado. Busque a pessoa acima para ligar as duas \u2014 ou cadastre-a."
200
+ ] }),
201
+ /* @__PURE__ */ jsxs("div", { className: "fz-fields fz-fields-2", children: [
202
+ /* @__PURE__ */ jsx(Field, { label: "Data *", children: /* @__PURE__ */ jsx(
203
+ Input,
204
+ {
205
+ type: "date",
206
+ value: form.reservedOn,
207
+ onChange: (e) => setForm({ ...form, reservedOn: e.target.value })
208
+ }
209
+ ) }),
210
+ /* @__PURE__ */ jsx(Field, { label: "Pessoas *", children: /* @__PURE__ */ jsx(
211
+ Input,
212
+ {
213
+ type: "number",
214
+ min: 1,
215
+ value: form.partySize,
216
+ onChange: (e) => setForm({ ...form, partySize: Number(e.target.value) })
217
+ }
218
+ ) })
219
+ ] }),
220
+ /* @__PURE__ */ jsxs("div", { className: "fz-fields fz-fields-2", children: [
221
+ /* @__PURE__ */ jsx(Field, { label: "Hora in\xEDcio *", children: /* @__PURE__ */ jsx(
222
+ TimePicker,
223
+ {
224
+ value: form.startTime,
225
+ onChange: (v) => setForm({ ...form, startTime: v })
226
+ }
227
+ ) }),
228
+ /* @__PURE__ */ jsx(Field, { label: "Hora fim", children: /* @__PURE__ */ jsx(
229
+ TimePicker,
230
+ {
231
+ value: form.endTime ?? "",
232
+ onChange: (v) => setForm({ ...form, endTime: v })
233
+ }
234
+ ) })
235
+ ] }),
236
+ /* @__PURE__ */ jsx(SlotHint, { slot, remainingAfter, party: form.partySize }),
237
+ /* @__PURE__ */ jsxs("div", { className: "fz-fields fz-fields-2", children: [
238
+ /* @__PURE__ */ jsx(Field, { label: "Pra\xE7a", children: /* @__PURE__ */ jsxs(
239
+ Select,
240
+ {
241
+ value: form.zoneId ?? "__none",
242
+ onValueChange: (v) => setForm({ ...form, zoneId: v === "__none" ? void 0 : v, tableId: void 0 }),
243
+ children: [
244
+ /* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Restaurante todo" }) }),
245
+ /* @__PURE__ */ jsxs(SelectContent, { children: [
246
+ /* @__PURE__ */ jsx(SelectItem, { value: "__none", children: "Restaurante todo" }),
247
+ zones.map((z) => /* @__PURE__ */ jsx(SelectItem, { value: z.id, children: z.name }, z.id))
248
+ ] })
249
+ ]
250
+ }
251
+ ) }),
252
+ /* @__PURE__ */ jsx(Field, { label: "Mesa (opcional)", children: /* @__PURE__ */ jsxs(
253
+ Select,
254
+ {
255
+ value: form.tableId ?? "__none",
256
+ onValueChange: (v) => setForm({ ...form, tableId: v === "__none" ? void 0 : v }),
257
+ children: [
258
+ /* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "\u2014 Nenhuma \u2014" }) }),
259
+ /* @__PURE__ */ jsxs(SelectContent, { children: [
260
+ /* @__PURE__ */ jsx(SelectItem, { value: "__none", children: "\u2014 Nenhuma \u2014" }),
261
+ zoneTables.map((t) => /* @__PURE__ */ jsxs(SelectItem, { value: t.id, children: [
262
+ "Mesa ",
263
+ t.number,
264
+ " \xB7 ",
265
+ t.seats,
266
+ " lug."
267
+ ] }, t.id))
268
+ ] })
269
+ ]
270
+ }
271
+ ) })
272
+ ] }),
273
+ /* @__PURE__ */ jsx(Field, { label: "Ocasi\xE3o", children: /* @__PURE__ */ jsxs(
274
+ Select,
275
+ {
276
+ value: form.occasion ?? "__none",
277
+ onValueChange: (v) => setForm({ ...form, occasion: v === "__none" ? void 0 : v }),
278
+ children: [
279
+ /* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "\u2014" }) }),
280
+ /* @__PURE__ */ jsxs(SelectContent, { children: [
281
+ /* @__PURE__ */ jsx(SelectItem, { value: "__none", children: "\u2014" }),
282
+ config.occasions.map((o) => /* @__PURE__ */ jsx(SelectItem, { value: o.value, children: o.label }, o.value))
283
+ ] })
284
+ ]
285
+ }
286
+ ) }),
287
+ /* @__PURE__ */ jsx(Field, { label: "Observa\xE7\xF5es", children: /* @__PURE__ */ jsx(
288
+ Input,
289
+ {
290
+ value: form.notes ?? "",
291
+ onChange: (e) => setForm({ ...form, notes: e.target.value }),
292
+ placeholder: "Cadeirinha de beb\xEA, anivers\xE1rio surpresa\u2026"
293
+ }
294
+ ) })
295
+ ] }) }),
296
+ /* @__PURE__ */ jsx(ModalFooter, { children: /* @__PURE__ */ jsxs("div", { className: "flex w-full items-center justify-between gap-3", children: [
297
+ /* @__PURE__ */ jsx("p", { className: "min-w-0 text-xs text-muted-foreground", children: missing.length ? `Falta ${missing.join(", ")}.` : "" }),
298
+ /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 gap-2", children: [
299
+ /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: onClose, children: "Cancelar" }),
300
+ /* @__PURE__ */ jsx(Button, { onClick: submit, disabled: !!missing.length || saving, children: saving ? "Salvando\u2026" : "Salvar" })
301
+ ] })
302
+ ] }) })
303
+ ] }) });
304
+ }
305
+ function Field({ label, children }) {
306
+ return /* @__PURE__ */ jsxs("label", { className: "block space-y-1.5", children: [
307
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: label }),
308
+ children
309
+ ] });
310
+ }
311
+ function SlotHint({ slot, remainingAfter, party }) {
312
+ if (!slot) {
313
+ return /* @__PURE__ */ jsx("p", { className: "rounded-lg bg-muted/50 px-3 py-2 text-xs text-muted-foreground", children: "Nenhuma faixa de capacidade cobre este hor\xE1rio. A reserva pode ser registrada assim mesmo \u2014 s\xF3 n\xE3o h\xE1 teto configurado para ela." });
314
+ }
315
+ const over = remainingAfter != null && remainingAfter < 0;
316
+ return /* @__PURE__ */ jsxs("p", { className: `rounded-lg px-3 py-2 text-xs ${over ? "bg-destructive/10 text-destructive" : "bg-muted/50 text-muted-foreground"}`, children: [
317
+ /* @__PURE__ */ jsxs("span", { className: "font-medium tabular-nums", children: [
318
+ slot.startTime,
319
+ "\u2013",
320
+ slot.endTime
321
+ ] }),
322
+ slot.zoneName ? ` \xB7 ${slot.zoneName}` : "",
323
+ " \xB7 ",
324
+ slot.booked,
325
+ "/",
326
+ slot.capacity,
327
+ " ocupados.",
328
+ " ",
329
+ over ? `Com ${party} pessoa(s) a faixa estoura em ${Math.abs(remainingAfter)}.` : `Sobram ${remainingAfter} depois desta reserva.`
330
+ ] });
331
+ }
332
+ function blank(date, slot) {
333
+ return {
334
+ guestName: "",
335
+ reservedOn: date,
336
+ // 20:00 is the V1's default and the right one: the reservation a
337
+ // restaurant takes over the phone is a dinner one.
338
+ startTime: slot?.startTime ?? "20:00",
339
+ zoneId: slot?.zoneId,
340
+ partySize: 2
341
+ };
342
+ }
343
+ function SeatDialog({ reservation, onClose }) {
344
+ const tables = useReservationsStore((s) => s.tables);
345
+ const seat = useReservationsStore((s) => s.seat);
346
+ const [tableId, setTableId] = useState(reservation?.tableId ?? null);
347
+ const [guests, setGuests] = useState(reservation?.partySize ?? 2);
348
+ const [saving, setSaving] = useState(false);
349
+ React2.useEffect(() => {
350
+ setTableId(reservation?.tableId ?? null);
351
+ setGuests(reservation?.partySize ?? 2);
352
+ }, [reservation]);
353
+ if (!reservation) return null;
354
+ const free = tables.filter((t) => !t.isOccupied);
355
+ const chosen = tables.find((t) => t.id === tableId);
356
+ const tooSmall = chosen ? chosen.seats < guests : false;
357
+ async function confirm() {
358
+ if (!tableId) return;
359
+ setSaving(true);
360
+ try {
361
+ await seat(reservation.id, tableId, guests);
362
+ onClose();
363
+ } finally {
364
+ setSaving(false);
365
+ }
366
+ }
367
+ return /* @__PURE__ */ jsx(Modal, { open: true, onOpenChange: (v) => !v && onClose(), children: /* @__PURE__ */ jsxs(ModalContent, { size: "md", children: [
368
+ /* @__PURE__ */ jsx(ModalHeader, { children: /* @__PURE__ */ jsxs(ModalTitle, { children: [
369
+ "Acomodar ",
370
+ reservation.guestName
371
+ ] }) }),
372
+ /* @__PURE__ */ jsx(ModalBody, { children: /* @__PURE__ */ jsxs("div", { className: "fz-container space-y-4", children: [
373
+ /* @__PURE__ */ jsxs("label", { className: "block space-y-1.5", children: [
374
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Quantas pessoas sentaram" }),
375
+ /* @__PURE__ */ jsx(Input, { type: "number", min: 1, value: guests, onChange: (e) => setGuests(Number(e.target.value)) }),
376
+ guests !== reservation.partySize && // The party that shows up is not always the party that booked,
377
+ // and the comanda has to open with the real number — the couvert
378
+ // and the split bill both hang off it.
379
+ /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
380
+ "A reserva era para ",
381
+ reservation.partySize,
382
+ ". A comanda abre com ",
383
+ guests,
384
+ "."
385
+ ] })
386
+ ] }),
387
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
388
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Mesa" }),
389
+ free.length === 0 ? /* @__PURE__ */ jsx("p", { className: "rounded-lg border border-dashed p-3 text-sm text-muted-foreground", children: "Nenhuma mesa livre. Uma mesa fica ocupada enquanto h\xE1 comanda aberta nela \u2014 feche uma comanda em Pedidos para liberar." }) : /* @__PURE__ */ jsx("div", { className: "grid max-h-64 grid-cols-3 gap-2 overflow-y-auto sm:grid-cols-4", children: free.map((t) => {
390
+ const selected = t.id === tableId;
391
+ const small = t.seats < guests;
392
+ return /* @__PURE__ */ jsxs(
393
+ "button",
394
+ {
395
+ type: "button",
396
+ onClick: () => setTableId(t.id),
397
+ className: `flex flex-col items-center rounded-lg border-2 p-2 transition-colors ${selected ? "border-primary bg-primary/10" : "border-border hover:bg-muted/50"}`,
398
+ children: [
399
+ /* @__PURE__ */ jsx("span", { className: "text-lg font-bold", children: t.number }),
400
+ /* @__PURE__ */ jsxs("span", { className: `flex items-center gap-0.5 text-[11px] ${small ? "text-accent" : "text-muted-foreground"}`, children: [
401
+ /* @__PURE__ */ jsx(Users, { className: "h-3 w-3" }),
402
+ t.seats
403
+ ] })
404
+ ]
405
+ },
406
+ t.id
407
+ );
408
+ }) })
409
+ ] }),
410
+ tooSmall && /* @__PURE__ */ jsxs("p", { className: "rounded-lg bg-accent/10 px-3 py-2 text-xs text-accent", children: [
411
+ "A mesa ",
412
+ chosen.number,
413
+ " tem ",
414
+ chosen.seats,
415
+ " lugares para ",
416
+ guests,
417
+ " pessoas."
418
+ ] })
419
+ ] }) }),
420
+ /* @__PURE__ */ jsx(ModalFooter, { children: /* @__PURE__ */ jsxs("div", { className: "flex w-full items-center justify-between gap-3", children: [
421
+ /* @__PURE__ */ jsx("p", { className: "min-w-0 text-xs text-muted-foreground", children: tableId ? "Abre a comanda desta mesa." : "Escolha a mesa para abrir a comanda." }),
422
+ /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 gap-2", children: [
423
+ /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: onClose, children: "Cancelar" }),
424
+ /* @__PURE__ */ jsx(Button, { onClick: confirm, disabled: !tableId || saving, children: saving ? "Abrindo\u2026" : "Acomodar e abrir comanda" })
425
+ ] })
426
+ ] }) })
427
+ ] }) });
428
+ }
429
+ function ServiceDayView() {
430
+ const config = useReservationsConfig();
431
+ const selectedDate = useReservationsStore((s) => s.selectedDate);
432
+ const setSelectedDate = useReservationsStore((s) => s.setSelectedDate);
433
+ const slots = useReservationsStore((s) => s.slots);
434
+ const slotsLoading = useReservationsStore((s) => s.slotsLoading);
435
+ const slotsError = useReservationsStore((s) => s.slotsError);
436
+ const dayReservations = useReservationsStore((s) => s.dayReservations);
437
+ const dayLoading = useReservationsStore((s) => s.dayLoading);
438
+ const summary = useReservationsStore((s) => s.summary);
439
+ const monthRows = useReservationsStore((s) => s.reservations);
440
+ const fetchDay = useReservationsStore((s) => s.fetchDay);
441
+ const fetchRange = useReservationsStore((s) => s.fetchRange);
442
+ const fetchSalao = useReservationsStore((s) => s.fetchSalao);
443
+ const setStatus = useReservationsStore((s) => s.setStatus);
444
+ const [statusFilter, setStatusFilter] = useState([]);
445
+ const [editing, setEditing] = useState(null);
446
+ const [creating, setCreating] = useState(false);
447
+ const [slotSeed, setSlotSeed] = useState(null);
448
+ const [seating, setSeating] = useState(null);
449
+ useEffect(() => {
450
+ void fetchDay();
451
+ void fetchSalao();
452
+ }, [fetchDay, fetchSalao]);
453
+ useEffect(() => {
454
+ const [y, m] = selectedDate.split("-").map(Number);
455
+ const from = `${y}-${String(m).padStart(2, "0")}-01`;
456
+ const last = new Date(y, m, 0).getDate();
457
+ void fetchRange(from, `${y}-${String(m).padStart(2, "0")}-${last}`);
458
+ }, [selectedDate, fetchRange]);
459
+ const colorOf = useMemo(() => {
460
+ const map = new Map(config.statuses.map((s) => [s.value, s]));
461
+ return (status) => map.get(status) ?? { label: status, color: "#6b7280" };
462
+ }, [config.statuses]);
463
+ const markers = useMemo(() => {
464
+ var _a;
465
+ const out = {};
466
+ for (const r of monthRows) {
467
+ if (r.status === "cancelled") continue;
468
+ const s = colorOf(r.status);
469
+ const day = out[_a = r.reservedOn] ?? (out[_a] = []);
470
+ if (!day.some((d) => d.color === s.color)) day.push({ color: s.color, label: s.label });
471
+ }
472
+ return out;
473
+ }, [monthRows, colorOf]);
474
+ const rows = statusFilter.length ? dayReservations.filter((r) => statusFilter.includes(r.status)) : dayReservations;
475
+ const dateObj = useMemo(() => {
476
+ const [y, m, d] = selectedDate.split("-").map(Number);
477
+ return new Date(y, m - 1, d);
478
+ }, [selectedDate]);
479
+ return /* @__PURE__ */ jsxs(TooltipProvider, { delayDuration: 300, children: [
480
+ /* @__PURE__ */ jsx(PageHeaderActions, { children: /* @__PURE__ */ jsx(PermissionGate, { feature: "reservations", action: "create", children: /* @__PURE__ */ jsxs(Button, { onClick: () => {
481
+ setSlotSeed(null);
482
+ setCreating(true);
483
+ }, children: [
484
+ /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" }),
485
+ /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: config.labels.newReservation })
486
+ ] }) }) }),
487
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 lg:flex-row", children: [
488
+ /* @__PURE__ */ jsxs("aside", { className: "w-full shrink-0 space-y-5 lg:w-60", children: [
489
+ /* @__PURE__ */ jsx(
490
+ MiniCalendar,
491
+ {
492
+ selectedDate: dateObj,
493
+ markers,
494
+ onDateSelect: (d) => setSelectedDate(toLocalISODate(d))
495
+ }
496
+ ),
497
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
498
+ /* @__PURE__ */ jsx(
499
+ FilterCheckList,
500
+ {
501
+ label: "Estado",
502
+ options: config.statuses.map((s) => ({
503
+ value: s.value,
504
+ label: s.label,
505
+ color: s.color,
506
+ count: dayReservations.filter((r) => r.status === s.value).length
507
+ })),
508
+ selected: statusFilter,
509
+ onChange: setStatusFilter
510
+ }
511
+ ),
512
+ statusFilter.length > 0 && /* @__PURE__ */ jsx("button", { onClick: () => setStatusFilter([]), className: "px-1 text-xs text-primary hover:underline", children: "Limpar filtro" })
513
+ ] })
514
+ ] }),
515
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1 space-y-5", children: [
516
+ /* @__PURE__ */ jsx(
517
+ StatTiles,
518
+ {
519
+ tiles: [
520
+ { id: "total", label: "Reservas", value: summary ? String(summary.total) : "\u2014" },
521
+ // Pessoas, não linhas: é o número contra o qual a cozinha se
522
+ // planeja, e cancelada/não-compareceu não comem.
523
+ { id: "guests", label: "Pessoas esperadas", value: summary ? String(summary.expectedGuests) : "\u2014" },
524
+ { id: "pending", label: "A confirmar", value: summary ? String(summary.pending) : "\u2014" },
525
+ { id: "seated", label: "J\xE1 sentaram", value: summary ? String(summary.seated) : "\u2014" }
526
+ ]
527
+ }
528
+ ),
529
+ /* @__PURE__ */ jsxs("section", { className: "space-y-2", children: [
530
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-medium", children: "Capacidade do dia" }),
531
+ /* @__PURE__ */ jsx(
532
+ CapacityStrip,
533
+ {
534
+ slots,
535
+ loading: slotsLoading,
536
+ error: slotsError,
537
+ onPickSlot: (slot) => {
538
+ setSlotSeed(slot);
539
+ setCreating(true);
540
+ }
541
+ }
542
+ )
543
+ ] }),
544
+ /* @__PURE__ */ jsxs("section", { className: "space-y-2", children: [
545
+ /* @__PURE__ */ jsxs("h3", { className: "text-sm font-medium", children: [
546
+ "Reservas do dia ",
547
+ rows.length ? /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
548
+ "(",
549
+ rows.length,
550
+ ")"
551
+ ] }) : null
552
+ ] }),
553
+ dayLoading ? (
554
+ // The SHAPE of the row, never "Carregando…".
555
+ /* @__PURE__ */ jsx("div", { className: "space-y-2", children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx(Skeleton, { className: "h-16 w-full rounded-lg" }, i)) })
556
+ ) : rows.length === 0 ? /* @__PURE__ */ jsx("p", { className: "rounded-lg border border-dashed p-6 text-center text-sm text-muted-foreground", children: dayReservations.length ? "Nenhuma reserva com esse estado neste dia." : "Nenhuma reserva para este dia." }) : /* @__PURE__ */ jsx("ul", { className: "space-y-2", children: rows.map((r) => /* @__PURE__ */ jsx(
557
+ ReservationRow,
558
+ {
559
+ reservation: r,
560
+ badge: colorOf(r.status),
561
+ onEdit: () => setEditing(r),
562
+ onSeat: () => setSeating(r),
563
+ onStatus: (s) => setStatus(r.id, s)
564
+ },
565
+ r.id
566
+ )) })
567
+ ] })
568
+ ] })
569
+ ] }),
570
+ /* @__PURE__ */ jsx(
571
+ ReservationModal,
572
+ {
573
+ open: creating || !!editing,
574
+ onClose: () => {
575
+ setCreating(false);
576
+ setEditing(null);
577
+ setSlotSeed(null);
578
+ },
579
+ date: selectedDate,
580
+ reservation: editing,
581
+ defaultSlot: slotSeed
582
+ }
583
+ ),
584
+ /* @__PURE__ */ jsx(SeatDialog, { reservation: seating, onClose: () => setSeating(null) })
585
+ ] });
586
+ }
587
+ function ReservationRow({ reservation: r, badge, onEdit, onSeat, onStatus }) {
588
+ const done = r.status === "seated" || r.status === "cancelled" || r.status === "no_show";
589
+ return /* @__PURE__ */ jsxs("li", { className: "flex items-center gap-3 rounded-lg border bg-card p-3", children: [
590
+ /* @__PURE__ */ jsx("span", { className: "w-12 shrink-0 text-sm font-semibold tabular-nums", children: r.startTime }),
591
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
592
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
593
+ /* @__PURE__ */ jsx("span", { className: "truncate font-medium", children: r.guestName }),
594
+ /* @__PURE__ */ jsx(DotBadge, { label: badge.label, color: badge.color })
595
+ ] }),
596
+ /* @__PURE__ */ jsxs("div", { className: "mt-0.5 flex flex-wrap items-center gap-x-3 gap-y-0.5 text-xs text-muted-foreground", children: [
597
+ /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1", children: [
598
+ /* @__PURE__ */ jsx(Users, { className: "h-3 w-3" }),
599
+ r.partySize
600
+ ] }),
601
+ r.zoneName && /* @__PURE__ */ jsx("span", { children: r.zoneName }),
602
+ r.tableNumber != null && /* @__PURE__ */ jsxs("span", { children: [
603
+ "Mesa ",
604
+ r.tableNumber
605
+ ] }),
606
+ r.phone && /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1", children: [
607
+ /* @__PURE__ */ jsx(Phone, { className: "h-3 w-3" }),
608
+ formatPhone(r.phone)
609
+ ] }),
610
+ r.orderReference && /* @__PURE__ */ jsx("span", { className: "font-medium text-foreground", children: r.orderReference }),
611
+ r.notes && /* @__PURE__ */ jsx("span", { className: "truncate italic", children: r.notes })
612
+ ] })
613
+ ] }),
614
+ /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [
615
+ r.status === "pending" && /* @__PURE__ */ jsx(IconAction, { label: "Confirmar", onClick: () => onStatus("confirmed"), children: /* @__PURE__ */ jsx(Check, { className: "h-4 w-4" }) }),
616
+ !done && /* @__PURE__ */ jsx(IconAction, { label: "Acomodar \u2014 abre a comanda", onClick: onSeat, primary: true, children: /* @__PURE__ */ jsx(Armchair, { className: "h-4 w-4" }) }),
617
+ !done && /* @__PURE__ */ jsx(IconAction, { label: "N\xE3o compareceu", onClick: () => onStatus("no_show"), children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" }) }),
618
+ /* @__PURE__ */ jsx(IconAction, { label: "Editar", onClick: onEdit, children: /* @__PURE__ */ jsx(Pencil, { className: "h-4 w-4" }) })
619
+ ] })
620
+ ] });
621
+ }
622
+ function IconAction({ label, onClick, primary, children }) {
623
+ return /* @__PURE__ */ jsxs(Tooltip, { children: [
624
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
625
+ "button",
626
+ {
627
+ onClick,
628
+ "aria-label": label,
629
+ className: `flex h-8 w-8 items-center justify-center rounded-button border transition-colors ${primary ? "border-primary bg-primary text-primary-foreground hover:bg-primary/90" : "border-border bg-card text-muted-foreground hover:bg-muted hover:text-foreground"}`,
630
+ children
631
+ }
632
+ ) }),
633
+ /* @__PURE__ */ jsx(TooltipContent, { children: label })
634
+ ] });
635
+ }
636
+ function ReservationsListView() {
637
+ const config = useReservationsConfig();
638
+ const rows = useReservationsStore((s) => s.reservations);
639
+ const loading = useReservationsStore((s) => s.listLoading);
640
+ const fetchRange = useReservationsStore((s) => s.fetchRange);
641
+ const selectedDate = useReservationsStore((s) => s.selectedDate);
642
+ const [from, setFrom] = useState(selectedDate);
643
+ const [to, setTo] = useState(() => {
644
+ const [y, m, d] = selectedDate.split("-").map(Number);
645
+ const end = new Date(y, m - 1, d + 30);
646
+ return `${end.getFullYear()}-${String(end.getMonth() + 1).padStart(2, "0")}-${String(end.getDate()).padStart(2, "0")}`;
647
+ });
648
+ const [statusFilter, setStatusFilter] = useState([]);
649
+ const [search, setSearch] = useState("");
650
+ const [editing, setEditing] = useState(null);
651
+ const [creating, setCreating] = useState(false);
652
+ const statusKey = statusFilter.join(",");
653
+ const load = useCallback(() => {
654
+ void fetchRange(from, to, {
655
+ status: statusKey ? statusKey.split(",") : void 0,
656
+ search: search || void 0
657
+ });
658
+ }, [from, to, statusKey, search, fetchRange]);
659
+ useEffect(() => {
660
+ load();
661
+ }, [load]);
662
+ const colorOf = useMemo(() => {
663
+ const map = new Map(config.statuses.map((s) => [s.value, s]));
664
+ return (s) => map.get(s) ?? { label: s, color: "#6b7280" };
665
+ }, [config.statuses]);
666
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
667
+ /* @__PURE__ */ jsx(PageHeaderActions, { children: /* @__PURE__ */ jsx(PermissionGate, { feature: "reservations", action: "create", children: /* @__PURE__ */ jsxs(Button, { onClick: () => setCreating(true), children: [
668
+ /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" }),
669
+ /* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: config.labels.newReservation })
670
+ ] }) }) }),
671
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 lg:flex-row", children: [
672
+ /* @__PURE__ */ jsxs("aside", { className: "w-full shrink-0 space-y-4 lg:w-60", children: [
673
+ /* @__PURE__ */ jsx(SearchField, { value: search, onChange: setSearch, placeholder: "Nome ou telefone\u2026" }),
674
+ /* @__PURE__ */ jsxs("label", { className: "block space-y-1.5", children: [
675
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "De" }),
676
+ /* @__PURE__ */ jsx(Input, { type: "date", value: from, onChange: (e) => setFrom(e.target.value) })
677
+ ] }),
678
+ /* @__PURE__ */ jsxs("label", { className: "block space-y-1.5", children: [
679
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "At\xE9" }),
680
+ /* @__PURE__ */ jsx(Input, { type: "date", value: to, onChange: (e) => setTo(e.target.value) })
681
+ ] }),
682
+ /* @__PURE__ */ jsx(
683
+ FilterCheckList,
684
+ {
685
+ label: "Estado",
686
+ options: config.statuses.map((s) => ({ value: s.value, label: s.label, color: s.color })),
687
+ selected: statusFilter,
688
+ onChange: setStatusFilter
689
+ }
690
+ )
691
+ ] }),
692
+ /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: loading ? /* @__PURE__ */ jsx("div", { className: "space-y-2", children: [0, 1, 2, 3].map((i) => /* @__PURE__ */ jsx(Skeleton, { className: "h-12 w-full rounded-lg" }, i)) }) : rows.length === 0 ? /* @__PURE__ */ jsx("p", { className: "rounded-lg border border-dashed p-6 text-center text-sm text-muted-foreground", children: "Nenhuma reserva encontrada neste per\xEDodo." }) : /* @__PURE__ */ jsx("div", { className: "overflow-x-auto rounded-lg border", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-sm", children: [
693
+ /* @__PURE__ */ jsx("thead", { className: "bg-muted/50 text-xs text-muted-foreground", children: /* @__PURE__ */ jsxs("tr", { children: [
694
+ /* @__PURE__ */ jsx(Th, { children: "Data" }),
695
+ /* @__PURE__ */ jsx(Th, { children: "Hora" }),
696
+ /* @__PURE__ */ jsx(Th, { children: "Cliente" }),
697
+ /* @__PURE__ */ jsx(Th, { children: "Pessoas" }),
698
+ /* @__PURE__ */ jsx(Th, { children: "Pra\xE7a" }),
699
+ /* @__PURE__ */ jsx(Th, { children: "Mesa" }),
700
+ /* @__PURE__ */ jsx(Th, { children: "Estado" }),
701
+ /* @__PURE__ */ jsx(Th, { children: "Comanda" })
702
+ ] }) }),
703
+ /* @__PURE__ */ jsx("tbody", { children: rows.map((r) => {
704
+ const badge = colorOf(r.status);
705
+ return /* @__PURE__ */ jsxs(
706
+ "tr",
707
+ {
708
+ onClick: () => setEditing(r),
709
+ className: "cursor-pointer border-t hover:bg-muted/40",
710
+ children: [
711
+ /* @__PURE__ */ jsx(Td, { className: "tabular-nums", children: r.reservedOn.split("-").reverse().join("/") }),
712
+ /* @__PURE__ */ jsx(Td, { className: "tabular-nums", children: r.startTime }),
713
+ /* @__PURE__ */ jsx(Td, { className: "font-medium", children: r.guestName }),
714
+ /* @__PURE__ */ jsx(Td, { className: "tabular-nums", children: r.partySize }),
715
+ /* @__PURE__ */ jsx(Td, { children: r.zoneName ?? "\u2014" }),
716
+ /* @__PURE__ */ jsx(Td, { children: r.tableNumber ?? "\u2014" }),
717
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(DotBadge, { label: badge.label, color: badge.color }) }),
718
+ /* @__PURE__ */ jsx(Td, { children: r.orderReference ?? "\u2014" })
719
+ ]
720
+ },
721
+ r.id
722
+ );
723
+ }) })
724
+ ] }) }) })
725
+ ] }),
726
+ /* @__PURE__ */ jsx(
727
+ ReservationModal,
728
+ {
729
+ open: creating || !!editing,
730
+ onClose: () => {
731
+ setCreating(false);
732
+ setEditing(null);
733
+ load();
734
+ },
735
+ date: editing?.reservedOn ?? from,
736
+ reservation: editing
737
+ }
738
+ )
739
+ ] });
740
+ }
741
+ var Th = ({ children }) => /* @__PURE__ */ jsx("th", { className: "px-3 py-2 text-left font-medium", children });
742
+ var Td = ({ children, className }) => /* @__PURE__ */ jsx("td", { className: `px-3 py-2 ${className ?? ""}`, children });
743
+ var WEEKDAYS = ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "S\xE1b"];
744
+ var MODES = [
745
+ {
746
+ value: "no_duration",
747
+ label: "Sem dura\xE7\xE3o \u2014 s\xF3 limite por faixa",
748
+ // The V1's own legend, verbatim. It is the clearest statement of the model
749
+ // and it explains the arithmetic everywhere else on the screen.
750
+ hint: "A capacidade \xE9 o teto de pessoas que pode iniciar dentro da faixa, sem rolagem entre faixas."
751
+ },
752
+ {
753
+ value: "fixed_duration",
754
+ label: "Dura\xE7\xE3o fixa global",
755
+ hint: "Toda reserva ocupa a mesa pela dura\xE7\xE3o padr\xE3o abaixo."
756
+ },
757
+ {
758
+ value: "per_slot_duration",
759
+ label: "Dura\xE7\xE3o por faixa de hor\xE1rio",
760
+ hint: "Cada faixa da grade define quanto tempo a mesa fica ocupada."
761
+ }
762
+ ];
763
+ function CapacitySettingsView() {
764
+ const settings = useReservationsStore((s) => s.settings);
765
+ const rules = useReservationsStore((s) => s.rules);
766
+ const exceptions = useReservationsStore((s) => s.exceptions);
767
+ const zones = useReservationsStore((s) => s.zones);
768
+ const loading = useReservationsStore((s) => s.configLoading);
769
+ const fetchConfig = useReservationsStore((s) => s.fetchConfig);
770
+ const fetchSalao = useReservationsStore((s) => s.fetchSalao);
771
+ const saveSettings = useReservationsStore((s) => s.saveSettings);
772
+ useEffect(() => {
773
+ void fetchConfig();
774
+ void fetchSalao();
775
+ }, [fetchConfig, fetchSalao]);
776
+ const [draft, setDraft] = useState(DEFAULT_SETTINGS);
777
+ const [dirty, setDirty] = useState(false);
778
+ useEffect(() => {
779
+ if (settings) setDraft(settings);
780
+ }, [settings]);
781
+ function edit(patch) {
782
+ setDraft((d) => ({ ...d, ...patch }));
783
+ setDirty(true);
784
+ }
785
+ if (loading && !settings) {
786
+ return /* @__PURE__ */ jsx("div", { className: "space-y-3", children: [0, 1, 2].map((i) => /* @__PURE__ */ jsx(Skeleton, { className: "h-24 w-full rounded-lg" }, i)) });
787
+ }
788
+ const mode = MODES.find((m) => m.value === draft.capacityMode);
789
+ return /* @__PURE__ */ jsxs("div", { className: "fz-container space-y-8", children: [
790
+ /* @__PURE__ */ jsxs("section", { className: "space-y-4", children: [
791
+ /* @__PURE__ */ jsxs("header", { children: [
792
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-medium", children: "Pol\xEDtica de reservas" }),
793
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Como a casa aceita e conta reserva." })
794
+ ] }),
795
+ /* @__PURE__ */ jsxs("label", { className: "block space-y-1.5", children: [
796
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Modo de capacidade" }),
797
+ /* @__PURE__ */ jsxs(Select, { value: draft.capacityMode, onValueChange: (v) => edit({ capacityMode: v }), children: [
798
+ /* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, {}) }),
799
+ /* @__PURE__ */ jsx(SelectContent, { children: MODES.map((m) => /* @__PURE__ */ jsx(SelectItem, { value: m.value, children: m.label }, m.value)) })
800
+ ] }),
801
+ /* @__PURE__ */ jsx("span", { className: "block text-xs text-muted-foreground", children: mode.hint })
802
+ ] }),
803
+ /* @__PURE__ */ jsxs("div", { className: "fz-fields fz-fields-2", children: [
804
+ /* @__PURE__ */ jsxs("label", { className: "block space-y-1.5", children: [
805
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Dura\xE7\xE3o padr\xE3o (minutos)" }),
806
+ /* @__PURE__ */ jsx(
807
+ Input,
808
+ {
809
+ type: "number",
810
+ min: 15,
811
+ value: draft.defaultDurationMinutes,
812
+ onChange: (e) => edit({ defaultDurationMinutes: Number(e.target.value) })
813
+ }
814
+ )
815
+ ] }),
816
+ /* @__PURE__ */ jsxs("label", { className: "block space-y-1.5", children: [
817
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Anteced\xEAncia m\xEDnima (horas)" }),
818
+ /* @__PURE__ */ jsx(
819
+ Input,
820
+ {
821
+ type: "number",
822
+ min: 0,
823
+ value: draft.minAdvanceHours,
824
+ onChange: (e) => edit({ minAdvanceHours: Number(e.target.value) })
825
+ }
826
+ ),
827
+ /* @__PURE__ */ jsx("span", { className: "block text-xs text-muted-foreground", children: draft.minAdvanceHours >= 24 ? `${(draft.minAdvanceHours / 24).toFixed(draft.minAdvanceHours % 24 ? 1 : 0)} dia(s) antes` : "No mesmo dia" })
828
+ ] })
829
+ ] }),
830
+ /* @__PURE__ */ jsxs("label", { className: "block space-y-1.5", children: [
831
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Anteced\xEAncia m\xE1xima (dias)" }),
832
+ /* @__PURE__ */ jsx(
833
+ Input,
834
+ {
835
+ type: "number",
836
+ min: 1,
837
+ value: draft.maxAdvanceDays,
838
+ onChange: (e) => edit({ maxAdvanceDays: Number(e.target.value) })
839
+ }
840
+ )
841
+ ] }),
842
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
843
+ /* @__PURE__ */ jsx(
844
+ ToggleRow,
845
+ {
846
+ label: "Confirmar automaticamente",
847
+ hint: "A reserva j\xE1 nasce Confirmada, sem algu\xE9m retornar a liga\xE7\xE3o.",
848
+ checked: draft.autoConfirm,
849
+ onChange: (v) => edit({ autoConfirm: v })
850
+ }
851
+ ),
852
+ /* @__PURE__ */ jsx(
853
+ ToggleRow,
854
+ {
855
+ label: "Exigir telefone",
856
+ hint: "Sem telefone n\xE3o h\xE1 como avisar de atraso ou de cancelamento.",
857
+ checked: draft.requirePhone,
858
+ onChange: (v) => edit({ requirePhone: v })
859
+ }
860
+ ),
861
+ /* @__PURE__ */ jsx(
862
+ ToggleRow,
863
+ {
864
+ label: "Exigir e-mail",
865
+ checked: draft.requireEmail,
866
+ onChange: (v) => edit({ requireEmail: v })
867
+ }
868
+ )
869
+ ] }),
870
+ /* @__PURE__ */ jsx(
871
+ Button,
872
+ {
873
+ onClick: async () => {
874
+ await saveSettings(draft);
875
+ setDirty(false);
876
+ },
877
+ disabled: !dirty,
878
+ children: "Salvar pol\xEDtica"
879
+ }
880
+ )
881
+ ] }),
882
+ /* @__PURE__ */ jsx(RulesSection, { rules, zones }),
883
+ /* @__PURE__ */ jsx(ExceptionsSection, { exceptions, zones })
884
+ ] });
885
+ }
886
+ function ToggleRow({ label, hint, checked, onChange }) {
887
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-4 rounded-lg border p-3", children: [
888
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
889
+ /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: label }),
890
+ hint && /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs text-muted-foreground", children: hint })
891
+ ] }),
892
+ /* @__PURE__ */ jsx(Switch, { checked, onCheckedChange: onChange, "aria-label": label })
893
+ ] });
894
+ }
895
+ var BLANK_RULE = { zoneId: void 0, capacity: 50, startTime: "12:00", endTime: "15:00", weekdays: [1, 2, 3, 4, 5] };
896
+ function RulesSection({ rules, zones }) {
897
+ const saveRule = useReservationsStore((s) => s.saveRule);
898
+ const deleteRule = useReservationsStore((s) => s.deleteRule);
899
+ const [draft, setDraft] = useState(null);
900
+ return /* @__PURE__ */ jsxs("section", { className: "space-y-3", children: [
901
+ /* @__PURE__ */ jsxs("header", { className: "flex items-center justify-between gap-3", children: [
902
+ /* @__PURE__ */ jsxs("div", { children: [
903
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-medium", children: "Grade semanal de capacidade" }),
904
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "Uma regra por pra\xE7a e faixa. Almo\xE7o e jantar s\xE3o duas; o fim de semana costuma ser uma terceira." })
905
+ ] }),
906
+ /* @__PURE__ */ jsxs(Button, { variant: "outline", size: "sm", onClick: () => setDraft({ ...BLANK_RULE }), children: [
907
+ /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" }),
908
+ "Nova regra"
909
+ ] })
910
+ ] }),
911
+ rules.length === 0 && !draft && /* @__PURE__ */ jsx("p", { className: "rounded-lg border border-dashed p-4 text-sm text-muted-foreground", children: "Sem grade, a tela do dia n\xE3o tem faixa nenhuma para desenhar e nada limita a lota\xE7\xE3o." }),
912
+ /* @__PURE__ */ jsx("ul", { className: "space-y-2", children: rules.map((r) => /* @__PURE__ */ jsxs("li", { className: "flex items-center justify-between gap-3 rounded-lg border bg-card p-3", children: [
913
+ /* @__PURE__ */ jsxs("p", { className: "min-w-0 text-sm", children: [
914
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: r.zoneName ?? "Restaurante todo" }),
915
+ /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
916
+ " \xB7 ",
917
+ r.weekdays.map((d) => WEEKDAYS[d]).join(", "),
918
+ " \u2022 ",
919
+ r.startTime,
920
+ " \u2013 ",
921
+ r.endTime,
922
+ " \u2022 ",
923
+ r.capacity,
924
+ " pessoas"
925
+ ] })
926
+ ] }),
927
+ /* @__PURE__ */ jsx(
928
+ "button",
929
+ {
930
+ onClick: () => deleteRule(r.id),
931
+ "aria-label": `Excluir regra de ${r.zoneName ?? "restaurante todo"}`,
932
+ className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-button border text-muted-foreground hover:bg-destructive/10 hover:text-destructive",
933
+ children: /* @__PURE__ */ jsx(Trash2, { className: "h-4 w-4" })
934
+ }
935
+ )
936
+ ] }, r.id)) }),
937
+ draft && /* @__PURE__ */ jsxs("div", { className: "space-y-3 rounded-lg border bg-muted/30 p-3", children: [
938
+ /* @__PURE__ */ jsxs("div", { className: "fz-fields fz-fields-2", children: [
939
+ /* @__PURE__ */ jsxs("label", { className: "block space-y-1.5", children: [
940
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Pra\xE7a" }),
941
+ /* @__PURE__ */ jsxs(Select, { value: draft.zoneId ?? "__all", onValueChange: (v) => setDraft({ ...draft, zoneId: v === "__all" ? void 0 : v }), children: [
942
+ /* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, {}) }),
943
+ /* @__PURE__ */ jsxs(SelectContent, { children: [
944
+ /* @__PURE__ */ jsx(SelectItem, { value: "__all", children: "Restaurante todo" }),
945
+ zones.map((z) => /* @__PURE__ */ jsx(SelectItem, { value: z.id, children: z.name }, z.id))
946
+ ] })
947
+ ] })
948
+ ] }),
949
+ /* @__PURE__ */ jsxs("label", { className: "block space-y-1.5", children: [
950
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Capacidade (pessoas)" }),
951
+ /* @__PURE__ */ jsx(
952
+ Input,
953
+ {
954
+ type: "number",
955
+ min: 1,
956
+ value: draft.capacity,
957
+ onChange: (e) => setDraft({ ...draft, capacity: Number(e.target.value) })
958
+ }
959
+ )
960
+ ] })
961
+ ] }),
962
+ /* @__PURE__ */ jsxs("div", { className: "fz-fields fz-fields-2", children: [
963
+ /* @__PURE__ */ jsxs("label", { className: "block space-y-1.5", children: [
964
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "In\xEDcio" }),
965
+ /* @__PURE__ */ jsx(TimePicker, { value: draft.startTime, onChange: (v) => setDraft({ ...draft, startTime: v }) })
966
+ ] }),
967
+ /* @__PURE__ */ jsxs("label", { className: "block space-y-1.5", children: [
968
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Fim" }),
969
+ /* @__PURE__ */ jsx(TimePicker, { value: draft.endTime, onChange: (v) => setDraft({ ...draft, endTime: v }) })
970
+ ] })
971
+ ] }),
972
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
973
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Dias da semana" }),
974
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: WEEKDAYS.map((label, i) => {
975
+ const on = draft.weekdays.includes(i);
976
+ return /* @__PURE__ */ jsx(
977
+ "button",
978
+ {
979
+ type: "button",
980
+ onClick: () => setDraft({
981
+ ...draft,
982
+ weekdays: on ? draft.weekdays.filter((d) => d !== i) : [...draft.weekdays, i].sort()
983
+ }),
984
+ className: `rounded-button border px-2.5 py-1 text-xs transition-colors ${on ? "border-primary bg-primary text-primary-foreground" : "border-border hover:bg-muted"}`,
985
+ children: label
986
+ },
987
+ i
988
+ );
989
+ }) })
990
+ ] }),
991
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3", children: [
992
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: draft.weekdays.length === 0 ? "Escolha pelo menos um dia da semana." : "" }),
993
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
994
+ /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: () => setDraft(null), children: "Cancelar" }),
995
+ /* @__PURE__ */ jsx(
996
+ Button,
997
+ {
998
+ size: "sm",
999
+ disabled: !draft.weekdays.length || draft.endTime <= draft.startTime,
1000
+ onClick: async () => {
1001
+ await saveRule(draft);
1002
+ setDraft(null);
1003
+ },
1004
+ children: "Salvar regra"
1005
+ }
1006
+ )
1007
+ ] })
1008
+ ] })
1009
+ ] })
1010
+ ] });
1011
+ }
1012
+ function todayISO() {
1013
+ const d = /* @__PURE__ */ new Date();
1014
+ return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
1015
+ }
1016
+ function ExceptionsSection({ exceptions, zones }) {
1017
+ const saveException = useReservationsStore((s) => s.saveException);
1018
+ const deleteException = useReservationsStore((s) => s.deleteException);
1019
+ const [draft, setDraft] = useState(null);
1020
+ return /* @__PURE__ */ jsxs("section", { className: "space-y-3", children: [
1021
+ /* @__PURE__ */ jsxs("header", { className: "flex items-center justify-between gap-3", children: [
1022
+ /* @__PURE__ */ jsxs("div", { children: [
1023
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-medium", children: "Exce\xE7\xF5es de capacidade" }),
1024
+ /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
1025
+ "Exce\xE7\xF5es ",
1026
+ /* @__PURE__ */ jsx("strong", { children: "sobrep\xF5em" }),
1027
+ " a grade semanal para os dias cobertos na mesma pra\xE7a. Capacidade 0 fecha a pra\xE7a sem apagar a grade."
1028
+ ] })
1029
+ ] }),
1030
+ /* @__PURE__ */ jsxs(
1031
+ Button,
1032
+ {
1033
+ variant: "outline",
1034
+ size: "sm",
1035
+ onClick: () => setDraft({ startsOn: todayISO(), endsOn: todayISO(), capacity: 0 }),
1036
+ children: [
1037
+ /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" }),
1038
+ "Nova exce\xE7\xE3o"
1039
+ ]
1040
+ }
1041
+ )
1042
+ ] }),
1043
+ /* @__PURE__ */ jsx("ul", { className: "space-y-2", children: exceptions.map((e) => /* @__PURE__ */ jsxs("li", { className: "flex items-center justify-between gap-3 rounded-lg border bg-card p-3", children: [
1044
+ /* @__PURE__ */ jsxs("p", { className: "min-w-0 text-sm", children: [
1045
+ /* @__PURE__ */ jsx("span", { className: "font-medium", children: e.zoneName ?? "Restaurante todo" }),
1046
+ /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
1047
+ " \xB7 ",
1048
+ e.startsOn,
1049
+ e.endsOn !== e.startsOn ? ` a ${e.endsOn}` : "",
1050
+ " \u2022 ",
1051
+ e.capacity === 0 ? "fechado" : `${e.capacity} pessoas`,
1052
+ e.reason ? ` \u2022 ${e.reason}` : ""
1053
+ ] })
1054
+ ] }),
1055
+ /* @__PURE__ */ jsx(
1056
+ "button",
1057
+ {
1058
+ onClick: () => deleteException(e.id),
1059
+ "aria-label": "Excluir exce\xE7\xE3o",
1060
+ className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-button border text-muted-foreground hover:bg-destructive/10 hover:text-destructive",
1061
+ children: /* @__PURE__ */ jsx(Trash2, { className: "h-4 w-4" })
1062
+ }
1063
+ )
1064
+ ] }, e.id)) }),
1065
+ exceptions.length === 0 && !draft && /* @__PURE__ */ jsxs("p", { className: "flex items-center gap-2 rounded-lg border border-dashed p-4 text-sm text-muted-foreground", children: [
1066
+ /* @__PURE__ */ jsx(CalendarOff, { className: "h-4 w-4 shrink-0" }),
1067
+ "Nenhuma exce\xE7\xE3o. Feriado, evento fechado e reforma entram aqui."
1068
+ ] }),
1069
+ draft && /* @__PURE__ */ jsxs("div", { className: "space-y-3 rounded-lg border bg-muted/30 p-3", children: [
1070
+ /* @__PURE__ */ jsxs("div", { className: "fz-fields fz-fields-2", children: [
1071
+ /* @__PURE__ */ jsxs("label", { className: "block space-y-1.5", children: [
1072
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Pra\xE7a" }),
1073
+ /* @__PURE__ */ jsxs(Select, { value: draft.zoneId ?? "__all", onValueChange: (v) => setDraft({ ...draft, zoneId: v === "__all" ? void 0 : v }), children: [
1074
+ /* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, {}) }),
1075
+ /* @__PURE__ */ jsxs(SelectContent, { children: [
1076
+ /* @__PURE__ */ jsx(SelectItem, { value: "__all", children: "Restaurante todo" }),
1077
+ zones.map((z) => /* @__PURE__ */ jsx(SelectItem, { value: z.id, children: z.name }, z.id))
1078
+ ] })
1079
+ ] })
1080
+ ] }),
1081
+ /* @__PURE__ */ jsxs("label", { className: "block space-y-1.5", children: [
1082
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Capacidade (0 = fechado)" }),
1083
+ /* @__PURE__ */ jsx(
1084
+ Input,
1085
+ {
1086
+ type: "number",
1087
+ min: 0,
1088
+ value: draft.capacity ?? 0,
1089
+ onChange: (e) => setDraft({ ...draft, capacity: Number(e.target.value) })
1090
+ }
1091
+ )
1092
+ ] })
1093
+ ] }),
1094
+ /* @__PURE__ */ jsxs("div", { className: "fz-fields fz-fields-2", children: [
1095
+ /* @__PURE__ */ jsxs("label", { className: "block space-y-1.5", children: [
1096
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "De" }),
1097
+ /* @__PURE__ */ jsx(Input, { type: "date", value: draft.startsOn ?? "", onChange: (e) => setDraft({ ...draft, startsOn: e.target.value }) })
1098
+ ] }),
1099
+ /* @__PURE__ */ jsxs("label", { className: "block space-y-1.5", children: [
1100
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "At\xE9" }),
1101
+ /* @__PURE__ */ jsx(Input, { type: "date", value: draft.endsOn ?? "", onChange: (e) => setDraft({ ...draft, endsOn: e.target.value }) })
1102
+ ] })
1103
+ ] }),
1104
+ /* @__PURE__ */ jsxs("label", { className: "block space-y-1.5", children: [
1105
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Motivo" }),
1106
+ /* @__PURE__ */ jsx(
1107
+ Input,
1108
+ {
1109
+ value: draft.reason ?? "",
1110
+ onChange: (e) => setDraft({ ...draft, reason: e.target.value }),
1111
+ placeholder: "Feriado, evento fechado, reforma\u2026"
1112
+ }
1113
+ )
1114
+ ] }),
1115
+ /* @__PURE__ */ jsxs("div", { className: "flex justify-end gap-2", children: [
1116
+ /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: () => setDraft(null), children: "Cancelar" }),
1117
+ /* @__PURE__ */ jsx(
1118
+ Button,
1119
+ {
1120
+ size: "sm",
1121
+ disabled: !draft.startsOn,
1122
+ onClick: async () => {
1123
+ await saveException(draft);
1124
+ setDraft(null);
1125
+ },
1126
+ children: "Salvar exce\xE7\xE3o"
1127
+ }
1128
+ )
1129
+ ] })
1130
+ ] })
1131
+ ] });
1132
+ }
1133
+ function ReservationsPage({ config, provider, store }) {
1134
+ const [tab, setTab] = useState("day");
1135
+ return /* @__PURE__ */ jsx(ReservationsContextProvider, { config, provider, store, children: /* @__PURE__ */ jsxs("div", { children: [
1136
+ /* @__PURE__ */ jsx(
1137
+ PageTabs,
1138
+ {
1139
+ "aria-label": "Reservas",
1140
+ value: tab,
1141
+ onChange: setTab,
1142
+ tabs: [
1143
+ { value: "day", label: "Servi\xE7o", icon: CalendarClock },
1144
+ { value: "list", label: "Lista", icon: List }
1145
+ ]
1146
+ }
1147
+ ),
1148
+ tab === "day" ? /* @__PURE__ */ jsx(ServiceDayView, {}) : /* @__PURE__ */ jsx(ReservationsListView, {})
1149
+ ] }) });
1150
+ }
1151
+ function ReservationsSettingsPage({ config, provider, store }) {
1152
+ return /* @__PURE__ */ jsx(ReservationsContextProvider, { config, provider, store, children: /* @__PURE__ */ jsx(CapacitySettingsView, {}) });
1153
+ }
1154
+
1155
+ export { ReservationsPage, ReservationsSettingsPage };
1156
+ //# sourceMappingURL=ReservationsPage-5RF5SYZT.js.map
1157
+ //# sourceMappingURL=ReservationsPage-5RF5SYZT.js.map