@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.
- package/LICENSE +21 -0
- package/dist/ReservationsPage-5RF5SYZT.js +1157 -0
- package/dist/ReservationsPage-5RF5SYZT.js.map +1 -0
- package/dist/chunk-7KXGSUHT.js +335 -0
- package/dist/chunk-7KXGSUHT.js.map +1 -0
- package/dist/components/CapacityStrip.d.ts +25 -0
- package/dist/components/CapacityStrip.d.ts.map +1 -0
- package/dist/components/ReservationModal.d.ts +23 -0
- package/dist/components/ReservationModal.d.ts.map +1 -0
- package/dist/components/SeatDialog.d.ts +16 -0
- package/dist/components/SeatDialog.d.ts.map +1 -0
- package/dist/context.d.ts +49 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/data/core-supabase.d.ts +32 -0
- package/dist/data/core-supabase.d.ts.map +1 -0
- package/dist/data/mock.d.ts +3 -0
- package/dist/data/mock.d.ts.map +1 -0
- package/dist/data/types.d.ts +37 -0
- package/dist/data/types.d.ts.map +1 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +870 -0
- package/dist/index.js.map +1 -0
- package/dist/locales/en.d.ts +2 -0
- package/dist/locales/en.d.ts.map +1 -0
- package/dist/locales/index.d.ts +2 -0
- package/dist/locales/index.d.ts.map +1 -0
- package/dist/locales/pt-BR.d.ts +2 -0
- package/dist/locales/pt-BR.d.ts.map +1 -0
- package/dist/migrations/index.d.ts +6 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/store.d.ts +48 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/types.d.ts +174 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/views/CapacitySettingsView.d.ts +3 -0
- package/dist/views/CapacitySettingsView.d.ts.map +1 -0
- package/dist/views/ReservationsListView.d.ts +5 -0
- package/dist/views/ReservationsListView.d.ts.map +1 -0
- package/dist/views/ReservationsPage.d.ts +27 -0
- package/dist/views/ReservationsPage.d.ts.map +1 -0
- package/dist/views/ServiceDayView.d.ts +15 -0
- package/dist/views/ServiceDayView.d.ts.map +1 -0
- package/package.json +62 -0
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
import { getSupabaseClientOptional } from '@fayz-ai/core';
|
|
2
|
+
|
|
3
|
+
// src/data/core-supabase.ts
|
|
4
|
+
var RESERVATIONS = "plg_reservations";
|
|
5
|
+
var VIEW = "v_reservations";
|
|
6
|
+
var RULES = "plg_reservations_capacity_rules";
|
|
7
|
+
var EXCEPTIONS = "plg_reservations_capacity_exceptions";
|
|
8
|
+
var SETTINGS = "plg_reservations_settings";
|
|
9
|
+
var ZONES = "plg_tables_zones";
|
|
10
|
+
var TABLES_VIEW = "v_tables";
|
|
11
|
+
var DEFAULT_SETTINGS = {
|
|
12
|
+
capacityMode: "no_duration",
|
|
13
|
+
defaultDurationMinutes: 120,
|
|
14
|
+
minAdvanceHours: 24,
|
|
15
|
+
maxAdvanceDays: 90,
|
|
16
|
+
autoConfirm: false,
|
|
17
|
+
requirePhone: true,
|
|
18
|
+
requireEmail: false
|
|
19
|
+
};
|
|
20
|
+
var READ_ONLY = "This provider reads reservations; pass `writes` to let the app that owns it change them.";
|
|
21
|
+
function hhmm(value) {
|
|
22
|
+
if (!value) return void 0;
|
|
23
|
+
return value.slice(0, 5);
|
|
24
|
+
}
|
|
25
|
+
function createCoreReservationsProvider(options) {
|
|
26
|
+
const db = () => {
|
|
27
|
+
const client = getSupabaseClientOptional();
|
|
28
|
+
if (!client) throw new Error("Supabase client is not configured");
|
|
29
|
+
return client;
|
|
30
|
+
};
|
|
31
|
+
function requireWrites() {
|
|
32
|
+
if (!options?.writes) throw new Error(READ_ONLY);
|
|
33
|
+
return options.writes;
|
|
34
|
+
}
|
|
35
|
+
function tenant() {
|
|
36
|
+
const id = requireWrites().tenantId();
|
|
37
|
+
if (!id) throw new Error("No active tenant");
|
|
38
|
+
return id;
|
|
39
|
+
}
|
|
40
|
+
function rowToReservation(r) {
|
|
41
|
+
return {
|
|
42
|
+
id: r.id,
|
|
43
|
+
personId: r.person_id ?? void 0,
|
|
44
|
+
guestName: r.guest_name,
|
|
45
|
+
phone: r.phone ?? void 0,
|
|
46
|
+
email: r.email ?? void 0,
|
|
47
|
+
zoneId: r.zone_id ?? void 0,
|
|
48
|
+
zoneName: r.zone_name ?? void 0,
|
|
49
|
+
zoneColor: r.zone_color ?? void 0,
|
|
50
|
+
tableId: r.table_id ?? void 0,
|
|
51
|
+
tableNumber: r.table_number ?? void 0,
|
|
52
|
+
reservedOn: r.reserved_on,
|
|
53
|
+
startTime: hhmm(r.start_time) ?? "00:00",
|
|
54
|
+
endTime: hhmm(r.end_time),
|
|
55
|
+
partySize: r.party_size,
|
|
56
|
+
occasion: r.occasion ?? void 0,
|
|
57
|
+
notes: r.notes ?? void 0,
|
|
58
|
+
status: r.status,
|
|
59
|
+
orderId: r.order_id ?? void 0,
|
|
60
|
+
orderReference: r.order_reference ?? void 0,
|
|
61
|
+
seatedAt: r.seated_at ?? void 0,
|
|
62
|
+
tenantId: r.tenant_id,
|
|
63
|
+
createdAt: r.created_at,
|
|
64
|
+
updatedAt: r.updated_at
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
async function byId(id) {
|
|
68
|
+
const { data, error } = await db().from(VIEW).select("*").eq("id", id).maybeSingle();
|
|
69
|
+
if (error) throw new Error(error.message);
|
|
70
|
+
if (!data) throw new Error("Reserva n\xE3o encontrada");
|
|
71
|
+
return rowToReservation(data);
|
|
72
|
+
}
|
|
73
|
+
function toRow(input) {
|
|
74
|
+
const row = {};
|
|
75
|
+
if (input.personId !== void 0) row.person_id = input.personId || null;
|
|
76
|
+
if (input.guestName !== void 0) row.guest_name = input.guestName;
|
|
77
|
+
if (input.phone !== void 0) row.phone = input.phone || null;
|
|
78
|
+
if (input.email !== void 0) row.email = input.email || null;
|
|
79
|
+
if (input.zoneId !== void 0) row.zone_id = input.zoneId || null;
|
|
80
|
+
if (input.tableId !== void 0) row.table_id = input.tableId || null;
|
|
81
|
+
if (input.reservedOn !== void 0) row.reserved_on = input.reservedOn;
|
|
82
|
+
if (input.startTime !== void 0) row.start_time = input.startTime;
|
|
83
|
+
if (input.endTime !== void 0) row.end_time = input.endTime || null;
|
|
84
|
+
if (input.partySize !== void 0) row.party_size = input.partySize;
|
|
85
|
+
if (input.occasion !== void 0) row.occasion = input.occasion || null;
|
|
86
|
+
if (input.notes !== void 0) row.notes = input.notes || null;
|
|
87
|
+
if (input.status !== void 0) row.status = input.status;
|
|
88
|
+
return row;
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
async getReservations(query) {
|
|
92
|
+
let q = db().from(VIEW).select("*").order("reserved_on").order("start_time");
|
|
93
|
+
if (query?.from) q = q.gte("reserved_on", query.from);
|
|
94
|
+
if (query?.to) q = q.lte("reserved_on", query.to);
|
|
95
|
+
if (query?.zoneId) q = q.eq("zone_id", query.zoneId);
|
|
96
|
+
if (query?.status) {
|
|
97
|
+
const wanted = Array.isArray(query.status) ? query.status : [query.status];
|
|
98
|
+
q = q.in("status", wanted);
|
|
99
|
+
}
|
|
100
|
+
if (query?.search) {
|
|
101
|
+
const term = `%${query.search}%`;
|
|
102
|
+
q = q.or(`guest_name.ilike.${term},phone.ilike.${term}`);
|
|
103
|
+
}
|
|
104
|
+
const { data, error } = await q;
|
|
105
|
+
if (error) throw new Error(error.message);
|
|
106
|
+
return (data ?? []).map(rowToReservation);
|
|
107
|
+
},
|
|
108
|
+
async getReservation(id) {
|
|
109
|
+
const { data, error } = await db().from(VIEW).select("*").eq("id", id).maybeSingle();
|
|
110
|
+
if (error) throw new Error(error.message);
|
|
111
|
+
return data ? rowToReservation(data) : null;
|
|
112
|
+
},
|
|
113
|
+
async createReservation(input) {
|
|
114
|
+
const tenantId = tenant();
|
|
115
|
+
const { data, error } = await db().from(RESERVATIONS).insert({ ...toRow(input), tenant_id: tenantId }).select("id").single();
|
|
116
|
+
if (error) throw new Error(error.message);
|
|
117
|
+
return byId(data.id);
|
|
118
|
+
},
|
|
119
|
+
async updateReservation(id, data) {
|
|
120
|
+
requireWrites();
|
|
121
|
+
const patch = toRow(data);
|
|
122
|
+
if (Object.keys(patch).length) {
|
|
123
|
+
const { error } = await db().from(RESERVATIONS).update(patch).eq("id", id);
|
|
124
|
+
if (error) throw new Error(error.message);
|
|
125
|
+
}
|
|
126
|
+
return byId(id);
|
|
127
|
+
},
|
|
128
|
+
async setStatus(id, status) {
|
|
129
|
+
requireWrites();
|
|
130
|
+
if (status === "seated") {
|
|
131
|
+
throw new Error('Acomodar abre a comanda \u2014 use "sentar" em vez de marcar o estado.');
|
|
132
|
+
}
|
|
133
|
+
const { error } = await db().from(RESERVATIONS).update({ status }).eq("id", id);
|
|
134
|
+
if (error) throw new Error(error.message);
|
|
135
|
+
return byId(id);
|
|
136
|
+
},
|
|
137
|
+
async deleteReservation(id) {
|
|
138
|
+
requireWrites();
|
|
139
|
+
const { error } = await db().from(RESERVATIONS).delete().eq("id", id);
|
|
140
|
+
if (error) throw new Error(error.message);
|
|
141
|
+
},
|
|
142
|
+
async seatReservation(input) {
|
|
143
|
+
const writes = requireWrites();
|
|
144
|
+
const reservation = await byId(input.reservationId);
|
|
145
|
+
if (reservation.status === "seated") throw new Error("Esta reserva j\xE1 foi acomodada");
|
|
146
|
+
if (reservation.status === "cancelled") throw new Error("Reserva cancelada n\xE3o senta");
|
|
147
|
+
const guests = input.guests ?? reservation.partySize;
|
|
148
|
+
let orderId;
|
|
149
|
+
if (writes.openComanda) {
|
|
150
|
+
const opened = await writes.openComanda({
|
|
151
|
+
tableId: input.tableId,
|
|
152
|
+
guests,
|
|
153
|
+
notes: `Reserva \xB7 ${reservation.guestName}`
|
|
154
|
+
});
|
|
155
|
+
orderId = opened.orderId;
|
|
156
|
+
}
|
|
157
|
+
const { error } = await db().from(RESERVATIONS).update({
|
|
158
|
+
status: "seated",
|
|
159
|
+
table_id: input.tableId,
|
|
160
|
+
party_size: guests,
|
|
161
|
+
order_id: orderId ?? null,
|
|
162
|
+
seated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
163
|
+
}).eq("id", input.reservationId);
|
|
164
|
+
if (error) throw new Error(error.message);
|
|
165
|
+
return byId(input.reservationId);
|
|
166
|
+
},
|
|
167
|
+
// -- The grid ------------------------------------------------------------
|
|
168
|
+
async getDayCapacity(date) {
|
|
169
|
+
const { data, error } = await db().rpc("reservations_day_capacity", { p_date: date });
|
|
170
|
+
if (error) throw new Error(error.message);
|
|
171
|
+
return (data ?? []).map((s) => ({
|
|
172
|
+
zoneId: s.zone_id ?? void 0,
|
|
173
|
+
zoneName: s.zone_name ?? void 0,
|
|
174
|
+
zoneColor: s.zone_color ?? void 0,
|
|
175
|
+
startTime: hhmm(s.start_time) ?? "00:00",
|
|
176
|
+
endTime: hhmm(s.end_time) ?? "23:59",
|
|
177
|
+
capacity: Number(s.capacity) || 0,
|
|
178
|
+
booked: Number(s.booked) || 0,
|
|
179
|
+
remaining: Number(s.remaining) || 0,
|
|
180
|
+
isException: !!s.is_exception
|
|
181
|
+
}));
|
|
182
|
+
},
|
|
183
|
+
async getCapacityRules() {
|
|
184
|
+
const { data, error } = await db().from(RULES).select("*, plg_tables_zones(name)").order("start_time");
|
|
185
|
+
if (error) throw new Error(error.message);
|
|
186
|
+
return (data ?? []).map((r) => ({
|
|
187
|
+
id: r.id,
|
|
188
|
+
zoneId: r.zone_id ?? void 0,
|
|
189
|
+
zoneName: r.plg_tables_zones?.name ?? void 0,
|
|
190
|
+
capacity: r.capacity,
|
|
191
|
+
startTime: hhmm(r.start_time) ?? "00:00",
|
|
192
|
+
endTime: hhmm(r.end_time) ?? "23:59",
|
|
193
|
+
weekdays: (r.weekdays ?? []).map(Number),
|
|
194
|
+
durationMinutes: r.duration_minutes ?? void 0,
|
|
195
|
+
isActive: r.is_active !== false,
|
|
196
|
+
tenantId: r.tenant_id
|
|
197
|
+
}));
|
|
198
|
+
},
|
|
199
|
+
async saveCapacityRule(rule) {
|
|
200
|
+
const tenantId = tenant();
|
|
201
|
+
const row = {
|
|
202
|
+
tenant_id: tenantId,
|
|
203
|
+
zone_id: rule.zoneId || null,
|
|
204
|
+
capacity: rule.capacity,
|
|
205
|
+
start_time: rule.startTime,
|
|
206
|
+
end_time: rule.endTime,
|
|
207
|
+
weekdays: rule.weekdays ?? [0, 1, 2, 3, 4, 5, 6],
|
|
208
|
+
duration_minutes: rule.durationMinutes ?? null,
|
|
209
|
+
is_active: rule.isActive !== false
|
|
210
|
+
};
|
|
211
|
+
const q = rule.id ? db().from(RULES).update(row).eq("id", rule.id) : db().from(RULES).insert(row);
|
|
212
|
+
const { data, error } = await q.select("id").single();
|
|
213
|
+
if (error) throw new Error(error.message);
|
|
214
|
+
const all = await this.getCapacityRules();
|
|
215
|
+
return all.find((r) => r.id === data.id);
|
|
216
|
+
},
|
|
217
|
+
async deleteCapacityRule(id) {
|
|
218
|
+
requireWrites();
|
|
219
|
+
const { error } = await db().from(RULES).delete().eq("id", id);
|
|
220
|
+
if (error) throw new Error(error.message);
|
|
221
|
+
},
|
|
222
|
+
async getCapacityExceptions() {
|
|
223
|
+
const { data, error } = await db().from(EXCEPTIONS).select("*, plg_tables_zones(name)").order("starts_on");
|
|
224
|
+
if (error) throw new Error(error.message);
|
|
225
|
+
return (data ?? []).map((e) => ({
|
|
226
|
+
id: e.id,
|
|
227
|
+
zoneId: e.zone_id ?? void 0,
|
|
228
|
+
zoneName: e.plg_tables_zones?.name ?? void 0,
|
|
229
|
+
startsOn: e.starts_on,
|
|
230
|
+
endsOn: e.ends_on,
|
|
231
|
+
startTime: hhmm(e.start_time),
|
|
232
|
+
endTime: hhmm(e.end_time),
|
|
233
|
+
capacity: e.capacity,
|
|
234
|
+
reason: e.reason ?? void 0,
|
|
235
|
+
tenantId: e.tenant_id
|
|
236
|
+
}));
|
|
237
|
+
},
|
|
238
|
+
async saveCapacityException(ex) {
|
|
239
|
+
const tenantId = tenant();
|
|
240
|
+
const row = {
|
|
241
|
+
tenant_id: tenantId,
|
|
242
|
+
zone_id: ex.zoneId || null,
|
|
243
|
+
starts_on: ex.startsOn,
|
|
244
|
+
ends_on: ex.endsOn ?? ex.startsOn,
|
|
245
|
+
start_time: ex.startTime || null,
|
|
246
|
+
end_time: ex.endTime || null,
|
|
247
|
+
capacity: ex.capacity ?? 0,
|
|
248
|
+
reason: ex.reason || null
|
|
249
|
+
};
|
|
250
|
+
const q = ex.id ? db().from(EXCEPTIONS).update(row).eq("id", ex.id) : db().from(EXCEPTIONS).insert(row);
|
|
251
|
+
const { data, error } = await q.select("id").single();
|
|
252
|
+
if (error) throw new Error(error.message);
|
|
253
|
+
const all = await this.getCapacityExceptions();
|
|
254
|
+
return all.find((e) => e.id === data.id);
|
|
255
|
+
},
|
|
256
|
+
async deleteCapacityException(id) {
|
|
257
|
+
requireWrites();
|
|
258
|
+
const { error } = await db().from(EXCEPTIONS).delete().eq("id", id);
|
|
259
|
+
if (error) throw new Error(error.message);
|
|
260
|
+
},
|
|
261
|
+
// -- The policy ----------------------------------------------------------
|
|
262
|
+
async getSettings() {
|
|
263
|
+
const { data, error } = await db().from(SETTINGS).select("*").maybeSingle();
|
|
264
|
+
if (error) throw new Error(error.message);
|
|
265
|
+
if (!data) return { ...DEFAULT_SETTINGS };
|
|
266
|
+
return {
|
|
267
|
+
capacityMode: data.capacity_mode,
|
|
268
|
+
defaultDurationMinutes: data.default_duration_minutes,
|
|
269
|
+
minAdvanceHours: data.min_advance_hours,
|
|
270
|
+
maxAdvanceDays: data.max_advance_days,
|
|
271
|
+
autoConfirm: !!data.auto_confirm,
|
|
272
|
+
requirePhone: !!data.require_phone,
|
|
273
|
+
requireEmail: !!data.require_email
|
|
274
|
+
};
|
|
275
|
+
},
|
|
276
|
+
async saveSettings(settings) {
|
|
277
|
+
const tenantId = tenant();
|
|
278
|
+
const { error } = await db().from(SETTINGS).upsert({
|
|
279
|
+
tenant_id: tenantId,
|
|
280
|
+
capacity_mode: settings.capacityMode,
|
|
281
|
+
default_duration_minutes: settings.defaultDurationMinutes,
|
|
282
|
+
min_advance_hours: settings.minAdvanceHours,
|
|
283
|
+
max_advance_days: settings.maxAdvanceDays,
|
|
284
|
+
auto_confirm: settings.autoConfirm,
|
|
285
|
+
require_phone: settings.requirePhone,
|
|
286
|
+
require_email: settings.requireEmail
|
|
287
|
+
}, { onConflict: "tenant_id" });
|
|
288
|
+
if (error) throw new Error(error.message);
|
|
289
|
+
return settings;
|
|
290
|
+
},
|
|
291
|
+
// -- The salão, borrowed -------------------------------------------------
|
|
292
|
+
async getZones() {
|
|
293
|
+
const { data, error } = await db().from(ZONES).select("id, name, color").eq("is_active", true).order("sort_order");
|
|
294
|
+
if (error) return [];
|
|
295
|
+
return (data ?? []).map((z) => ({ id: z.id, name: z.name, color: z.color ?? void 0 }));
|
|
296
|
+
},
|
|
297
|
+
async getTables(zoneId) {
|
|
298
|
+
let q = db().from(TABLES_VIEW).select("id, number, name, seats, zone_id, status").order("number");
|
|
299
|
+
if (zoneId) q = q.eq("zone_id", zoneId);
|
|
300
|
+
const { data, error } = await q;
|
|
301
|
+
if (error) return [];
|
|
302
|
+
return (data ?? []).map((t) => ({
|
|
303
|
+
id: t.id,
|
|
304
|
+
number: t.number,
|
|
305
|
+
name: t.name ?? void 0,
|
|
306
|
+
seats: t.seats ?? 0,
|
|
307
|
+
zoneId: t.zone_id ?? void 0,
|
|
308
|
+
// `occupied` is derived by v_tables from the open comanda — the one
|
|
309
|
+
// fact, read here too rather than guessed from a stored column.
|
|
310
|
+
isOccupied: t.status === "occupied"
|
|
311
|
+
}));
|
|
312
|
+
},
|
|
313
|
+
async getSummary(date) {
|
|
314
|
+
const { data, error } = await db().from(RESERVATIONS).select("status, party_size").eq("reserved_on", date);
|
|
315
|
+
if (error) throw new Error(error.message);
|
|
316
|
+
const rows = data ?? [];
|
|
317
|
+
const count = (s) => rows.filter((r) => r.status === s).length;
|
|
318
|
+
return {
|
|
319
|
+
total: rows.length,
|
|
320
|
+
pending: count("pending"),
|
|
321
|
+
confirmed: count("confirmed"),
|
|
322
|
+
seated: count("seated"),
|
|
323
|
+
noShow: count("no_show"),
|
|
324
|
+
cancelled: count("cancelled"),
|
|
325
|
+
// Cancelled and no-show do not eat. This is the number the kitchen
|
|
326
|
+
// plans against, not the row count.
|
|
327
|
+
expectedGuests: rows.filter((r) => !["cancelled", "no_show"].includes(r.status)).reduce((sum, r) => sum + (r.party_size ?? 0), 0)
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
export { DEFAULT_SETTINGS, createCoreReservationsProvider };
|
|
334
|
+
//# sourceMappingURL=chunk-7KXGSUHT.js.map
|
|
335
|
+
//# sourceMappingURL=chunk-7KXGSUHT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/data/core-supabase.ts"],"names":[],"mappings":"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","file":"chunk-7KXGSUHT.js","sourcesContent":["import { getSupabaseClientOptional } from '@fayz-ai/core'\nimport type { ReservationsDataProvider } from './types'\nimport type {\n Reservation, CapacityRule, CapacityException, ReservationSettings,\n DaySlot, ReservationZone, ReservationTable, ReservationStatus,\n CreateReservationInput, ReservationQuery, SeatReservationInput,\n ReservationsSummary, Occasion,\n} from '../types'\n\n// ---------------------------------------------------------------------------\n// Reservations, over the plugin's own schema.\n//\n// public.plg_reservations the reservations\n// public.plg_reservations_capacity_rules the weekly grid\n// public.plg_reservations_capacity_exceptions what overrides it\n// public.plg_reservations_settings the policy\n// public.v_reservations the reservation with names\n// public.reservations_day_capacity(date) the slots of a day\n//\n// The salão is BORROWED, not copied: zones and mesas are plugin-tables' tables.\n// Capacity is per praça for one reason — the V1 keeps them apart\n// (`service_locations` for capacity, `restaurant_sections` for the mesa) and its\n// own document records the consequence: \"nada na tela avisa\", so whoever\n// registered the praças cannot find those names when configuring the lotação.\n// ---------------------------------------------------------------------------\n\nconst RESERVATIONS = 'plg_reservations'\nconst VIEW = 'v_reservations'\nconst RULES = 'plg_reservations_capacity_rules'\nconst EXCEPTIONS = 'plg_reservations_capacity_exceptions'\nconst SETTINGS = 'plg_reservations_settings'\nconst ZONES = 'plg_tables_zones'\nconst TABLES_VIEW = 'v_tables'\n\nexport const DEFAULT_SETTINGS: ReservationSettings = {\n capacityMode: 'no_duration',\n defaultDurationMinutes: 120,\n minAdvanceHours: 24,\n maxAdvanceDays: 90,\n autoConfirm: false,\n requirePhone: true,\n requireEmail: false,\n}\n\nexport interface CoreReservationsWriteOptions {\n /** The active org, stamped on insert. RLS checks it again on the way in. */\n tenantId: () => string | undefined | null\n /**\n * How a seated party becomes a comanda.\n *\n * NOT reimplemented here. Opening a comanda means inserting into\n * `public.orders`, drawing a number off the app's own sequence and writing\n * `plg_tables_order_extensions` — that is plugin-tables' `seatGuests`, and a\n * second copy of it is how two screens start numbering comandas in two\n * series. The app wires its tables provider in; see resto-saas\n * `src/restaurant/reservations.ts`.\n *\n * Absent, seating still moves the status — it just leaves no comanda, and the\n * screen says as much rather than pretending.\n */\n openComanda?: (input: { tableId: string; guests: number; notes?: string }) => Promise<{ orderId?: string }>\n}\n\nexport interface CoreReservationsProviderOptions {\n writes?: CoreReservationsWriteOptions\n}\n\nconst READ_ONLY = 'This provider reads reservations; pass `writes` to let the app that owns it change them.'\n\n/** \"HH:MM:SS\" from Postgres → \"HH:MM\" for a form. Null stays undefined. */\nfunction hhmm(value?: string | null): string | undefined {\n if (!value) return undefined\n return value.slice(0, 5)\n}\n\nexport function createCoreReservationsProvider(\n options?: CoreReservationsProviderOptions,\n): ReservationsDataProvider {\n const db = () => {\n const client = getSupabaseClientOptional() as any\n if (!client) throw new Error('Supabase client is not configured')\n return client\n }\n\n function requireWrites(): CoreReservationsWriteOptions {\n if (!options?.writes) throw new Error(READ_ONLY)\n return options.writes\n }\n\n function tenant(): string {\n const id = requireWrites().tenantId()\n if (!id) throw new Error('No active tenant')\n return id\n }\n\n function rowToReservation(r: any): Reservation {\n return {\n id: r.id,\n personId: r.person_id ?? undefined,\n guestName: r.guest_name,\n phone: r.phone ?? undefined,\n email: r.email ?? undefined,\n zoneId: r.zone_id ?? undefined,\n zoneName: r.zone_name ?? undefined,\n zoneColor: r.zone_color ?? undefined,\n tableId: r.table_id ?? undefined,\n tableNumber: r.table_number ?? undefined,\n reservedOn: r.reserved_on,\n startTime: hhmm(r.start_time) ?? '00:00',\n endTime: hhmm(r.end_time),\n partySize: r.party_size,\n occasion: (r.occasion ?? undefined) as Occasion | undefined,\n notes: r.notes ?? undefined,\n status: r.status as ReservationStatus,\n orderId: r.order_id ?? undefined,\n orderReference: r.order_reference ?? undefined,\n seatedAt: r.seated_at ?? undefined,\n tenantId: r.tenant_id,\n createdAt: r.created_at,\n updatedAt: r.updated_at,\n }\n }\n\n async function byId(id: string): Promise<Reservation> {\n const { data, error } = await db().from(VIEW).select('*').eq('id', id).maybeSingle()\n if (error) throw new Error(error.message)\n if (!data) throw new Error('Reserva não encontrada')\n return rowToReservation(data)\n }\n\n /** The columns a write touches. `undefined` means \"leave alone\"; the caller\n * clears a field by passing null through `Partial`. */\n function toRow(input: Partial<CreateReservationInput>): Record<string, unknown> {\n const row: Record<string, unknown> = {}\n if (input.personId !== undefined) row.person_id = input.personId || null\n if (input.guestName !== undefined) row.guest_name = input.guestName\n if (input.phone !== undefined) row.phone = input.phone || null\n if (input.email !== undefined) row.email = input.email || null\n if (input.zoneId !== undefined) row.zone_id = input.zoneId || null\n if (input.tableId !== undefined) row.table_id = input.tableId || null\n if (input.reservedOn !== undefined) row.reserved_on = input.reservedOn\n if (input.startTime !== undefined) row.start_time = input.startTime\n if (input.endTime !== undefined) row.end_time = input.endTime || null\n if (input.partySize !== undefined) row.party_size = input.partySize\n if (input.occasion !== undefined) row.occasion = input.occasion || null\n if (input.notes !== undefined) row.notes = input.notes || null\n if (input.status !== undefined) row.status = input.status\n return row\n }\n\n return {\n async getReservations(query?: ReservationQuery): Promise<Reservation[]> {\n let q = db().from(VIEW).select('*')\n .order('reserved_on').order('start_time')\n if (query?.from) q = q.gte('reserved_on', query.from)\n if (query?.to) q = q.lte('reserved_on', query.to)\n if (query?.zoneId) q = q.eq('zone_id', query.zoneId)\n if (query?.status) {\n const wanted = Array.isArray(query.status) ? query.status : [query.status]\n q = q.in('status', wanted)\n }\n if (query?.search) {\n // Name OR phone — reception searches by whichever one the caller gave.\n const term = `%${query.search}%`\n q = q.or(`guest_name.ilike.${term},phone.ilike.${term}`)\n }\n const { data, error } = await q\n if (error) throw new Error(error.message)\n return (data ?? []).map(rowToReservation)\n },\n\n async getReservation(id: string): Promise<Reservation | null> {\n const { data, error } = await db().from(VIEW).select('*').eq('id', id).maybeSingle()\n if (error) throw new Error(error.message)\n return data ? rowToReservation(data) : null\n },\n\n async createReservation(input: CreateReservationInput): Promise<Reservation> {\n const tenantId = tenant()\n const { data, error } = await db().from(RESERVATIONS)\n .insert({ ...toRow(input), tenant_id: tenantId })\n .select('id').single()\n if (error) throw new Error(error.message)\n return byId(data.id)\n },\n\n async updateReservation(id: string, data: Partial<CreateReservationInput>): Promise<Reservation> {\n requireWrites()\n const patch = toRow(data)\n if (Object.keys(patch).length) {\n const { error } = await db().from(RESERVATIONS).update(patch).eq('id', id)\n if (error) throw new Error(error.message)\n }\n return byId(id)\n },\n\n async setStatus(id: string, status: ReservationStatus): Promise<Reservation> {\n requireWrites()\n if (status === 'seated') {\n throw new Error('Acomodar abre a comanda — use \"sentar\" em vez de marcar o estado.')\n }\n const { error } = await db().from(RESERVATIONS).update({ status }).eq('id', id)\n if (error) throw new Error(error.message)\n return byId(id)\n },\n\n async deleteReservation(id: string): Promise<void> {\n requireWrites()\n const { error } = await db().from(RESERVATIONS).delete().eq('id', id)\n if (error) throw new Error(error.message)\n },\n\n async seatReservation(input: SeatReservationInput): Promise<Reservation> {\n const writes = requireWrites()\n const reservation = await byId(input.reservationId)\n if (reservation.status === 'seated') throw new Error('Esta reserva já foi acomodada')\n if (reservation.status === 'cancelled') throw new Error('Reserva cancelada não senta')\n\n const guests = input.guests ?? reservation.partySize\n // The comanda first: if it fails, the reservation is untouched and\n // reception tries another mesa. Marking `seated` and then failing to open\n // would leave a party the floor plan cannot see.\n let orderId: string | undefined\n if (writes.openComanda) {\n const opened = await writes.openComanda({\n tableId: input.tableId,\n guests,\n notes: `Reserva · ${reservation.guestName}`,\n })\n orderId = opened.orderId\n }\n\n const { error } = await db().from(RESERVATIONS).update({\n status: 'seated',\n table_id: input.tableId,\n party_size: guests,\n order_id: orderId ?? null,\n seated_at: new Date().toISOString(),\n }).eq('id', input.reservationId)\n if (error) throw new Error(error.message)\n return byId(input.reservationId)\n },\n\n // -- The grid ------------------------------------------------------------\n\n async getDayCapacity(date: string): Promise<DaySlot[]> {\n const { data, error } = await db().rpc('reservations_day_capacity', { p_date: date })\n if (error) throw new Error(error.message)\n return (data ?? []).map((s: any) => ({\n zoneId: s.zone_id ?? undefined,\n zoneName: s.zone_name ?? undefined,\n zoneColor: s.zone_color ?? undefined,\n startTime: hhmm(s.start_time) ?? '00:00',\n endTime: hhmm(s.end_time) ?? '23:59',\n capacity: Number(s.capacity) || 0,\n booked: Number(s.booked) || 0,\n remaining: Number(s.remaining) || 0,\n isException: !!s.is_exception,\n }))\n },\n\n async getCapacityRules(): Promise<CapacityRule[]> {\n const { data, error } = await db().from(RULES)\n .select('*, plg_tables_zones(name)').order('start_time')\n if (error) throw new Error(error.message)\n return (data ?? []).map((r: any) => ({\n id: r.id,\n zoneId: r.zone_id ?? undefined,\n zoneName: r.plg_tables_zones?.name ?? undefined,\n capacity: r.capacity,\n startTime: hhmm(r.start_time) ?? '00:00',\n endTime: hhmm(r.end_time) ?? '23:59',\n weekdays: (r.weekdays ?? []).map(Number),\n durationMinutes: r.duration_minutes ?? undefined,\n isActive: r.is_active !== false,\n tenantId: r.tenant_id,\n }))\n },\n\n async saveCapacityRule(rule): Promise<CapacityRule> {\n const tenantId = tenant()\n const row: Record<string, unknown> = {\n tenant_id: tenantId,\n zone_id: rule.zoneId || null,\n capacity: rule.capacity,\n start_time: rule.startTime,\n end_time: rule.endTime,\n weekdays: rule.weekdays ?? [0, 1, 2, 3, 4, 5, 6],\n duration_minutes: rule.durationMinutes ?? null,\n is_active: rule.isActive !== false,\n }\n const q = rule.id\n ? db().from(RULES).update(row).eq('id', rule.id)\n : db().from(RULES).insert(row)\n const { data, error } = await q.select('id').single()\n if (error) throw new Error(error.message)\n const all = await this.getCapacityRules()\n return all.find((r) => r.id === data.id)!\n },\n\n async deleteCapacityRule(id: string): Promise<void> {\n requireWrites()\n const { error } = await db().from(RULES).delete().eq('id', id)\n if (error) throw new Error(error.message)\n },\n\n async getCapacityExceptions(): Promise<CapacityException[]> {\n const { data, error } = await db().from(EXCEPTIONS)\n .select('*, plg_tables_zones(name)').order('starts_on')\n if (error) throw new Error(error.message)\n return (data ?? []).map((e: any) => ({\n id: e.id,\n zoneId: e.zone_id ?? undefined,\n zoneName: e.plg_tables_zones?.name ?? undefined,\n startsOn: e.starts_on,\n endsOn: e.ends_on,\n startTime: hhmm(e.start_time),\n endTime: hhmm(e.end_time),\n capacity: e.capacity,\n reason: e.reason ?? undefined,\n tenantId: e.tenant_id,\n }))\n },\n\n async saveCapacityException(ex): Promise<CapacityException> {\n const tenantId = tenant()\n const row: Record<string, unknown> = {\n tenant_id: tenantId,\n zone_id: ex.zoneId || null,\n starts_on: ex.startsOn,\n ends_on: ex.endsOn ?? ex.startsOn,\n start_time: ex.startTime || null,\n end_time: ex.endTime || null,\n capacity: ex.capacity ?? 0,\n reason: ex.reason || null,\n }\n const q = ex.id\n ? db().from(EXCEPTIONS).update(row).eq('id', ex.id)\n : db().from(EXCEPTIONS).insert(row)\n const { data, error } = await q.select('id').single()\n if (error) throw new Error(error.message)\n const all = await this.getCapacityExceptions()\n return all.find((e) => e.id === data.id)!\n },\n\n async deleteCapacityException(id: string): Promise<void> {\n requireWrites()\n const { error } = await db().from(EXCEPTIONS).delete().eq('id', id)\n if (error) throw new Error(error.message)\n },\n\n // -- The policy ----------------------------------------------------------\n\n async getSettings(): Promise<ReservationSettings> {\n const { data, error } = await db().from(SETTINGS).select('*').maybeSingle()\n if (error) throw new Error(error.message)\n if (!data) return { ...DEFAULT_SETTINGS }\n return {\n capacityMode: data.capacity_mode,\n defaultDurationMinutes: data.default_duration_minutes,\n minAdvanceHours: data.min_advance_hours,\n maxAdvanceDays: data.max_advance_days,\n autoConfirm: !!data.auto_confirm,\n requirePhone: !!data.require_phone,\n requireEmail: !!data.require_email,\n }\n },\n\n async saveSettings(settings: ReservationSettings): Promise<ReservationSettings> {\n const tenantId = tenant()\n const { error } = await db().from(SETTINGS).upsert({\n tenant_id: tenantId,\n capacity_mode: settings.capacityMode,\n default_duration_minutes: settings.defaultDurationMinutes,\n min_advance_hours: settings.minAdvanceHours,\n max_advance_days: settings.maxAdvanceDays,\n auto_confirm: settings.autoConfirm,\n require_phone: settings.requirePhone,\n require_email: settings.requireEmail,\n }, { onConflict: 'tenant_id' })\n if (error) throw new Error(error.message)\n return settings\n },\n\n // -- The salão, borrowed -------------------------------------------------\n\n async getZones(): Promise<ReservationZone[]> {\n const { data, error } = await db().from(ZONES)\n .select('id, name, color').eq('is_active', true).order('sort_order')\n // A house that has not installed the floor plan yet is not an error: the\n // grid falls back to the restaurant as a whole.\n if (error) return []\n return (data ?? []).map((z: any) => ({ id: z.id, name: z.name, color: z.color ?? undefined }))\n },\n\n async getTables(zoneId?: string): Promise<ReservationTable[]> {\n let q = db().from(TABLES_VIEW).select('id, number, name, seats, zone_id, status').order('number')\n if (zoneId) q = q.eq('zone_id', zoneId)\n const { data, error } = await q\n if (error) return []\n return (data ?? []).map((t: any) => ({\n id: t.id,\n number: t.number,\n name: t.name ?? undefined,\n seats: t.seats ?? 0,\n zoneId: t.zone_id ?? undefined,\n // `occupied` is derived by v_tables from the open comanda — the one\n // fact, read here too rather than guessed from a stored column.\n isOccupied: t.status === 'occupied',\n }))\n },\n\n async getSummary(date: string): Promise<ReservationsSummary> {\n const { data, error } = await db().from(RESERVATIONS)\n .select('status, party_size').eq('reserved_on', date)\n if (error) throw new Error(error.message)\n const rows = data ?? []\n const count = (s: ReservationStatus) => rows.filter((r: any) => r.status === s).length\n return {\n total: rows.length,\n pending: count('pending'),\n confirmed: count('confirmed'),\n seated: count('seated'),\n noShow: count('no_show'),\n cancelled: count('cancelled'),\n // Cancelled and no-show do not eat. This is the number the kitchen\n // plans against, not the row count.\n expectedGuests: rows\n .filter((r: any) => !['cancelled', 'no_show'].includes(r.status))\n .reduce((sum: number, r: any) => sum + (r.party_size ?? 0), 0),\n }\n },\n }\n}\n"]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { DaySlot } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* The day's windows, with what is left in each.
|
|
5
|
+
*
|
|
6
|
+
* THIS IS THE SCREEN THE V1 NEVER MANAGED TO DRAW. With three rules covering
|
|
7
|
+
* all seven weekdays, its "Capacidade do dia" answered *"Nenhuma grade
|
|
8
|
+
* configurada para este dia"* on every date tested (V1-041) — a database error
|
|
9
|
+
* wearing an empty state's clothes. Two consequences shape this component:
|
|
10
|
+
*
|
|
11
|
+
* 1. **An error is not an empty state.** `error` and "no slots" are different
|
|
12
|
+
* props with different words. Someone whose grid is fine must never be told
|
|
13
|
+
* to go configure it again.
|
|
14
|
+
* 2. **The bar is the product.** `12:00–15:00 · 38/50` answers the question
|
|
15
|
+
* reception is actually holding the phone about, and the V1 answers it
|
|
16
|
+
* nowhere — not here, and not in its reservation form either.
|
|
17
|
+
*/
|
|
18
|
+
export declare function CapacityStrip({ slots, loading, error, onPickSlot }: {
|
|
19
|
+
slots: DaySlot[];
|
|
20
|
+
loading?: boolean;
|
|
21
|
+
error?: string | null;
|
|
22
|
+
/** Clicking a window starts a reservation already inside it. */
|
|
23
|
+
onPickSlot?: (slot: DaySlot) => void;
|
|
24
|
+
}): React.JSX.Element;
|
|
25
|
+
//# sourceMappingURL=CapacityStrip.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CapacityStrip.d.ts","sourceRoot":"","sources":["../../src/components/CapacityStrip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAEvC;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE;IACnE,KAAK,EAAE,OAAO,EAAE,CAAA;IAChB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,gEAAgE;IAChE,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;CACrC,qBAqFA"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { Reservation, DaySlot } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* The reservation form.
|
|
5
|
+
*
|
|
6
|
+
* Its one non-obvious job is the line under the time: the window this
|
|
7
|
+
* reservation would fall into, and what is left in it AFTER this party. The V1
|
|
8
|
+
* has this same form and — verified with a network spy — *"abrir e preencher
|
|
9
|
+
* Nova reserva não disparou nenhuma chamada à `get_reservation_availability`"*:
|
|
10
|
+
* whoever is on the phone decides blind. Everything else here is the V1's field
|
|
11
|
+
* list, in the V1's order.
|
|
12
|
+
*/
|
|
13
|
+
export declare function ReservationModal({ open, onClose, date, reservation, defaultSlot }: {
|
|
14
|
+
open: boolean;
|
|
15
|
+
onClose: () => void;
|
|
16
|
+
/** The day the screen is on, used when creating. */
|
|
17
|
+
date: string;
|
|
18
|
+
/** Editing an existing one. */
|
|
19
|
+
reservation?: Reservation | null;
|
|
20
|
+
/** Clicking a window on the capacity strip pre-fills the time and the zone. */
|
|
21
|
+
defaultSlot?: DaySlot | null;
|
|
22
|
+
}): React.JSX.Element;
|
|
23
|
+
//# sourceMappingURL=ReservationModal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReservationModal.d.ts","sourceRoot":"","sources":["../../src/components/ReservationModal.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAuC,MAAM,OAAO,CAAA;AAS3D,OAAO,KAAK,EAAE,WAAW,EAA0B,OAAO,EAAY,MAAM,UAAU,CAAA;AAmBtF;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,EAAE;IAClF,IAAI,EAAE,OAAO,CAAA;IACb,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAA;IACZ,+BAA+B;IAC/B,WAAW,CAAC,EAAE,WAAW,GAAG,IAAI,CAAA;IAChC,+EAA+E;IAC/E,WAAW,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;CAC7B,qBAwSA"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { Reservation } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* "Chegaram" — the click that turns a reservation into a comanda.
|
|
5
|
+
*
|
|
6
|
+
* In the V1, *Acomodada* is only a status: the night's reservations leave no
|
|
7
|
+
* trace in its money, and its Operação panel counts comandas that never knew a
|
|
8
|
+
* reservation happened. Here this dialog picks the mesa, and seating opens the
|
|
9
|
+
* comanda on it through plugin-tables — one path from the phone call to the
|
|
10
|
+
* bill.
|
|
11
|
+
*/
|
|
12
|
+
export declare function SeatDialog({ reservation, onClose }: {
|
|
13
|
+
reservation: Reservation | null;
|
|
14
|
+
onClose: () => void;
|
|
15
|
+
}): React.JSX.Element | null;
|
|
16
|
+
//# sourceMappingURL=SeatDialog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SeatDialog.d.ts","sourceRoot":"","sources":["../../src/components/SeatDialog.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAA;AAOvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAE3C;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE;IACnD,WAAW,EAAE,WAAW,GAAG,IAAI,CAAA;IAC/B,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB,4BA8GA"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { type EntityLookup } from '@fayz-ai/admin';
|
|
2
|
+
import type { EntityDef } from '@fayz-ai/core';
|
|
3
|
+
import type { ReservationsDataProvider } from './data/types';
|
|
4
|
+
import type { ReservationsUIState } from './store';
|
|
5
|
+
import type { ReservationStatus, Occasion } from './types';
|
|
6
|
+
export interface ReservationsPluginLabels {
|
|
7
|
+
pageTitle: string;
|
|
8
|
+
pageSubtitle: string;
|
|
9
|
+
newReservation: string;
|
|
10
|
+
}
|
|
11
|
+
/** A state, with the word and the colour the house shows for it. Same shape as
|
|
12
|
+
* the agenda's status list on purpose: both feed `DotBadge` from @fayz-ai/ui,
|
|
13
|
+
* which is the piece the two screens genuinely share. */
|
|
14
|
+
export interface ReservationStatusOption {
|
|
15
|
+
value: ReservationStatus;
|
|
16
|
+
label: string;
|
|
17
|
+
color: string;
|
|
18
|
+
}
|
|
19
|
+
export interface OccasionOption {
|
|
20
|
+
value: Occasion;
|
|
21
|
+
label: string;
|
|
22
|
+
}
|
|
23
|
+
export interface ResolvedReservationsConfig {
|
|
24
|
+
labels: ReservationsPluginLabels;
|
|
25
|
+
statuses: ReservationStatusOption[];
|
|
26
|
+
occasions: OccasionOption[];
|
|
27
|
+
/** How the day is drawn when the house has no grid yet — the first and last
|
|
28
|
+
* hour of the strip. Not a rule: purely how wide the empty ruler is. */
|
|
29
|
+
dayWindow: {
|
|
30
|
+
start: string;
|
|
31
|
+
end: string;
|
|
32
|
+
};
|
|
33
|
+
/** O `people.kind` que a busca varre, para a casa so ver a gente dela. */
|
|
34
|
+
clientKind: string;
|
|
35
|
+
/** Busca propria, quando o app tem uma. */
|
|
36
|
+
contactLookup?: EntityLookup;
|
|
37
|
+
/** O que o "+ Cadastrar" escreve — a entidade que a pagina de cadastro usa. */
|
|
38
|
+
clientEntityDef?: EntityDef;
|
|
39
|
+
}
|
|
40
|
+
export declare const ReservationsContextProvider: import("react").FC<{
|
|
41
|
+
config: ResolvedReservationsConfig;
|
|
42
|
+
provider: ReservationsDataProvider;
|
|
43
|
+
store: import("zustand").StoreApi<ReservationsUIState>;
|
|
44
|
+
children?: React.ReactNode;
|
|
45
|
+
}>;
|
|
46
|
+
export declare const useReservationsConfig: () => ResolvedReservationsConfig;
|
|
47
|
+
export declare const useReservationsProvider: () => ReservationsDataProvider;
|
|
48
|
+
export declare const useReservationsStore: <T>(selector: (state: ReservationsUIState) => T) => T;
|
|
49
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAA;AACvE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AAC9C,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAA;AAC5D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAM1D,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,MAAM,CAAA;IACpB,cAAc,EAAE,MAAM,CAAA;CACvB;AAED;;0DAE0D;AAC1D,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,iBAAiB,CAAA;IACxB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,QAAQ,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,0BAA0B;IACzC,MAAM,EAAE,wBAAwB,CAAA;IAChC,QAAQ,EAAE,uBAAuB,EAAE,CAAA;IACnC,SAAS,EAAE,cAAc,EAAE,CAAA;IAC3B;6EACyE;IACzE,SAAS,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;IAgBzC,0EAA0E;IAC1E,UAAU,EAAE,MAAM,CAAA;IAClB,2CAA2C;IAC3C,aAAa,CAAC,EAAE,YAAY,CAAA;IAC5B,+EAA+E;IAC/E,eAAe,CAAC,EAAE,SAAS,CAAA;CAC5B;AAID,eAAO,MAAM,2BAA2B;;;;;EAAsB,CAAA;AAC9D,eAAO,MAAM,qBAAqB,kCAAgB,CAAA;AAClD,eAAO,MAAM,uBAAuB,gCAAkB,CAAA;AACtD,eAAO,MAAM,oBAAoB,uDAAe,CAAA"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ReservationsDataProvider } from './types';
|
|
2
|
+
import type { ReservationSettings } from '../types';
|
|
3
|
+
export declare const DEFAULT_SETTINGS: ReservationSettings;
|
|
4
|
+
export interface CoreReservationsWriteOptions {
|
|
5
|
+
/** The active org, stamped on insert. RLS checks it again on the way in. */
|
|
6
|
+
tenantId: () => string | undefined | null;
|
|
7
|
+
/**
|
|
8
|
+
* How a seated party becomes a comanda.
|
|
9
|
+
*
|
|
10
|
+
* NOT reimplemented here. Opening a comanda means inserting into
|
|
11
|
+
* `public.orders`, drawing a number off the app's own sequence and writing
|
|
12
|
+
* `plg_tables_order_extensions` — that is plugin-tables' `seatGuests`, and a
|
|
13
|
+
* second copy of it is how two screens start numbering comandas in two
|
|
14
|
+
* series. The app wires its tables provider in; see resto-saas
|
|
15
|
+
* `src/restaurant/reservations.ts`.
|
|
16
|
+
*
|
|
17
|
+
* Absent, seating still moves the status — it just leaves no comanda, and the
|
|
18
|
+
* screen says as much rather than pretending.
|
|
19
|
+
*/
|
|
20
|
+
openComanda?: (input: {
|
|
21
|
+
tableId: string;
|
|
22
|
+
guests: number;
|
|
23
|
+
notes?: string;
|
|
24
|
+
}) => Promise<{
|
|
25
|
+
orderId?: string;
|
|
26
|
+
}>;
|
|
27
|
+
}
|
|
28
|
+
export interface CoreReservationsProviderOptions {
|
|
29
|
+
writes?: CoreReservationsWriteOptions;
|
|
30
|
+
}
|
|
31
|
+
export declare function createCoreReservationsProvider(options?: CoreReservationsProviderOptions): ReservationsDataProvider;
|
|
32
|
+
//# sourceMappingURL=core-supabase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core-supabase.d.ts","sourceRoot":"","sources":["../../src/data/core-supabase.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAA;AACvD,OAAO,KAAK,EACoC,mBAAmB,EAIlE,MAAM,UAAU,CAAA;AA2BjB,eAAO,MAAM,gBAAgB,EAAE,mBAQ9B,CAAA;AAED,MAAM,WAAW,4BAA4B;IAC3C,4EAA4E;IAC5E,QAAQ,EAAE,MAAM,MAAM,GAAG,SAAS,GAAG,IAAI,CAAA;IACzC;;;;;;;;;;;;OAYG;IACH,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC;QAAE,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAC5G;AAED,MAAM,WAAW,+BAA+B;IAC9C,MAAM,CAAC,EAAE,4BAA4B,CAAA;CACtC;AAUD,wBAAgB,8BAA8B,CAC5C,OAAO,CAAC,EAAE,+BAA+B,GACxC,wBAAwB,CAoW1B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock.d.ts","sourceRoot":"","sources":["../../src/data/mock.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAA;AA6DvD,wBAAgB,8BAA8B,IAAI,wBAAwB,CAyKzE"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Reservation, CapacityRule, CapacityException, ReservationSettings, DaySlot, ReservationZone, ReservationTable, CreateReservationInput, ReservationQuery, SeatReservationInput, ReservationsSummary } from '../types';
|
|
2
|
+
export interface ReservationsDataProvider {
|
|
3
|
+
getReservations(query?: ReservationQuery): Promise<Reservation[]>;
|
|
4
|
+
getReservation(id: string): Promise<Reservation | null>;
|
|
5
|
+
createReservation(input: CreateReservationInput): Promise<Reservation>;
|
|
6
|
+
updateReservation(id: string, data: Partial<CreateReservationInput>): Promise<Reservation>;
|
|
7
|
+
setStatus(id: string, status: Reservation['status']): Promise<Reservation>;
|
|
8
|
+
deleteReservation(id: string): Promise<void>;
|
|
9
|
+
/**
|
|
10
|
+
* The party arrived and sat down.
|
|
11
|
+
*
|
|
12
|
+
* A single call because it is a single decision with two effects: the
|
|
13
|
+
* reservation becomes `seated` AND a comanda opens on the mesa. The V1 does
|
|
14
|
+
* only the first, which is why a night of reservations leaves no trace in its
|
|
15
|
+
* money. A provider that cannot open a comanda still satisfies this — it
|
|
16
|
+
* moves the status and leaves `orderId` empty, and the screen says so.
|
|
17
|
+
*/
|
|
18
|
+
seatReservation(input: SeatReservationInput): Promise<Reservation>;
|
|
19
|
+
/** One row per zone × window that applies to this date, with what is left. */
|
|
20
|
+
getDayCapacity(date: string): Promise<DaySlot[]>;
|
|
21
|
+
getCapacityRules(): Promise<CapacityRule[]>;
|
|
22
|
+
saveCapacityRule(rule: Partial<CapacityRule> & {
|
|
23
|
+
id?: string;
|
|
24
|
+
}): Promise<CapacityRule>;
|
|
25
|
+
deleteCapacityRule(id: string): Promise<void>;
|
|
26
|
+
getCapacityExceptions(): Promise<CapacityException[]>;
|
|
27
|
+
saveCapacityException(ex: Partial<CapacityException> & {
|
|
28
|
+
id?: string;
|
|
29
|
+
}): Promise<CapacityException>;
|
|
30
|
+
deleteCapacityException(id: string): Promise<void>;
|
|
31
|
+
getSettings(): Promise<ReservationSettings>;
|
|
32
|
+
saveSettings(settings: ReservationSettings): Promise<ReservationSettings>;
|
|
33
|
+
getZones(): Promise<ReservationZone[]>;
|
|
34
|
+
getTables(zoneId?: string): Promise<ReservationTable[]>;
|
|
35
|
+
getSummary(date: string): Promise<ReservationsSummary>;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/data/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EAAE,YAAY,EAAE,iBAAiB,EAAE,mBAAmB,EACjE,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAC1C,sBAAsB,EAAE,gBAAgB,EAAE,oBAAoB,EAC9D,mBAAmB,EACpB,MAAM,UAAU,CAAA;AAEjB,MAAM,WAAW,wBAAwB;IAEvC,eAAe,CAAC,KAAK,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAAA;IACjE,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAA;IACvD,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,WAAW,CAAC,CAAA;IACtE,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,sBAAsB,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAA;IAC1F,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAA;IAC1E,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAE5C;;;;;;;;OAQG;IACH,eAAe,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,WAAW,CAAC,CAAA;IAGlE,8EAA8E;IAC9E,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;IAChD,gBAAgB,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAAA;IAC3C,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG;QAAE,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;IACtF,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC7C,qBAAqB,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAA;IACrD,qBAAqB,CAAC,EAAE,EAAE,OAAO,CAAC,iBAAiB,CAAC,GAAG;QAAE,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAA;IACnG,uBAAuB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAGlD,WAAW,IAAI,OAAO,CAAC,mBAAmB,CAAC,CAAA;IAC3C,YAAY,CAAC,QAAQ,EAAE,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAA;IAQzE,QAAQ,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAAA;IACtC,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAA;IAGvD,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAA;CACvD"}
|