@oneclick.dev/cms-core-modules 0.0.117 → 0.0.118

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.
@@ -0,0 +1,1258 @@
1
+ import { defineComponent as ae, resolveComponent as F, openBlock as s, createElementBlock as d, createElementVNode as e, Fragment as G, renderList as te, toDisplayString as g, normalizeStyle as se, normalizeClass as Q, createVNode as u, withCtx as M, unref as w, createTextVNode as le, createCommentVNode as B, computed as R, ref as D, createBlock as Z, nextTick as ve, provide as ne, onMounted as $e, onUnmounted as Te, inject as de, onBeforeUnmount as Ae, watch as ue, useTemplateRef as ze } from "vue";
2
+ import { a as ce, b as me } from "./DateFormatter-BkKoSf_l.mjs";
3
+ import { X as De, Search as Ee, Clock as he, Users as xe, ChevronLeft as ge, ChevronRight as fe, Asterisk as Be, CalendarDays as Pe } from "lucide-vue-next";
4
+ import { _ as je } from "./EditLayout.vue_vue_type_script_setup_true_lang-pDO9b4Pv.mjs";
5
+ import { useModuleRoute as ye, useModule as be, useFirebaseIntegration as _e, useModulePermissions as Oe } from "@oneclick.dev/cms-kit";
6
+ import { u as Re, _ as Le, a as Ue, b as Ne, F as Fe } from "./OrderDetailDialog.vue_vue_type_script_setup_true_lang-DwAUYR8p.mjs";
7
+ import { _ as Ve } from "./_plugin-vue_export-helper-CHgC5LLL.mjs";
8
+ import { _ as He } from "./NewReservationDialog.vue_vue_type_script_setup_true_lang-BXTkYCm_.mjs";
9
+ import { a as Qe } from "./index-hMp4p5qA.mjs";
10
+ const We = { class: "mb-6" }, qe = { class: "flex items-end gap-px h-24 bg-muted/30 rounded-lg p-2 overflow-visible" }, Xe = ["onClick"], Ye = { class: "absolute -top-8 left-1/2 -translate-x-1/2 bg-popover border shadow-md rounded px-2 py-1 text-xs whitespace-nowrap opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none z-10" }, Je = { class: "font-medium" }, Ke = { class: "text-muted-foreground" }, Ge = { class: "w-full flex-1 flex items-end justify-center" }, Ze = {
11
+ key: 1,
12
+ class: "text-[10px] mt-1"
13
+ }, et = {
14
+ key: 0,
15
+ class: "mt-2 text-sm text-muted-foreground flex items-center gap-2"
16
+ }, tt = { class: "font-medium text-foreground" }, st = { class: "font-medium text-foreground" }, ot = /* @__PURE__ */ ae({
17
+ __name: "TimelineChart",
18
+ props: {
19
+ timeSlots: {},
20
+ slotStats: {},
21
+ selectedTimeSlot: {},
22
+ maxSpots: {}
23
+ },
24
+ emits: ["select", "clear"],
25
+ setup(f, { emit: T }) {
26
+ const _ = T, A = (o) => {
27
+ _("select", o);
28
+ }, L = () => {
29
+ _("clear");
30
+ };
31
+ return (o, c) => {
32
+ const m = F("Button");
33
+ return s(), d("div", We, [
34
+ c[2] || (c[2] = e("h3", { class: "font-semibold text-sm mb-2" }, "Timeline", -1)),
35
+ e("div", qe, [
36
+ (s(!0), d(G, null, te(f.timeSlots, (a) => (s(), d("div", {
37
+ key: a.startTime,
38
+ class: "flex-1 min-w-0 flex flex-col items-center cursor-pointer group h-full relative",
39
+ onClick: (k) => A(a.startTime)
40
+ }, [
41
+ e("div", Ye, [
42
+ e("div", Je, g(a.startTime), 1),
43
+ e("div", Ke, g(f.slotStats[a.startTime]?.spots || 0) + " spots", 1)
44
+ ]),
45
+ e("div", Ge, [
46
+ e("div", {
47
+ class: Q(["w-full transition-all duration-200", [
48
+ f.selectedTimeSlot === a.startTime ? "bg-primary" : f.slotStats[a.startTime]?.spots > 0 ? "bg-primary/60 group-hover:bg-primary/80" : "bg-muted-foreground/20 group-hover:bg-muted-foreground/30"
49
+ ]]),
50
+ style: se({
51
+ height: f.slotStats[a.startTime]?.spots > 0 ? `${f.slotStats[a.startTime].spots / f.maxSpots * 100}%` : "2px",
52
+ minHeight: f.slotStats[a.startTime]?.spots > 0 ? "4px" : "2px"
53
+ })
54
+ }, null, 6)
55
+ ]),
56
+ a.startTime.endsWith(":00") ? (s(), d("span", {
57
+ key: 0,
58
+ class: Q(["text-[10px] text-muted-foreground mt-1 transition-colors truncate", { "text-primary font-medium": f.selectedTimeSlot === a.startTime }])
59
+ }, g(a.label), 3)) : (s(), d("span", Ze, " "))
60
+ ], 8, Xe))), 128))
61
+ ]),
62
+ f.selectedTimeSlot ? (s(), d("div", et, [
63
+ u(m, {
64
+ variant: "ghost",
65
+ size: "icon",
66
+ class: "h-6 w-6 p-0",
67
+ onClick: L
68
+ }, {
69
+ default: M(() => [
70
+ u(w(De), { size: 14 })
71
+ ]),
72
+ _: 1
73
+ }),
74
+ e("span", null, [
75
+ c[0] || (c[0] = le(" Showing ", -1)),
76
+ e("span", tt, g(f.slotStats[f.selectedTimeSlot]?.bookings || 0), 1),
77
+ c[1] || (c[1] = le(" bookings at ", -1)),
78
+ e("span", st, g(f.selectedTimeSlot), 1)
79
+ ])
80
+ ])) : B("", !0)
81
+ ]);
82
+ };
83
+ }
84
+ }), at = { class: "flex items-center justify-between mb-3" }, nt = { class: "font-semibold" }, rt = {
85
+ key: 0,
86
+ class: "text-muted-foreground font-normal"
87
+ }, lt = { class: "relative mb-3" }, it = {
88
+ key: 0,
89
+ class: "flex items-center justify-center py-8"
90
+ }, ut = {
91
+ key: 1,
92
+ class: "text-center py-8 text-muted-foreground"
93
+ }, dt = {
94
+ key: 2,
95
+ class: "space-y-2 max-h-80 overflow-y-auto"
96
+ }, ct = ["onClick"], mt = { class: "flex items-start justify-between" }, ft = { class: "flex-1" }, pt = { class: "font-medium" }, vt = { class: "text-sm text-muted-foreground" }, gt = { class: "text-sm text-muted-foreground" }, ht = { class: "flex items-center gap-4" }, xt = { class: "flex items-center gap-2 mt-1 text-xs text-muted-foreground" }, yt = { class: "flex items-center gap-2 mt-1 text-xs text-muted-foreground" }, bt = { class: "text-right" }, _t = {
97
+ key: 0,
98
+ class: "inline-block px-2 py-1 text-xs rounded-full bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-400"
99
+ }, kt = {
100
+ key: 1,
101
+ class: "inline-block px-2 py-1 text-xs rounded-full bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400"
102
+ }, wt = {
103
+ key: 2,
104
+ class: "inline-block px-2 py-1 text-xs rounded-full bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-400"
105
+ }, St = {
106
+ key: 3,
107
+ class: "inline-block px-2 py-1 text-xs rounded-full bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-400"
108
+ }, $t = {
109
+ key: 4,
110
+ class: "inline-block px-2 py-1 text-xs rounded-full bg-yellow-100 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-400"
111
+ }, Tt = {
112
+ key: 5,
113
+ class: "text-sm font-medium mt-1"
114
+ }, Dt = /* @__PURE__ */ ae({
115
+ __name: "BookingsList",
116
+ props: {
117
+ agendaData: {},
118
+ resources: {},
119
+ orders: {},
120
+ filteredOrders: {},
121
+ isLoading: { type: Boolean },
122
+ selectedTimeSlot: {},
123
+ searchQuery: {}
124
+ },
125
+ emits: ["update:searchQuery", "refresh"],
126
+ setup(f, { emit: T }) {
127
+ const _ = f, { params: A } = ye(), L = R(() => A.value?.id ?? A.id ?? _.agendaData?.id ?? ""), { metadataSchema: o } = Re(L), c = R(() => {
128
+ const v = Array.isArray(_.resources) ? _.resources : [], p = Array.isArray(_.agendaData?.resources) ? _.agendaData.resources : [], E = [...v, ...p], l = /* @__PURE__ */ new Set();
129
+ return E.filter((t) => {
130
+ const n = t?.id;
131
+ return !n || l.has(String(n)) ? !1 : (l.add(String(n)), !0);
132
+ });
133
+ }), m = T, { config: a } = be(), k = _e(a.project), x = D(null), N = D(null), P = (v) => {
134
+ m("update:searchQuery", v);
135
+ }, C = () => {
136
+ m("update:searchQuery", "");
137
+ }, V = () => {
138
+ m("refresh");
139
+ }, j = (v, p) => {
140
+ const E = v.id || v.orderId || p.orderId || "", l = c.value.find((t) => String(t.id) === String(p.resourceId));
141
+ return {
142
+ customerInfo: v.customerInfo,
143
+ amountDue: v.amountDue,
144
+ amountPaid: v.amountPaid,
145
+ status: v.status,
146
+ reservationStatus: p.status,
147
+ subtotal: v.subtotal,
148
+ total: v.total,
149
+ discount: v.discount,
150
+ id: E,
151
+ res_id: p.id,
152
+ resourceId: p.resourceId,
153
+ spots: p.spots,
154
+ date: p.date,
155
+ createdAt: v.createdAt,
156
+ startTime: p.timeslot?.startTime,
157
+ endTime: p.timeslot?.endTime,
158
+ reservationPrice: p.totalPrice,
159
+ reservationBasePrice: p.basePrice,
160
+ reservationAddOnsPrice: p.addOnsPrice,
161
+ orderReservationCount: Array.isArray(v.reservations) ? v.reservations.length : void 0,
162
+ adjustments: v.adjustments || [],
163
+ reservationAdjustments: p.adjustments || [],
164
+ pricingOptionId: p.pricingOptionId,
165
+ pricingOption: p.pricingOption,
166
+ resourceName: l?.name,
167
+ resourceColor: l?.color,
168
+ metadata: v.metadata || {},
169
+ reservationMetadata: p.metadata || {},
170
+ refundStatus: p.refundStatus,
171
+ refundedAt: p.refundedAt,
172
+ refundedAmount: p.refundedAmount,
173
+ refunds: Array.isArray(p.refunds) ? p.refunds : []
174
+ };
175
+ }, O = async () => {
176
+ await ve(), await new Promise((v) => {
177
+ if (typeof requestAnimationFrame == "function") {
178
+ requestAnimationFrame(() => v());
179
+ return;
180
+ }
181
+ v();
182
+ });
183
+ }, H = async (v) => {
184
+ if (!v) return;
185
+ const p = await k.get(a.reservationsCollection, v);
186
+ if (!p) return;
187
+ const E = { ...p, id: p.id || v }, l = (E.reservations || []).map((t) => j(E, t));
188
+ l.length && (await O(), N.value?.openDialog({
189
+ id: E.id,
190
+ customerInfo: E.customerInfo,
191
+ status: E.status,
192
+ createdAt: E.createdAt,
193
+ metadata: E.metadata || {},
194
+ reservations: l,
195
+ adjustments: E.adjustments || [],
196
+ totalPrice: typeof E.total == "number" ? E.total : l.reduce((t, n) => t + (n.reservationPrice || 0), 0),
197
+ totalSpots: l.reduce((t, n) => t + (n.spots || 0), 0)
198
+ }));
199
+ }, oe = async (v) => {
200
+ await O(), x.value?.openDialog(v);
201
+ }, Y = (v) => v.orderReservationCount === 1 && typeof v.total == "number" ? v.total : typeof v.reservationPrice == "number" ? v.reservationPrice : null, ee = (v) => {
202
+ const p = Y(v);
203
+ return p === null ? null : `€${p.toFixed(2)}`;
204
+ };
205
+ return (v, p) => {
206
+ const E = F("Input"), l = F("Button");
207
+ return s(), d("div", null, [
208
+ e("div", at, [
209
+ e("h3", nt, [
210
+ p[2] || (p[2] = le(" Bookings ", -1)),
211
+ f.selectedTimeSlot || f.searchQuery ? (s(), d("span", rt, " (" + g(f.filteredOrders.length) + " of " + g(f.orders.length) + ") ", 1)) : B("", !0)
212
+ ])
213
+ ]),
214
+ e("div", lt, [
215
+ u(w(Ee), {
216
+ size: 16,
217
+ class: "absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground"
218
+ }),
219
+ u(E, {
220
+ "model-value": f.searchQuery,
221
+ placeholder: "Search by name, email, or phone...",
222
+ class: "pl-9 pr-9",
223
+ "onUpdate:modelValue": P
224
+ }, null, 8, ["model-value"]),
225
+ f.searchQuery ? (s(), Z(l, {
226
+ key: 0,
227
+ variant: "ghost",
228
+ size: "icon",
229
+ class: "absolute right-1 top-1/2 -translate-y-1/2 h-7 w-7",
230
+ onClick: C
231
+ }, {
232
+ default: M(() => [
233
+ u(w(De), { size: 14 })
234
+ ]),
235
+ _: 1
236
+ })) : B("", !0)
237
+ ]),
238
+ f.isLoading ? (s(), d("div", it, [...p[3] || (p[3] = [
239
+ e("div", { class: "animate-spin rounded-full h-8 w-8 border-b-2 border-primary" }, null, -1)
240
+ ])])) : f.filteredOrders.length === 0 ? (s(), d("div", ut, g(f.selectedTimeSlot ? "No bookings for this time slot" : "No bookings for this event"), 1)) : (s(), d("div", dt, [
241
+ (s(!0), d(G, null, te(f.filteredOrders, (t) => (s(), d("div", {
242
+ key: t.res_id || t.id,
243
+ class: "p-3 border rounded-lg hover:bg-muted/50 transition-colors",
244
+ onClick: (n) => x.value?.openDialog(t)
245
+ }, [
246
+ e("div", mt, [
247
+ e("div", ft, [
248
+ e("div", pt, g(t.customerInfo.firstName + " " + t.customerInfo.lastName || "Unknown Customer"), 1),
249
+ e("div", vt, g(t.customerInfo.email), 1),
250
+ e("div", gt, g(t.customerInfo.phone), 1),
251
+ e("div", ht, [
252
+ e("div", xt, [
253
+ u(w(he), { size: 12 }),
254
+ e("span", null, g(t.startTime) + " - " + g(t.endTime), 1)
255
+ ]),
256
+ e("div", yt, [
257
+ u(w(xe), { size: 12 }),
258
+ e("span", null, g(t.spots), 1)
259
+ ])
260
+ ]),
261
+ u(Le, {
262
+ metadata: { ...t.metadata, ...t.reservationMetadata },
263
+ schema: w(o),
264
+ "display-filter": ["highlight", "badge"],
265
+ compact: "",
266
+ class: "mt-1"
267
+ }, null, 8, ["metadata", "schema"])
268
+ ]),
269
+ e("div", bt, [
270
+ t.reservationStatus === "needs_approval" ? (s(), d("span", _t, "Needs Approval")) : t.reservationStatus === "approved" ? (s(), d("span", kt, "Approved")) : t.reservationStatus === "rejected" ? (s(), d("span", wt, "Rejected")) : t.reservationStatus === "cancelled" ? (s(), d("span", St, "Cancelled")) : (s(), d("span", $t, "Pending")),
271
+ ee(t) ? (s(), d("div", Tt, g(ee(t)), 1)) : B("", !0)
272
+ ])
273
+ ])
274
+ ], 8, ct))), 128))
275
+ ])),
276
+ u(Ue, {
277
+ ref_key: "reservationDetailDialog",
278
+ ref: x,
279
+ "agenda-data": f.agendaData,
280
+ resources: f.resources,
281
+ "show-order-link": "",
282
+ onCancelled: V,
283
+ onConfirmed: V,
284
+ onRejected: V,
285
+ onTransferred: V,
286
+ onOpenOrder: p[0] || (p[0] = (t) => H(t))
287
+ }, null, 8, ["agenda-data", "resources"]),
288
+ u(Ne, {
289
+ ref_key: "orderDetailDialog",
290
+ ref: N,
291
+ "agenda-data": f.agendaData,
292
+ resources: f.resources,
293
+ onOpenReservation: p[1] || (p[1] = (t) => oe(t))
294
+ }, null, 8, ["agenda-data", "resources"])
295
+ ]);
296
+ };
297
+ }
298
+ }), Ct = { class: "flex items-center gap-4 mt-2 text-sm" }, It = { class: "flex items-center gap-1" }, Mt = {
299
+ key: 0,
300
+ class: "flex items-center gap-1"
301
+ }, At = { class: "flex items-center gap-1" }, zt = { class: "py-4" }, Et = /* @__PURE__ */ ae({
302
+ __name: "EventDialog",
303
+ props: {
304
+ agendaData: {},
305
+ resources: { default: () => [] }
306
+ },
307
+ setup(f, { expose: T }) {
308
+ const _ = f, { config: A } = be(), { params: L } = ye(), o = _e(A.project), c = D(!1), m = D(null), a = D([]), k = D(!1), x = D(null), N = D("");
309
+ ne("event", m);
310
+ const P = R(() => {
311
+ if (!m.value) return [];
312
+ const l = m.value.resource?.interval || 60, t = [], [n, I] = m.value.startTime.split(":").map(Number), [X, q] = m.value.endTime.split(":").map(Number), S = n * 60 + I, $ = X * 60 + q;
313
+ for (let y = S; y < $; y += l) {
314
+ const i = Math.floor(y / 60), h = y % 60, z = Math.min(y + l, $), b = Math.floor(z / 60), U = z % 60, W = `${i.toString().padStart(2, "0")}:${h.toString().padStart(2, "0")}`, r = `${b.toString().padStart(2, "0")}:${U.toString().padStart(2, "0")}`;
315
+ t.push({
316
+ startTime: W,
317
+ endTime: r,
318
+ label: W
319
+ });
320
+ }
321
+ return t;
322
+ }), C = (l) => {
323
+ const t = l.getFullYear(), n = String(l.getMonth() + 1).padStart(2, "0"), I = String(l.getDate()).padStart(2, "0");
324
+ return `${t}-${n}-${I}`;
325
+ }, V = R(() => {
326
+ const l = {};
327
+ return P.value.forEach((t) => {
328
+ l[t.startTime] = { bookings: 0, spots: 0, orders: [] };
329
+ }), a.value.forEach((t) => {
330
+ P.value.forEach((n) => {
331
+ t.startTime < n.endTime && t.endTime > n.startTime && (l[n.startTime].bookings++, l[n.startTime].spots += t.spots || 0, l[n.startTime].orders.push(t));
332
+ });
333
+ }), l;
334
+ }), j = R(() => Math.max(1, ...Object.values(V.value).map((l) => l.spots))), O = R(() => {
335
+ let l = a.value;
336
+ return x.value && (l = V.value[x.value]?.orders || []), N.value.trim() && (l = new Fe(l, {
337
+ keys: [
338
+ "customerInfo.firstName",
339
+ "customerInfo.lastName",
340
+ "customerInfo.email",
341
+ "customerInfo.phone"
342
+ ],
343
+ threshold: 0.3,
344
+ ignoreLocation: !0
345
+ }).search(N.value).map((n) => n.item)), l;
346
+ }), H = R(() => ({
347
+ spots: a.value.reduce((l, t) => l + (t.spots || 0), 0),
348
+ bookings: a.value.length
349
+ })), oe = (l) => {
350
+ x.value === l ? x.value = null : x.value = l;
351
+ }, Y = () => {
352
+ x.value = null;
353
+ }, ee = async (l) => {
354
+ c.value = !0, m.value = l, x.value = null, N.value = "", await v();
355
+ }, v = async () => {
356
+ if (m.value) {
357
+ k.value = !0, a.value = [];
358
+ try {
359
+ const l = L.value.id, t = C(new Date(m.value.date)), n = m.value.resourceId || m.value.resource?.id, I = /* @__PURE__ */ new Set();
360
+ if (n ? I.add(`${n}_${t}`) : _.resources?.forEach((S) => {
361
+ I.add(`${S.id}_${t}`);
362
+ }), I.size === 0) {
363
+ a.value = [];
364
+ return;
365
+ }
366
+ const X = await o.find(A.reservationsCollection, {
367
+ filters: [
368
+ { field: "agendaId", operator: "==", value: l },
369
+ { field: "status", operator: "==", value: "confirmed" },
370
+ { field: "flattenedReservationDates", operator: "array-contains-any", value: Array.from(I) }
371
+ ]
372
+ });
373
+ let q = [];
374
+ X.forEach((S) => {
375
+ (S.reservations?.filter((y) => y.date !== t ? !1 : n ? y.resourceId === n : !0) || []).forEach((y) => {
376
+ const i = _.resources.find((z) => z.id === y.resourceId), h = S.id || S.orderId || y.orderId || "";
377
+ (y.status === "approved" || y.status === "needs_approval") && q.push({
378
+ customerInfo: S.customerInfo,
379
+ amountDue: S.amountDue,
380
+ amountPaid: S.amountPaid,
381
+ status: S.status,
382
+ reservationStatus: y.status,
383
+ subtotal: S.subtotal,
384
+ total: S.total,
385
+ discount: S.discount,
386
+ id: h,
387
+ res_id: y.id,
388
+ resourceId: y.resourceId,
389
+ spots: y.spots,
390
+ date: t,
391
+ createdAt: S.createdAt,
392
+ startTime: y.timeslot?.startTime,
393
+ endTime: y.timeslot?.endTime,
394
+ reservationPrice: y.totalPrice,
395
+ reservationBasePrice: y.basePrice,
396
+ reservationAddOnsPrice: y.addOnsPrice,
397
+ orderReservationCount: Array.isArray(S.reservations) ? S.reservations.length : void 0,
398
+ adjustments: S.adjustments || [],
399
+ reservationAdjustments: y.adjustments || [],
400
+ pricingOptionId: y.pricingOptionId,
401
+ pricingOption: y.pricingOption,
402
+ resourceName: i?.name,
403
+ resourceColor: i?.color,
404
+ metadata: S.metadata || {},
405
+ reservationMetadata: y.metadata || {},
406
+ refundStatus: y.refundStatus,
407
+ refundedAt: y.refundedAt,
408
+ refundedAmount: y.refundedAmount,
409
+ refunds: Array.isArray(y.refunds) ? y.refunds : []
410
+ });
411
+ });
412
+ }), a.value = q.sort((S, $) => S.startTime?.localeCompare($.startTime || "") || 0);
413
+ } catch (l) {
414
+ console.error("Error loading orders:", l), a.value = [];
415
+ } finally {
416
+ k.value = !1;
417
+ }
418
+ }
419
+ }, p = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], E = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
420
+ return T({
421
+ openDialog: ee
422
+ }), (l, t) => {
423
+ const n = F("DialogTitle"), I = F("DialogDescription"), X = F("DialogHeader"), q = F("Button"), S = F("DialogFooter"), $ = F("DialogScrollContent"), y = F("Dialog");
424
+ return s(), Z(y, {
425
+ open: c.value,
426
+ "onUpdate:open": t[2] || (t[2] = (i) => c.value = i)
427
+ }, {
428
+ default: M(() => [
429
+ u($, { class: "sm:max-w-3xl" }, {
430
+ default: M(() => [
431
+ u(X, null, {
432
+ default: M(() => [
433
+ m.value?.date ? (s(), Z(n, { key: 0 }, {
434
+ default: M(() => [
435
+ le(g(p[new Date(m.value.date).getUTCDay()]) + " " + g(E[new Date(m.value.date).getUTCMonth()]) + " " + g(new Date(m.value.date).getUTCDate()) + ", " + g(new Date(m.value.date).getUTCFullYear()), 1)
436
+ ]),
437
+ _: 1
438
+ })) : B("", !0),
439
+ u(I, null, {
440
+ default: M(() => [
441
+ e("div", Ct, [
442
+ e("div", It, [
443
+ u(w(he), { size: 14 }),
444
+ e("span", null, g(m.value?.startTime) + " – " + g(m.value?.endTime), 1)
445
+ ]),
446
+ m.value?.resource ? (s(), d("div", Mt, [
447
+ e("div", {
448
+ class: "w-4 h-4 rounded-full",
449
+ style: se({ backgroundColor: m.value.resource.color || "#6b7280" })
450
+ }, null, 4),
451
+ e("span", null, g(m.value.resource.name), 1)
452
+ ])) : B("", !0),
453
+ e("div", At, [
454
+ u(w(xe), { size: 14 }),
455
+ e("span", null, g(H.value.spots) + " spots in " + g(H.value.bookings) + " reservations", 1)
456
+ ])
457
+ ])
458
+ ]),
459
+ _: 1
460
+ })
461
+ ]),
462
+ _: 1
463
+ }),
464
+ e("div", zt, [
465
+ P.value.length > 1 ? (s(), Z(ot, {
466
+ key: 0,
467
+ "time-slots": P.value,
468
+ "slot-stats": V.value,
469
+ "selected-time-slot": x.value,
470
+ "max-spots": j.value,
471
+ onSelect: oe,
472
+ onClear: Y,
473
+ tabindex: "0"
474
+ }, null, 8, ["time-slots", "slot-stats", "selected-time-slot", "max-spots"])) : B("", !0),
475
+ u(Dt, {
476
+ "agenda-data": f.agendaData,
477
+ resources: f.resources,
478
+ orders: a.value,
479
+ "filtered-orders": O.value,
480
+ "is-loading": k.value,
481
+ "selected-time-slot": x.value,
482
+ "search-query": N.value,
483
+ "onUpdate:searchQuery": t[0] || (t[0] = (i) => N.value = i),
484
+ onRefresh: v
485
+ }, null, 8, ["agenda-data", "resources", "orders", "filtered-orders", "is-loading", "selected-time-slot", "search-query"])
486
+ ]),
487
+ u(S, null, {
488
+ default: M(() => [
489
+ u(q, {
490
+ variant: "outline",
491
+ onClick: t[1] || (t[1] = (i) => c.value = !1)
492
+ }, {
493
+ default: M(() => [...t[3] || (t[3] = [
494
+ le("Close", -1)
495
+ ])]),
496
+ _: 1
497
+ })
498
+ ]),
499
+ _: 1
500
+ })
501
+ ]),
502
+ _: 1
503
+ })
504
+ ]),
505
+ _: 1
506
+ }, 8, ["open"]);
507
+ };
508
+ }
509
+ }), Bt = { class: "flex-1 border-r shadow-sm overflow-hidden min-h-[1536px]" }, Pt = { class: "relative h-full min-h-[1536px]" }, jt = { class: "divide-y divide-input/80 h-full flex flex-col min-h-[1536px] border-y border-input/80" }, Ot = { class: "absolute inset-0 pointer-events-none" }, Rt = { class: "relative mr-1 @md:mr-3 h-full ml-0.5 @md:ml-2" }, Lt = ["onClick"], Ut = {
510
+ key: 0,
511
+ class: "absolute bottom-0 left-0 right-0 h-1 bg-black/20"
512
+ }, Nt = { class: "flex items-start justify-between gap-2 mb-1" }, Ft = { class: "font-semibold text-xs @md:text-sm leading-tight line-clamp-1 flex-1" }, Vt = { class: "flex items-center gap-1 shrink-0" }, Ht = ["title"], Qt = { class: "font-medium" }, ke = /* @__PURE__ */ ae({
513
+ __name: "EventTimeline",
514
+ props: {
515
+ agendaData: {},
516
+ date: {},
517
+ events: {},
518
+ firstDay: { type: Boolean, default: !1 },
519
+ resources: { default: () => [] }
520
+ },
521
+ setup(f) {
522
+ const T = f, _ = D(null), A = (c) => {
523
+ const [m, a] = c.split(":").map(Number);
524
+ return m * 60 + a;
525
+ };
526
+ R(() => !T.events || !T.resources ? [] : T.resources.map((c) => {
527
+ const a = T.events.filter((k) => k.resourceId === c.id).map((k) => {
528
+ const x = A(k.startTime), P = A(k.endTime) - x, C = x / 1440 * 100, V = P / 1440 * 100, j = (k.bookings ?? 0) > 0, O = k.maxBookings ? (k.bookings ?? 0) / k.maxBookings * 100 : 0;
529
+ return {
530
+ ...k,
531
+ top: `${C}%`,
532
+ height: `${V}%`,
533
+ color: k.resource?.color || "#3b82f6",
534
+ hasBookings: j,
535
+ fillPercentage: O,
536
+ isSmall: P < 60
537
+ };
538
+ });
539
+ return {
540
+ resource: c,
541
+ events: a
542
+ };
543
+ }));
544
+ const L = R(() => T.events ? T.events.map((c) => {
545
+ const m = A(c.startTime), k = A(c.endTime) - m, x = m / 1440 * 100, N = k / 1440 * 100, P = (c.bookings ?? 0) > 0, C = c.maxBookings ? (c.bookings ?? 0) / c.maxBookings * 100 : 0;
546
+ return {
547
+ ...c,
548
+ top: `${x}%`,
549
+ height: `${N}%`,
550
+ color: c.resource?.color || "#3b82f6",
551
+ hasBookings: P,
552
+ fillPercentage: C,
553
+ isSmall: k < 60
554
+ };
555
+ }) : []), o = Array.from({ length: 24 }, (c, m) => ({
556
+ hour: m,
557
+ label: `${m.toString().padStart(2, "0")}:00`
558
+ }));
559
+ return (c, m) => (s(), d(G, null, [
560
+ e("div", Bt, [
561
+ e("div", Pt, [
562
+ e("div", jt, [
563
+ (s(!0), d(G, null, te(w(o), (a) => (s(), d("div", {
564
+ key: a.hour,
565
+ class: "flex-1 flex transition-all duration-200"
566
+ }, [...m[0] || (m[0] = [
567
+ e("div", { class: "flex-1 relative" }, [
568
+ e("div", { class: "absolute top-1/2 left-0 right-0 border-t border-dashed border-input/50" })
569
+ ], -1)
570
+ ])]))), 128))
571
+ ]),
572
+ e("div", Ot, [
573
+ e("div", Rt, [
574
+ (s(!0), d(G, null, te(L.value, (a) => (s(), d("div", {
575
+ key: a.id,
576
+ style: se({
577
+ top: a.top,
578
+ height: a.height,
579
+ opacity: a.hasBookings ? "1" : "0.5"
580
+ }),
581
+ class: "event-card absolute left-0.5 right-0.5 @md:left-2 @md:right-2 rounded-lg pointer-events-auto cursor-pointer group/event transition-all duration-200 hover:shadow-xl overflow-hidden",
582
+ onClick: (k) => _.value?.openDialog(a)
583
+ }, [
584
+ e("div", {
585
+ style: se({ backgroundColor: a.color }),
586
+ class: "absolute inset-0 shadow-lg"
587
+ }, [
588
+ a.maxBookings ? (s(), d("div", Ut, [
589
+ e("div", {
590
+ class: "h-full bg-white/40 transition-all duration-300",
591
+ style: se({ width: `${a.fillPercentage}%` })
592
+ }, null, 4)
593
+ ])) : B("", !0)
594
+ ], 4),
595
+ e("div", {
596
+ class: Q(["relative h-full p-1.5 @md:p-3 flex flex-col", `${a.hasBookings ? "text-white" : "text-gray-600 dark:text-gray-100"}`])
597
+ }, [
598
+ e("div", Nt, [
599
+ e("h3", Ft, g(a.title), 1),
600
+ e("div", Vt, [
601
+ a.resource ? (s(), d("div", {
602
+ key: 0,
603
+ class: "w-5 h-5 @md:w-6 @md:h-6 rounded-full flex items-center justify-center text-[10px] @md:text-xs font-bold bg-white/30 backdrop-blur-sm text-white border border-white/40",
604
+ title: a.resource.name
605
+ }, g(a.resource.avatarLabel || a.resource.name.charAt(0).toUpperCase()), 9, Ht)) : B("", !0),
606
+ e("div", {
607
+ class: Q([
608
+ "flex items-center gap-0.5 @md:gap-1 px-1.5 @md:px-2 py-0.5 rounded-full text-[10px] @md:text-xs font-medium",
609
+ a.hasBookings ? "bg-white text-black backdrop-blur-sm" : "bg-black/10 backdrop-blur-sm"
610
+ ])
611
+ }, [
612
+ u(w(xe), { size: 12 }),
613
+ e("span", null, g(a.bookings), 1)
614
+ ], 2)
615
+ ])
616
+ ]),
617
+ e("div", {
618
+ class: Q(["flex items-center gap-1 @md:gap-2 text-[10px] @md:text-xs opacity-90 mt-auto", { "-translate-x-1 -translate-y-2 scale-80 origin-[0_0]": a.isSmall }])
619
+ }, [
620
+ e("div", {
621
+ class: Q(["flex items-center gap-1 px-1 @md:px-2 py-0.5 rounded backdrop-blur-sm", { "bg-black/10": !a.isSmall }])
622
+ }, [
623
+ u(w(he), { size: 10 }),
624
+ e("span", Qt, g(a.startTime) + " – " + g(a.endTime), 1)
625
+ ], 2)
626
+ ], 2)
627
+ ], 2),
628
+ m[1] || (m[1] = e("div", { class: "absolute inset-0 border-2 border-white/0 group-hover/event:border-white/30 rounded-lg transition-colors duration-200 pointer-events-none" }, null, -1))
629
+ ], 12, Lt))), 128))
630
+ ])
631
+ ])
632
+ ])
633
+ ]),
634
+ u(Et, {
635
+ "agenda-data": f.agendaData,
636
+ resources: f.resources,
637
+ ref_key: "eventDialog",
638
+ ref: _
639
+ }, null, 8, ["agenda-data", "resources"])
640
+ ], 64));
641
+ }
642
+ }), Wt = { class: "sticky left-0 mt-auto z-10 divide-y divide-border/50 h-full flex flex-col min-h-[1536px] bg-input" }, qt = { class: "flex-shrink-0 text-[10px] @md:text-xs font-medium text-muted-foreground px-1.5 @md:px-3 pb-3 border-r border-border/50 w-10 @md:w-14" }, Xt = { class: "flex items-center gap-1.5" }, we = /* @__PURE__ */ ae({
643
+ __name: "Event24hSidebar",
644
+ setup(f) {
645
+ const T = Array.from({ length: 24 }, (_, A) => ({
646
+ hour: A,
647
+ label: `${A.toString().padStart(2, "0")}:00`
648
+ }));
649
+ return (_, A) => (s(), d("div", Wt, [
650
+ (s(!0), d(G, null, te(w(T), (L) => (s(), d("div", {
651
+ key: L.hour,
652
+ class: "flex-1 flex transition-all duration-200"
653
+ }, [
654
+ e("div", qt, [
655
+ e("div", Xt, [
656
+ e("span", {
657
+ class: Q({ "-translate-y-1/2": L.hour !== 0 })
658
+ }, g(L.label), 3)
659
+ ])
660
+ ])
661
+ ]))), 128))
662
+ ]));
663
+ }
664
+ }), Yt = { class: "absolute top-0 w-full pointer-events-none" }, Jt = {
665
+ key: 0,
666
+ class: "absolute -right-2 -top-0.5 px-2 py-0.5 bg-red-500 text-white text-xs font-medium rounded shadow-lg"
667
+ }, Se = /* @__PURE__ */ ae({
668
+ __name: "EventTimeIndicator",
669
+ props: {
670
+ currentDate: {
671
+ type: Object,
672
+ required: !1
673
+ }
674
+ },
675
+ setup(f) {
676
+ const T = D(Date.now());
677
+ let _;
678
+ $e(() => {
679
+ _ = window.setInterval(() => {
680
+ T.value = Date.now();
681
+ }, 1e3);
682
+ }), Te(() => {
683
+ _ && clearInterval(_);
684
+ });
685
+ const A = R(() => {
686
+ const o = new Date(T.value);
687
+ return `${(o.getHours() * 60 + o.getMinutes() + o.getSeconds() / 60) / 1440 * 100}%`;
688
+ }), L = R(() => new Date(T.value).getFullYear() + "-" + (new Date(T.value).getMonth() + 1).toString().padStart(2, "0") + "-" + new Date(T.value).getDate().toString().padStart(2, "0"));
689
+ return (o, c) => (s(), d("div", Yt, [
690
+ e("div", {
691
+ class: "absolute left-0 right-0 h-0.5 bg-red-500 z-30 pointer-events-none transition-[top] duration-300 ease-linear",
692
+ style: se({ top: A.value })
693
+ }, [
694
+ c[0] || (c[0] = e("div", { class: "absolute -left-2 -top-1.5 w-3 h-3 bg-red-500 rounded-full shadow-lg shadow-red-500/50" }, null, -1)),
695
+ f.currentDate && f.currentDate == L.value ? (s(), d("div", Jt, " Now ")) : B("", !0)
696
+ ], 4)
697
+ ]));
698
+ }
699
+ }), Kt = {
700
+ key: 0,
701
+ class: "relative flex flex-1 min-w-0"
702
+ }, Gt = {
703
+ key: 1,
704
+ class: "flex-1 min-w-0 relative min-h-[1616px] @md:min-h-[1658px]"
705
+ }, Zt = {
706
+ key: 0,
707
+ class: "absolute top-0 right-0 z-10 px-3 py-1.5 bg-primary/90 text-primary-foreground text-xs font-medium rounded-bl-lg shadow-lg backdrop-blur-sm flex items-center gap-1.5 animate-pulse-subtle"
708
+ }, es = { class: "flex pb-4 min-w-[200px]" }, ts = ["onClick"], ss = {
709
+ key: 0,
710
+ class: "absolute top-2 right-2 flex items-center gap-1 px-2 py-0.5 bg-primary/20 backdrop-blur-sm rounded-full border border-primary/30"
711
+ }, os = { class: "text-xs text-muted-foreground font-medium group-hover:text-foreground/70 transition-colors" }, as = {
712
+ key: 0,
713
+ class: "absolute bottom-0 left-0 w-full h-1 bg-orange-500"
714
+ }, ns = /* @__PURE__ */ ae({
715
+ __name: "EventView",
716
+ props: {
717
+ agendaData: { default: () => ({}) }
718
+ },
719
+ setup(f) {
720
+ const T = de("activeDate", D(ce(me()))), _ = de("viewMode", D(1)), A = de("events", D([])), L = de("resources", D([])), o = D(null), c = D(!1), m = D(!1);
721
+ R(() => L.value.length > 1);
722
+ const a = R(() => {
723
+ const t = [], n = T.value;
724
+ for (let I = 0; I < _.value; I++)
725
+ t.push(n.add({ days: I }));
726
+ return t;
727
+ }), k = (t, n) => {
728
+ const I = `${t.year}-${String(t.month).padStart(2, "0")}-${String(t.day).padStart(2, "0")}`;
729
+ return A.value?.filter((X) => X.date === I) || [];
730
+ }, x = (t) => {
731
+ const n = ce(me());
732
+ return t.year === n.year && t.month === n.month && t.day === n.day;
733
+ }, N = (t) => {
734
+ T.value = t, _.value = 1;
735
+ };
736
+ let P = null, C = null;
737
+ const V = () => {
738
+ o.value && (O(), o.value.scrollBy({ left: -300, behavior: "smooth" }), C = window.setTimeout(() => {
739
+ P = window.setInterval(() => {
740
+ o.value && o.value.scrollBy({ left: -20, behavior: "auto" });
741
+ }, 50);
742
+ }, 300));
743
+ }, j = () => {
744
+ o.value && (O(), o.value.scrollBy({ left: 300, behavior: "smooth" }), C = window.setTimeout(() => {
745
+ P = window.setInterval(() => {
746
+ o.value && o.value.scrollBy({ left: 20, behavior: "auto" });
747
+ }, 50);
748
+ }, 300));
749
+ }, O = () => {
750
+ C && (clearTimeout(C), C = null), P && (clearInterval(P), P = null);
751
+ }, H = () => {
752
+ if (!o.value) return;
753
+ const { scrollLeft: t, scrollWidth: n, clientWidth: I } = o.value;
754
+ c.value = t > 10, m.value = t < n - I - 10;
755
+ }, oe = (t) => {
756
+ o.value && Math.abs(t.deltaY) > Math.abs(t.deltaX) && (t.preventDefault(), o.value.scrollBy({ left: t.deltaY, behavior: "auto" }));
757
+ }, Y = D(!1), ee = D(0), v = D(0), p = (t) => {
758
+ !o.value || _.value === 1 || t.target.closest(".event-card") || (Y.value = !0, ee.value = t.pageX, v.value = o.value.scrollLeft, o.value.style.userSelect = "none", t.preventDefault());
759
+ }, E = (t) => {
760
+ if (!Y.value || !o.value) return;
761
+ const n = t.pageX, I = (ee.value - n) * 1.2;
762
+ o.value.scrollLeft = v.value + I;
763
+ }, l = () => {
764
+ o.value && (Y.value = !1, o.value.style.userSelect = "");
765
+ };
766
+ return $e(() => {
767
+ o.value && (o.value.addEventListener("scroll", H), o.value.addEventListener("wheel", oe, { passive: !1 }), ve(() => {
768
+ H(), setTimeout(H, 50), setTimeout(H, 150), setTimeout(H, 300), setTimeout(H, 500);
769
+ })), document.addEventListener("mousemove", E), document.addEventListener("mouseup", l);
770
+ }), Ae(() => {
771
+ document.removeEventListener("mousemove", E), document.removeEventListener("mouseup", l);
772
+ }), ue(_, () => {
773
+ _.value > 1 ? ve(() => {
774
+ setTimeout(() => {
775
+ if (!o.value) return;
776
+ const { scrollWidth: t, clientWidth: n } = o.value;
777
+ t > n && (m.value = !0, c.value = !1);
778
+ }, 100);
779
+ }) : o.value && (o.value.style.cursor = "");
780
+ }), Te(() => {
781
+ O(), o.value && (o.value.removeEventListener("scroll", H), o.value.removeEventListener("wheel", oe));
782
+ }), (t, n) => {
783
+ const I = F("Button"), X = F("TooltipTrigger"), q = F("TooltipContent"), S = F("Tooltip");
784
+ return w(_) === 1 ? (s(), d("div", Kt, [
785
+ u(we),
786
+ u(Se, {
787
+ class: "h-full",
788
+ "current-date": w(T)
789
+ }, null, 8, ["current-date"]),
790
+ u(ke, {
791
+ "agenda-data": f.agendaData,
792
+ date: w(T),
793
+ events: k(w(T)),
794
+ resources: w(L)
795
+ }, null, 8, ["agenda-data", "date", "events", "resources"])
796
+ ])) : (s(), d("div", Gt, [
797
+ w(_) === 7 ? (s(), d("div", Zt, [
798
+ u(w(ge), { size: 12 }),
799
+ n[0] || (n[0] = e("span", null, "Scroll to view all days", -1)),
800
+ u(w(fe), { size: 12 })
801
+ ])) : B("", !0),
802
+ c.value ? (s(), Z(I, {
803
+ key: 1,
804
+ variant: "outline",
805
+ size: "icon",
806
+ onMousedown: V,
807
+ onMouseup: O,
808
+ onMouseleave: O,
809
+ onTouchstart: V,
810
+ onTouchend: O,
811
+ class: "sticky top-1/2 left-2 -translate-y-1/2 z-40 h-10 w-10 rounded-full shadow-lg bg-background/95 backdrop-blur-sm hover:bg-background border-2"
812
+ }, {
813
+ default: M(() => [
814
+ u(w(ge), { size: 20 })
815
+ ]),
816
+ _: 1
817
+ })) : B("", !0),
818
+ m.value ? (s(), Z(I, {
819
+ key: 2,
820
+ variant: "outline",
821
+ size: "icon",
822
+ onMousedown: j,
823
+ onMouseup: O,
824
+ onMouseleave: O,
825
+ onTouchstart: j,
826
+ onTouchend: O,
827
+ class: "sticky top-1/2 right-2 -translate-y-1/2 z-40 h-10 w-10 rounded-full shadow-lg bg-background/95 backdrop-blur-sm hover:bg-background border-2 float-right"
828
+ }, {
829
+ default: M(() => [
830
+ u(w(fe), { size: 20 })
831
+ ]),
832
+ _: 1
833
+ })) : B("", !0),
834
+ u(Se, { class: "h-[calc(100%-122px)] mt-[80px] @md:h-[calc(100%-164px)] @md:mt-[122px]" }),
835
+ e("div", {
836
+ class: Q(["absolute right-0 top-0 bottom-0 w-8 bg-gradient-to-l from-background to-transparent z-10 pointer-events-none transition-opacity duration-300", m.value ? "opacity-100" : "opacity-0"])
837
+ }, null, 2),
838
+ e("div", {
839
+ ref_key: "scrollContainer",
840
+ ref: o,
841
+ class: "absolute inset-0 overflow-x-auto overflow-y-hidden",
842
+ onScroll: H,
843
+ onMousedown: p
844
+ }, [
845
+ e("div", es, [
846
+ u(we),
847
+ n[5] || (n[5] = e("div", { class: "absolute w-10 @md:w-14 h-[125px] bg-input" }, null, -1)),
848
+ (s(!0), d(G, null, te(a.value, ($, y) => (s(), d("div", {
849
+ key: $.toString(),
850
+ class: Q(["flex-shrink-0", { "min-w-[200px] w-[33.33%]": w(_) === 3, "min-w-[280px]": w(_) === 7 }])
851
+ }, [
852
+ e("div", {
853
+ onClick: (i) => N($),
854
+ class: Q([
855
+ "relative p-3 border cursor-pointer transition-all duration-200 group relative",
856
+ x($) ? "bg-gradient-to-br from-primary/10 to-primary/5 border-primary/30 hover:from-primary/20 hover:to-primary/10 hover:border-primary/50 hover:shadow-md" : "bg-gradient-to-br from-muted/50 to-muted/30 border-border hover:from-accent/50 hover:to-accent/30 hover:border-accent-foreground/20 hover:shadow-md"
857
+ ])
858
+ }, [
859
+ x($) ? (s(), d("div", ss, [...n[1] || (n[1] = [
860
+ e("div", { class: "w-1.5 h-1.5 bg-primary rounded-full animate-pulse" }, null, -1),
861
+ e("span", { class: "text-[9px] font-bold text-primary uppercase tracking-wide" }, "Today", -1)
862
+ ])])) : B("", !0),
863
+ e("div", {
864
+ class: Q([
865
+ "text-xs font-semibold uppercase tracking-wider transition-colors",
866
+ x($) ? "text-primary group-hover:text-primary/80" : "text-muted-foreground group-hover:text-foreground"
867
+ ])
868
+ }, g(new Date($.year, $.month - 1, $.day).toLocaleDateString("en-US", { weekday: "short" })), 3),
869
+ e("div", {
870
+ class: Q([
871
+ "text-2xl font-bold transition-colors",
872
+ x($) ? "text-foreground" : "text-foreground group-hover:text-primary"
873
+ ])
874
+ }, g($.day), 3),
875
+ e("div", os, g(new Date($.year, $.month - 1, $.day).toLocaleDateString("en-US", { month: "long", year: "numeric" })), 1),
876
+ n[4] || (n[4] = e("div", { class: "mt-2 pt-2 border-t border-border/0 group-hover:border-border/50 transition-all" }, [
877
+ e("div", { class: "text-[10px] text-muted-foreground/0 group-hover:text-muted-foreground/100 uppercase tracking-wide transition-all" }, " Click to view ")
878
+ ], -1)),
879
+ u(S, null, {
880
+ default: M(() => [
881
+ u(X, { "as-child": "" }, {
882
+ default: M(() => [
883
+ k($).filter((i) => i.isException).length > 0 ? (s(), Z(w(Be), {
884
+ key: 0,
885
+ class: "absolute top-3 right-3 size-4 text-orange-500"
886
+ })) : B("", !0)
887
+ ]),
888
+ _: 2
889
+ }, 1024),
890
+ u(q, null, {
891
+ default: M(() => [...n[2] || (n[2] = [
892
+ e("p", null, " This day has exceptions applied to it. ", -1)
893
+ ])]),
894
+ _: 1
895
+ })
896
+ ]),
897
+ _: 2
898
+ }, 1024),
899
+ u(S, null, {
900
+ default: M(() => [
901
+ u(X, { "as-child": "" }, {
902
+ default: M(() => [
903
+ k($).filter((i) => i.isException).length > 0 ? (s(), d("div", as)) : B("", !0)
904
+ ]),
905
+ _: 2
906
+ }, 1024),
907
+ u(q, null, {
908
+ default: M(() => [...n[3] || (n[3] = [
909
+ e("p", null, " This day has exceptions applied to it. ", -1)
910
+ ])]),
911
+ _: 1
912
+ })
913
+ ]),
914
+ _: 2
915
+ }, 1024)
916
+ ], 10, ts),
917
+ u(ke, {
918
+ "agenda-data": f.agendaData,
919
+ date: $,
920
+ events: k($),
921
+ resources: w(L)
922
+ }, null, 8, ["agenda-data", "date", "events", "resources"])
923
+ ], 2))), 128))
924
+ ])
925
+ ], 544)
926
+ ]));
927
+ };
928
+ }
929
+ }), rs = /* @__PURE__ */ Ve(ns, [["__scopeId", "data-v-f5d39ef7"]]), ls = { class: "flex items-center justify-between @sm:justify-start gap-4" }, is = { class: "flex flex-col" }, us = { class: "flex items-center gap-2" }, ds = { class: "text-lg @sm:text-2xl font-bold tracking-tight truncate" }, cs = { class: "text-xs @sm:text-sm text-muted-foreground ml-7 truncate" }, ms = { class: "flex @sm:items-center justify-between flex-col @sm:flex-row @5xl:justify-end gap-2" }, fs = { class: "flex items-center gap-1 @5xl:mr-2" }, ps = {
930
+ key: 0,
931
+ class: "flex items-center gap-2 px-1 overflow-x-auto pb-2 -mx-1 scrollbar-hide"
932
+ }, vs = ["onClick"], gs = { class: "flex gap-2 @md:gap-4" }, hs = { class: "hidden @md:flex flex-shrink-0 flex-col gap-4" }, xs = {
933
+ key: 0,
934
+ class: "rounded-md border p-3"
935
+ }, ys = { class: "space-y-1" }, bs = ["onClick"], _s = { class: "min-w-0 flex-1" }, ks = { class: "text-sm font-medium truncate" }, ws = {
936
+ key: 0,
937
+ class: "pt-2 mt-2 border-t"
938
+ }, Ss = {
939
+ key: 0,
940
+ class: "mt-1 space-y-1"
941
+ }, $s = { class: "min-w-0 flex-1" }, Ts = { class: "text-sm font-medium truncate text-muted-foreground" }, js = /* @__PURE__ */ ae({
942
+ __name: "agenda",
943
+ setup(f) {
944
+ const { hasPermission: T } = Oe(), { params: _ } = ye(), { config: A } = be(), L = _e(A.project), o = D(ce(me())), c = D(1), m = ze("container"), { width: a } = Qe(m), k = R(() => a.value < 640);
945
+ ue(k, (i) => {
946
+ i && c.value !== 1 && (c.value = 1);
947
+ }, { immediate: !0 });
948
+ const x = D(null), N = D(/* @__PURE__ */ new Map()), P = R(() => x.value?.resources || []), C = R(() => P.value.filter((i) => i.isActive)), V = R(() => P.value.filter((i) => !i.isActive)), j = D(null), O = D(!1);
949
+ ue(C, (i) => {
950
+ i.length > 0 && !j.value && (j.value = i[0].id);
951
+ }, { immediate: !0 });
952
+ const H = R(() => {
953
+ if (!j.value)
954
+ return C.value.length > 0 ? [C.value[0]] : [];
955
+ const i = C.value.find((h) => h.id === j.value);
956
+ return i ? [i] : C.value.length > 0 ? [C.value[0]] : [];
957
+ }), oe = R(() => x.value?.pricingOptions?.find((h) => h.isDefault)?.duration || 30), Y = (i) => {
958
+ j.value = i;
959
+ };
960
+ ue(o, () => {
961
+ $();
962
+ });
963
+ const ee = R(() => {
964
+ const i = o.value, h = new Date(i.year, i.month - 1, i.day), z = h.toLocaleDateString("en-US", { weekday: "long" }).toUpperCase(), b = i.day, U = h.toLocaleDateString("en-US", { month: "short" }).toUpperCase();
965
+ return {
966
+ dayName: z,
967
+ day: b,
968
+ monthName: U,
969
+ full: `${z} ${b} ${U}`
970
+ };
971
+ }), v = () => {
972
+ o.value = o.value.subtract({ days: c.value });
973
+ }, p = () => {
974
+ o.value = o.value.add({ days: c.value });
975
+ }, E = () => {
976
+ o.value = ce(me());
977
+ }, l = (i) => {
978
+ const [h, z] = i.split(":").map(Number);
979
+ return h * 60 + z;
980
+ }, t = (i, h) => (x.value?.exceptions || []).find((b) => h >= b.startDate && h <= b.endDate ? b.resourceIds === null ? !0 : b.resourceIds?.includes(i) : !1) || null, n = (i, h, z) => {
981
+ const b = t(i.id, z);
982
+ if (b)
983
+ return b.isClosed ? [] : b.timeslots.map((r) => ({
984
+ startTime: r.startTime,
985
+ endTime: r.endTime,
986
+ isException: !0
987
+ }));
988
+ const U = h.getDay(), W = i.openingHours?.[U] || [];
989
+ return W.length === 0 ? [] : W.map((r) => ({
990
+ startTime: r.start,
991
+ endTime: r.end,
992
+ isException: !1
993
+ }));
994
+ }, I = (i, h, z, b) => {
995
+ if (!x.value) return 0;
996
+ const U = N.value.get(h);
997
+ return U ? U.filter((r) => r.resourceId === i).reduce((r, J) => {
998
+ const K = l(J.startTime), re = l(J.endTime), ie = l(z), pe = l(b);
999
+ return K < pe && re > ie ? r + (J.reserved || 0) : r;
1000
+ }, 0) : 0;
1001
+ }, X = R(() => {
1002
+ if (!x.value) return [];
1003
+ N.value.size;
1004
+ let i = [], h = [];
1005
+ for (let b = 0; b < c.value; b++) {
1006
+ const U = o.value.add({ days: b });
1007
+ h.push(U);
1008
+ }
1009
+ const z = H.value.length > 0 ? H.value : [];
1010
+ return z.length === 0 ? [] : (h.forEach((b) => {
1011
+ let U = new Date(b.year, b.month - 1, b.day);
1012
+ const W = `${b.year}-${String(b.month).padStart(2, "0")}-${String(b.day).padStart(2, "0")}`;
1013
+ z.forEach((r) => {
1014
+ const J = n(r, U, W);
1015
+ i = i.concat(J.map((K, re) => {
1016
+ const ie = I(r.id, W, K.startTime, K.endTime);
1017
+ return {
1018
+ id: `block-${W}-${r.id}-${re}`,
1019
+ title: x.value.serviceName,
1020
+ date: W,
1021
+ startTime: K.startTime,
1022
+ endTime: K.endTime,
1023
+ theme: r.color || "#3b82f6",
1024
+ bookings: ie,
1025
+ maxBookings: r.capacity,
1026
+ isException: K.isException || !1,
1027
+ resourceId: r.id,
1028
+ resource: r,
1029
+ interval: r.interval || 30,
1030
+ serviceDuration: oe.value
1031
+ };
1032
+ }));
1033
+ });
1034
+ }), i);
1035
+ });
1036
+ let q = null;
1037
+ const S = async () => {
1038
+ q || (q = // @ts-ignore - params is actually a computed ref in the implementation
1039
+ L.get(A.agendaCollection, _.value.id).then((i) => {
1040
+ x.value = i;
1041
+ }).finally(() => {
1042
+ q = null;
1043
+ })), await q;
1044
+ }, $ = async () => {
1045
+ if (x.value || await S(), !x.value) return;
1046
+ const i = _.value.id, h = o.value;
1047
+ N.value.clear();
1048
+ const z = [];
1049
+ for (let b = 0; b < c.value; b++) {
1050
+ const U = h.add({ days: b }), W = `${U.year}-${String(U.month).padStart(2, "0")}-${String(U.day).padStart(2, "0")}`, r = `${i}_${W}`;
1051
+ z.push(
1052
+ L.get(A.reservedSpotsCollection, r).then((J) => {
1053
+ if (J) {
1054
+ const K = [];
1055
+ for (const re of C.value) {
1056
+ const ie = J?.[re.id] || {};
1057
+ Object.entries(ie).forEach(([pe, Ce]) => {
1058
+ const [Ie, Me] = pe.split("-");
1059
+ K.push({
1060
+ resourceId: re.id,
1061
+ startTime: Ie,
1062
+ endTime: Me,
1063
+ reserved: Ce
1064
+ });
1065
+ });
1066
+ }
1067
+ N.value.set(W, K);
1068
+ }
1069
+ }).catch(() => {
1070
+ })
1071
+ );
1072
+ }
1073
+ await Promise.all(z);
1074
+ };
1075
+ return (async () => (await S(), await $()))(), ue(c, () => {
1076
+ $();
1077
+ }), ne("agendaData", x), ne("activeDate", o), ne("viewMode", c), ne("events", X), ne("resources", H), ne("allResources", C), (i, h) => {
1078
+ const z = F("Button"), b = F("SegmentedControlButton"), U = F("SegmentedControl"), W = F("Calendar");
1079
+ return s(), Z(je, null, {
1080
+ default: M(() => [
1081
+ e("div", {
1082
+ ref_key: "container",
1083
+ ref: m,
1084
+ class: "flex flex-col gap-2 @md:gap-4 w-full"
1085
+ }, [
1086
+ e("div", {
1087
+ class: Q(["flex flex-col @5xl:flex-row @5xl:items-center @5xl:justify-between gap-3 px-1", (k.value, "")])
1088
+ }, [
1089
+ e("div", ls, [
1090
+ e("div", is, [
1091
+ e("div", us, [
1092
+ u(w(Pe), {
1093
+ size: 20,
1094
+ class: "text-primary flex-shrink-0"
1095
+ }),
1096
+ e("h2", ds, g(ee.value.full), 1)
1097
+ ]),
1098
+ e("p", cs, g(x.value?.serviceName), 1)
1099
+ ])
1100
+ ]),
1101
+ e("div", ms, [
1102
+ e("div", fs, [
1103
+ u(z, {
1104
+ variant: "outline",
1105
+ size: "icon",
1106
+ class: "size-8 @sm:size-9",
1107
+ onClick: v
1108
+ }, {
1109
+ default: M(() => [
1110
+ u(w(ge), { size: 16 })
1111
+ ]),
1112
+ _: 1
1113
+ }),
1114
+ u(z, {
1115
+ variant: "outline",
1116
+ size: "sm",
1117
+ class: "h-8 @sm:h-9 px-2 @sm:px-3 text-xs @sm:text-sm",
1118
+ onClick: E
1119
+ }, {
1120
+ default: M(() => [...h[3] || (h[3] = [
1121
+ le(" Today ", -1)
1122
+ ])]),
1123
+ _: 1
1124
+ }),
1125
+ u(z, {
1126
+ variant: "outline",
1127
+ size: "icon",
1128
+ class: "size-8 @sm:size-9",
1129
+ onClick: p
1130
+ }, {
1131
+ default: M(() => [
1132
+ u(w(fe), { size: 16 })
1133
+ ]),
1134
+ _: 1
1135
+ })
1136
+ ]),
1137
+ k.value ? B("", !0) : (s(), Z(U, {
1138
+ key: 0,
1139
+ modelValue: c.value,
1140
+ "onUpdate:modelValue": h[0] || (h[0] = (r) => c.value = r)
1141
+ }, {
1142
+ default: M(() => [
1143
+ u(b, { value: 1 }, {
1144
+ default: M(() => [...h[4] || (h[4] = [
1145
+ e("span", { class: "whitespace-nowrap" }, "1 Day", -1)
1146
+ ])]),
1147
+ _: 1
1148
+ }),
1149
+ u(b, { value: 3 }, {
1150
+ default: M(() => [...h[5] || (h[5] = [
1151
+ e("span", { class: "whitespace-nowrap" }, "3 Days", -1)
1152
+ ])]),
1153
+ _: 1
1154
+ }),
1155
+ u(b, { value: 7 }, {
1156
+ default: M(() => [...h[6] || (h[6] = [
1157
+ e("span", { class: "whitespace-nowrap" }, "7 Days", -1)
1158
+ ])]),
1159
+ _: 1
1160
+ })
1161
+ ]),
1162
+ _: 1
1163
+ }, 8, ["modelValue"])),
1164
+ w(T)("manage-reservations") ? (s(), Z(He, {
1165
+ key: 1,
1166
+ "agenda-data": x.value
1167
+ }, null, 8, ["agenda-data"])) : B("", !0)
1168
+ ])
1169
+ ], 2),
1170
+ k.value && C.value.length > 0 ? (s(), d("div", ps, [
1171
+ (s(!0), d(G, null, te(C.value, (r) => (s(), d("button", {
1172
+ key: r.id,
1173
+ class: Q(["flex items-center gap-2 px-3 py-1.5 rounded-full border text-sm whitespace-nowrap transition-colors flex-shrink-0", {
1174
+ "bg-primary text-primary-foreground border-primary": j.value === r.id,
1175
+ "bg-background hover:bg-muted": j.value !== r.id
1176
+ }]),
1177
+ onClick: (J) => Y(r.id)
1178
+ }, [
1179
+ e("div", {
1180
+ class: "size-5 rounded-full flex items-center justify-center text-white text-[10px] font-medium",
1181
+ style: se({ backgroundColor: j.value === r.id ? "rgba(255,255,255,0.3)" : r.color || "#6b7280" })
1182
+ }, g(r.avatarLabel || r.name.charAt(0).toUpperCase()), 5),
1183
+ e("span", null, g(r.name), 1)
1184
+ ], 10, vs))), 128))
1185
+ ])) : B("", !0),
1186
+ e("div", gs, [
1187
+ e("div", hs, [
1188
+ u(W, {
1189
+ modelValue: o.value,
1190
+ "onUpdate:modelValue": h[1] || (h[1] = (r) => o.value = r),
1191
+ "weekday-format": "short",
1192
+ class: "rounded-md border"
1193
+ }, null, 8, ["modelValue"]),
1194
+ P.value.length > 0 ? (s(), d("div", xs, [
1195
+ h[7] || (h[7] = e("div", { class: "flex items-center justify-between mb-3" }, [
1196
+ e("span", { class: "text-sm font-medium" }, "Resources")
1197
+ ], -1)),
1198
+ e("div", ys, [
1199
+ (s(!0), d(G, null, te(C.value, (r) => (s(), d("div", {
1200
+ key: r.id,
1201
+ class: Q(["flex items-center gap-2 p-2 rounded-md hover:bg-muted cursor-pointer transition-colors", {
1202
+ "bg-muted ring-2 ring-primary/20": j.value === r.id,
1203
+ "opacity-50": j.value && j.value !== r.id
1204
+ }]),
1205
+ onClick: (J) => Y(r.id)
1206
+ }, [
1207
+ e("div", {
1208
+ class: "size-7 rounded-full flex items-center justify-center text-white text-xs font-medium flex-shrink-0",
1209
+ style: se({ backgroundColor: r.color || "#6b7280" })
1210
+ }, g(r.avatarLabel || r.name.charAt(0).toUpperCase()), 5),
1211
+ e("div", _s, [
1212
+ e("div", ks, g(r.name), 1)
1213
+ ]),
1214
+ e("div", {
1215
+ class: Q(["size-2 rounded-full flex-shrink-0", j.value === r.id ? "bg-primary" : "bg-muted-foreground/30"])
1216
+ }, null, 2)
1217
+ ], 10, bs))), 128)),
1218
+ V.value.length > 0 ? (s(), d("div", ws, [
1219
+ e("button", {
1220
+ class: "flex items-center gap-2 text-xs text-muted-foreground hover:text-foreground w-full py-1 transition-colors",
1221
+ onClick: h[2] || (h[2] = (r) => O.value = !O.value)
1222
+ }, [
1223
+ u(w(fe), {
1224
+ size: 14,
1225
+ class: Q(["transition-transform", { "rotate-90": O.value }])
1226
+ }, null, 8, ["class"]),
1227
+ e("span", null, "Inactive (" + g(V.value.length) + ")", 1)
1228
+ ]),
1229
+ O.value ? (s(), d("div", Ss, [
1230
+ (s(!0), d(G, null, te(V.value, (r) => (s(), d("div", {
1231
+ key: r.id,
1232
+ class: "flex items-center gap-2 p-2 rounded-md opacity-50"
1233
+ }, [
1234
+ e("div", {
1235
+ class: "size-7 rounded-full flex items-center justify-center text-white text-xs font-medium flex-shrink-0 grayscale",
1236
+ style: se({ backgroundColor: r.color || "#6b7280" })
1237
+ }, g(r.avatarLabel || r.name.charAt(0).toUpperCase()), 5),
1238
+ e("div", $s, [
1239
+ e("div", Ts, g(r.name), 1)
1240
+ ])
1241
+ ]))), 128))
1242
+ ])) : B("", !0)
1243
+ ])) : B("", !0)
1244
+ ])
1245
+ ])) : B("", !0)
1246
+ ]),
1247
+ u(rs, { "agenda-data": x.value }, null, 8, ["agenda-data"])
1248
+ ])
1249
+ ], 512)
1250
+ ]),
1251
+ _: 1
1252
+ });
1253
+ };
1254
+ }
1255
+ });
1256
+ export {
1257
+ js as default
1258
+ };