@fayz-ai/plugin-agenda 0.1.8 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/components/AgendaMobileList.d.ts +10 -0
  2. package/dist/components/AgendaMobileList.d.ts.map +1 -0
  3. package/dist/components/AppointmentModal.d.ts +4 -2
  4. package/dist/components/AppointmentModal.d.ts.map +1 -1
  5. package/dist/components/AppointmentPopover.d.ts.map +1 -1
  6. package/dist/components/EventContextMenu.d.ts.map +1 -1
  7. package/dist/config.d.ts +62 -1
  8. package/dist/config.d.ts.map +1 -1
  9. package/dist/data/index.d.ts +1 -0
  10. package/dist/data/index.d.ts.map +1 -1
  11. package/dist/data/mock.d.ts +15 -1
  12. package/dist/data/mock.d.ts.map +1 -1
  13. package/dist/data/supabase.d.ts.map +1 -1
  14. package/dist/index.cjs +614 -308
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.ts +2 -0
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +452 -147
  19. package/dist/index.js.map +1 -1
  20. package/dist/locales/en.d.ts.map +1 -1
  21. package/dist/locales/pt-BR.d.ts.map +1 -1
  22. package/dist/store.d.ts +3 -0
  23. package/dist/store.d.ts.map +1 -1
  24. package/dist/types.d.ts +8 -0
  25. package/dist/types.d.ts.map +1 -1
  26. package/dist/views/CalendarView.d.ts.map +1 -1
  27. package/package.json +5 -8
  28. package/src/components/AgendaMobileList.tsx +103 -0
  29. package/src/components/AppointmentModal.tsx +86 -9
  30. package/src/components/AppointmentPopover.tsx +20 -10
  31. package/src/components/EventContextMenu.tsx +3 -0
  32. package/src/config.ts +104 -5
  33. package/src/data/index.ts +1 -0
  34. package/src/data/mock.ts +22 -5
  35. package/src/data/supabase.ts +13 -2
  36. package/src/index.ts +8 -3
  37. package/src/locales/en.ts +12 -0
  38. package/src/locales/pt-BR.ts +12 -0
  39. package/src/store.ts +4 -2
  40. package/src/types.ts +8 -0
  41. package/src/views/CalendarView.tsx +220 -54
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { setAgendaTenantId, getAgendaTenantId } from './chunk-3LJKZQK4.js';
2
- import React11, { useState, useEffect, useRef, useCallback, useMemo } from 'react';
3
- import { getSupabaseClientOptional, registerTranslations, createSafeDataProvider, usePluginRuntimeOptional, useTranslation, getActiveTenantId, getCurrentLocale } from '@fayz-ai/core';
2
+ import React12, { useState, useEffect, useRef, useMemo, useCallback } from 'react';
3
+ import { getSupabaseClientOptional, registerTranslations, createSafeDataProvider, usePluginRuntimeOptional, useTranslation, getActiveTenantId, getCurrentLocale, formatCurrency } from '@fayz-ai/core';
4
4
  import { createPluginContext, setScheduleBlockConfig, getScheduleBlockConfig, PluginSettingsPanel, dedup, SettingsGroup, ToggleRow, SelectRow, usePluginPrefs, PersonLink, CrudFormPage, CrudDetailPage } from '@fayz-ai/saas';
5
5
  import FullCalendar from '@fullcalendar/react';
6
6
  import dayGridPlugin from '@fullcalendar/daygrid';
@@ -67,23 +67,47 @@ var DEFAULT_BOOKING_TYPES = [
67
67
  requiresClient: false
68
68
  }
69
69
  ];
70
+ var SIMPLE_EVENT_BOOKING_TYPES = [
71
+ {
72
+ id: "event",
73
+ label: "Event",
74
+ icon: "Calendar",
75
+ color: "#6366f1",
76
+ fields: { title: true, client: false, professional: false, services: false, location: false, status: false },
77
+ requiresServices: false,
78
+ requiresClient: false
79
+ }
80
+ ];
70
81
  function resolveConfig(options) {
82
+ const simple = options?.eventMode === "simple";
83
+ const bookingTypes = options?.bookingTypes ?? (simple ? SIMPLE_EVENT_BOOKING_TYPES : DEFAULT_BOOKING_TYPES);
84
+ const capabilities = {
85
+ title: bookingTypes.some((bt) => bt.fields.title === true),
86
+ client: bookingTypes.some((bt) => bt.fields.client),
87
+ professional: bookingTypes.some((bt) => bt.fields.professional),
88
+ services: bookingTypes.some((bt) => bt.fields.services),
89
+ location: bookingTypes.some((bt) => bt.fields.location),
90
+ status: bookingTypes.some((bt) => bt.fields.status)
91
+ };
71
92
  return {
72
93
  modules: {
73
- workingHours: options?.modules?.workingHours !== false,
74
- confirmations: options?.modules?.confirmations !== false,
75
- conflictDetection: options?.modules?.conflictDetection !== false,
94
+ // Off-unless-explicit in simple mode (`?? !simple`); default-on in full.
95
+ workingHours: options?.modules?.workingHours ?? !simple,
96
+ confirmations: options?.modules?.confirmations ?? !simple,
97
+ conflictDetection: options?.modules?.conflictDetection ?? !simple,
76
98
  dragAndDrop: options?.modules?.dragAndDrop !== false,
77
99
  locationSelection: options?.modules?.locationSelection === true,
78
100
  financial: options?.modules?.financial ?? !!options?.financialBridge
79
101
  },
102
+ simpleMode: simple,
103
+ capabilities,
80
104
  labels: { ...DEFAULT_LABELS, ...options?.labels },
81
105
  currency: { ...DEFAULT_CURRENCY, ...options?.currency },
82
106
  bookingKind: options?.bookingKind ?? "appointment",
83
107
  orderKind: options?.orderKind ?? "service_order",
84
108
  scheduleKind: options?.scheduleKind ?? "working_hours",
85
109
  statuses: options?.statuses ?? DEFAULT_STATUSES,
86
- bookingTypes: options?.bookingTypes ?? DEFAULT_BOOKING_TYPES,
110
+ bookingTypes,
87
111
  businessHours: options?.businessHours ?? { startTime: "07:00", endTime: "21:00" },
88
112
  slotDuration: options?.slotDuration ?? 30,
89
113
  professionalKind: options?.professionalKind ?? "staff",
@@ -91,6 +115,8 @@ function resolveConfig(options) {
91
115
  autoCreateOrder: options?.autoCreateOrder !== false,
92
116
  locations: options?.locations ?? [],
93
117
  confirmationChannels: options?.confirmationChannels ?? [],
118
+ cancellationDetails: options?.cancellationDetails,
119
+ onBookingCreated: options?.onBookingCreated,
94
120
  contactLookup: options?.contactLookup,
95
121
  clientEntityDef: options?.clientEntityDef,
96
122
  serviceLookup: options?.serviceLookup,
@@ -418,7 +444,7 @@ function toDateLocale(locale) {
418
444
  }
419
445
  function MiniCalendar({ selectedDate, onDateSelect, onMonthChange }) {
420
446
  const locale = getCurrentLocale();
421
- const [viewMonth, setViewMonth] = React11.useState(() => new Date(selectedDate.getFullYear(), selectedDate.getMonth(), 1));
447
+ const [viewMonth, setViewMonth] = React12.useState(() => new Date(selectedDate.getFullYear(), selectedDate.getMonth(), 1));
422
448
  const monthLabel = viewMonth.toLocaleDateString(toDateLocale(locale), { month: "long", year: "numeric" });
423
449
  const dayLabels = DAY_LABELS[locale] ?? DAY_LABELS.en;
424
450
  const weeks = useMemo(() => {
@@ -707,7 +733,7 @@ var ICON_COLORS = {
707
733
  bank_transfer: "text-warning",
708
734
  check: "text-muted-foreground"
709
735
  };
710
- function BookingPaymentPanel({ orderId, orderTotal, services, onClose, onPaymentChange, formatCurrency, inline }) {
736
+ function BookingPaymentPanel({ orderId, orderTotal, services, onClose, onPaymentChange, formatCurrency: formatCurrency2, inline }) {
711
737
  const t = useTranslation();
712
738
  const config = useAgendaConfig();
713
739
  const bridge = config.financialBridge;
@@ -789,7 +815,7 @@ function BookingPaymentPanel({ orderId, orderTotal, services, onClose, onPayment
789
815
  !loading && isPaid && justPaid && /* @__PURE__ */ jsxs("div", { className: "text-center py-8 space-y-2 animate-in fade-in zoom-in-95 duration-300", children: [
790
816
  /* @__PURE__ */ jsx("div", { className: "flex h-14 w-14 mx-auto items-center justify-center rounded-full bg-success/10 animate-bounce", style: { animationDuration: "600ms", animationIterationCount: "2" }, children: /* @__PURE__ */ jsx(Check, { className: "h-7 w-7 text-success" }) }),
791
817
  /* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-success", children: t("agenda.payment.checkoutComplete") }),
792
- /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: formatCurrency(detail.totalAmount) })
818
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: formatCurrency2(detail.totalAmount) })
793
819
  ] }),
794
820
  !loading && detail && detail.status !== "none" && !justPaid && /* @__PURE__ */ jsxs("div", { className: "space-y-3 animate-in fade-in duration-300", children: [
795
821
  detail.movements.length > 0 ? /* @__PURE__ */ jsx("div", { className: "space-y-1.5", children: detail.movements.map((mov) => {
@@ -821,21 +847,21 @@ function BookingPaymentPanel({ orderId, orderTotal, services, onClose, onPayment
821
847
  ] }),
822
848
  isPartial && /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 rounded-full bg-warning/10 px-2 py-0.5 text-[10px] font-medium text-warning", children: [
823
849
  "! ",
824
- formatCurrency(mov.paidAmount),
850
+ formatCurrency2(mov.paidAmount),
825
851
  "/",
826
- formatCurrency(mov.amount)
852
+ formatCurrency2(mov.amount)
827
853
  ] }),
828
854
  isOverdue && /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 rounded-full bg-destructive/10 px-2 py-0.5 text-[10px] font-medium text-destructive", children: [
829
855
  "! ",
830
856
  t("agenda.payment.overdue")
831
857
  ] }),
832
858
  mov.status === "pending" && /* @__PURE__ */ jsx("span", { className: "inline-flex items-center rounded-full bg-muted px-2 py-0.5 text-[10px] font-medium text-muted-foreground", children: t("agenda.payment.pending") }),
833
- /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold", children: formatCurrency(mov.paidAmount || mov.amount) })
859
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold", children: formatCurrency2(mov.paidAmount || mov.amount) })
834
860
  ] })
835
861
  ] }, mov.id);
836
862
  }) }) : /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-sm px-1", children: [
837
863
  /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: t("agenda.payment.total") }),
838
- /* @__PURE__ */ jsx("span", { className: "font-semibold", children: formatCurrency(detail.totalAmount) })
864
+ /* @__PURE__ */ jsx("span", { className: "font-semibold", children: formatCurrency2(detail.totalAmount) })
839
865
  ] }),
840
866
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
841
867
  detail.referenceNumber && /* @__PURE__ */ jsxs("span", { className: "text-[10px] font-mono text-muted-foreground", children: [
@@ -860,12 +886,12 @@ function BookingPaymentPanel({ orderId, orderTotal, services, onClose, onPayment
860
886
  /* @__PURE__ */ jsx("p", { className: "text-[11px] font-medium text-muted-foreground mb-2", children: t("agenda.payment.serviceSummary") }),
861
887
  /* @__PURE__ */ jsx("div", { className: "space-y-0.5", children: services.map((svc, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-sm py-1", children: [
862
888
  /* @__PURE__ */ jsx("span", { className: "truncate", children: svc.name }),
863
- /* @__PURE__ */ jsx("span", { className: "shrink-0 text-muted-foreground", children: formatCurrency(svc.price) })
889
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 text-muted-foreground", children: formatCurrency2(svc.price) })
864
890
  ] }, i)) })
865
891
  ] }),
866
892
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-sm font-semibold pt-2 border-t", children: [
867
893
  /* @__PURE__ */ jsx("span", { children: t("agenda.payment.total") }),
868
- /* @__PURE__ */ jsx("span", { children: formatCurrency(orderTotal) })
894
+ /* @__PURE__ */ jsx("span", { children: formatCurrency2(orderTotal) })
869
895
  ] }),
870
896
  /* @__PURE__ */ jsxs("div", { children: [
871
897
  /* @__PURE__ */ jsx("p", { className: "text-[11px] font-medium text-muted-foreground mb-2", children: t("agenda.payment.paymentMethod") }),
@@ -940,7 +966,7 @@ function BookingPaymentPanel({ orderId, orderTotal, services, onClose, onPayment
940
966
  children: Array.from({ length: 12 }, (_, i) => i + 1).map((n) => /* @__PURE__ */ jsxs("option", { value: n, children: [
941
967
  n,
942
968
  "x ",
943
- n > 1 ? formatCurrency(orderTotal / n) : ""
969
+ n > 1 ? formatCurrency2(orderTotal / n) : ""
944
970
  ] }, n))
945
971
  }
946
972
  )
@@ -969,7 +995,7 @@ function BookingPaymentPanel({ orderId, orderTotal, services, onClose, onPayment
969
995
  onClick: handleCheckout,
970
996
  disabled: processing || !selectedTypeId,
971
997
  className: "w-full rounded-lg bg-primary border border-primary py-2.5 text-sm font-medium text-primary-foreground hover:bg-primary/90 shadow-button-primary active:shadow-button-inset disabled:opacity-40 transition-colors",
972
- children: processing ? t("agenda.payment.checkingOut") : `${t("agenda.payment.checkout")} ${formatCurrency(orderTotal)}`
998
+ children: processing ? t("agenda.payment.checkingOut") : `${t("agenda.payment.checkout")} ${formatCurrency2(orderTotal)}`
973
999
  }
974
1000
  )
975
1001
  ] })
@@ -1232,7 +1258,7 @@ function LocationSelect({ value, onChange, locations }) {
1232
1258
  )) })
1233
1259
  ] });
1234
1260
  }
1235
- function AppointmentModal({ open, mode, bookingId, prefill, initialTab, onClose, onCreated }) {
1261
+ function AppointmentModal({ open, mode, bookingId, prefill, initialTab, externalSource, onClose, onCreated }) {
1236
1262
  const t = useTranslation();
1237
1263
  const locale = getCurrentLocale();
1238
1264
  const config = useAgendaConfig();
@@ -1245,8 +1271,10 @@ function AppointmentModal({ open, mode, bookingId, prefill, initialTab, onClose,
1245
1271
  const agendaDateRange = useAgendaStore((s) => s.dateRange);
1246
1272
  const professionals = useAgendaStore((s) => s.professionals);
1247
1273
  const storeLocations = useAgendaStore((s) => s.locations);
1274
+ const defaultBookingType = config.bookingTypes[0]?.id ?? "appointment";
1248
1275
  const [loading, setLoading] = useState(mode === "edit");
1249
- const [bookingType, setBookingType] = useState(prefill?.kind ?? "appointment");
1276
+ const [bookingType, setBookingType] = useState(prefill?.kind ?? defaultBookingType);
1277
+ const [title, setTitle] = useState("");
1250
1278
  const [clientId, setClientId] = useState(prefill?.clientId ?? "");
1251
1279
  const [clientSearch, setClientSearch] = useState("");
1252
1280
  const [clientPhone, setClientPhone] = useState("");
@@ -1291,6 +1319,10 @@ function AppointmentModal({ open, mode, bookingId, prefill, initialTab, onClose,
1291
1319
  const [clientData, setClientData] = useState(null);
1292
1320
  const [clientDataLoading, setClientDataLoading] = useState(false);
1293
1321
  const [clientEditing, setClientEditing] = useState(false);
1322
+ const [cancellationReasons, setCancellationReasons] = useState([]);
1323
+ const [cancellationReasonId, setCancellationReasonId] = useState("");
1324
+ const [cancellationNotes, setCancellationNotes] = useState("");
1325
+ const [cancellationReasonsLoading, setCancellationReasonsLoading] = useState(false);
1294
1326
  const activeType = config.bookingTypes.find((bt) => bt.id === bookingType) ?? config.bookingTypes[0];
1295
1327
  useEffect(() => {
1296
1328
  if (!open) return;
@@ -1311,7 +1343,8 @@ function AppointmentModal({ open, mode, bookingId, prefill, initialTab, onClose,
1311
1343
  setNewClientPhone("");
1312
1344
  setNewClientEmail("");
1313
1345
  setCreatingClient(false);
1314
- setBookingType(prefill?.kind ?? "appointment");
1346
+ setBookingType(prefill?.kind ?? defaultBookingType);
1347
+ setTitle("");
1315
1348
  setEditingDate(false);
1316
1349
  setEditingTime(false);
1317
1350
  setConfirmingDelete(false);
@@ -1323,6 +1356,9 @@ function AppointmentModal({ open, mode, bookingId, prefill, initialTab, onClose,
1323
1356
  setClientData(null);
1324
1357
  setClientDataLoading(false);
1325
1358
  setClientEditing(false);
1359
+ setCancellationReasonId("");
1360
+ setCancellationNotes("");
1361
+ setCancellationReasonsLoading(false);
1326
1362
  setModalTab(initialTab || "appointment");
1327
1363
  if (!prefill?.professionalId && professionals.length === 1) setProfessionalId(professionals[0].id);
1328
1364
  setDate(() => {
@@ -1345,7 +1381,8 @@ function AppointmentModal({ open, mode, bookingId, prefill, initialTab, onClose,
1345
1381
  setLoading(false);
1346
1382
  return;
1347
1383
  }
1348
- setBookingType(b.kind ?? "appointment");
1384
+ setBookingType(b.kind ?? defaultBookingType);
1385
+ setTitle(b.clientName ?? "");
1349
1386
  setClientId(b.clientId ?? "");
1350
1387
  setClientSearch(b.clientName ?? "");
1351
1388
  setProfessionalId(b.professionalId ?? "");
@@ -1367,6 +1404,7 @@ function AppointmentModal({ open, mode, bookingId, prefill, initialTab, onClose,
1367
1404
  setEditPaymentStatus(b.paymentStatus ?? "none");
1368
1405
  const svcSnap = b.services ? b.services.map((s) => ({ id: s.serviceId ?? "", dur: s.durationMinutes, price: s.price })) : [];
1369
1406
  initialSnapshot.current = JSON.stringify({
1407
+ title: b.clientName ?? "",
1370
1408
  clientId: b.clientId ?? "",
1371
1409
  professionalId: b.professionalId ?? "",
1372
1410
  locationId: b.locationId ?? "",
@@ -1374,6 +1412,8 @@ function AppointmentModal({ open, mode, bookingId, prefill, initialTab, onClose,
1374
1412
  startTime: `${String(new Date(b.startsAt).getHours()).padStart(2, "0")}:${String(new Date(b.startsAt).getMinutes()).padStart(2, "0")}`,
1375
1413
  status: b.status,
1376
1414
  notes: b.notes ?? "",
1415
+ cancellationReasonId: "",
1416
+ cancellationNotes: "",
1377
1417
  services: svcSnap
1378
1418
  });
1379
1419
  setLoading(false);
@@ -1398,6 +1438,11 @@ function AppointmentModal({ open, mode, bookingId, prefill, initialTab, onClose,
1398
1438
  setClientDataLoading(false);
1399
1439
  }).catch(() => setClientDataLoading(false));
1400
1440
  }, [modalTab, clientId]);
1441
+ useEffect(() => {
1442
+ if (!open || status !== "cancelled" || !config.cancellationDetails || cancellationReasons.length > 0) return;
1443
+ setCancellationReasonsLoading(true);
1444
+ config.cancellationDetails.listReasons().then((reasons) => setCancellationReasons(reasons)).catch(() => setCancellationReasons([])).finally(() => setCancellationReasonsLoading(false));
1445
+ }, [open, status, config.cancellationDetails, cancellationReasons.length]);
1401
1446
  useEffect(() => {
1402
1447
  if (!open || !config.serviceLookup) return;
1403
1448
  const lookup = config.serviceLookup;
@@ -1497,10 +1542,11 @@ function AppointmentModal({ open, mode, bookingId, prefill, initialTab, onClose,
1497
1542
  locationId: locationId || void 0,
1498
1543
  startsAt,
1499
1544
  notes: notes || void 0,
1545
+ title: activeType.fields.title ? title.trim() : void 0,
1500
1546
  services: services.map((s) => ({ serviceId: s.serviceId, name: s.name, durationMinutes: s.durationMinutes, price: s.price }))
1501
1547
  });
1502
1548
  onClose();
1503
- onCreated?.(newBooking.id);
1549
+ onCreated?.(newBooking.id, externalSource);
1504
1550
  } else if (bookingId) {
1505
1551
  await updateBooking(bookingId, {
1506
1552
  clientId,
@@ -1509,8 +1555,17 @@ function AppointmentModal({ open, mode, bookingId, prefill, initialTab, onClose,
1509
1555
  startsAt,
1510
1556
  notes: notes || void 0,
1511
1557
  status,
1558
+ title: activeType.fields.title ? title.trim() : void 0,
1512
1559
  services: services.map((s) => ({ serviceId: s.serviceId, name: s.name, durationMinutes: s.durationMinutes, price: s.price }))
1513
1560
  });
1561
+ if (status === "cancelled" && config.cancellationDetails && cancellationReasonId) {
1562
+ await config.cancellationDetails.saveCancellationDetails({
1563
+ bookingId,
1564
+ reasonId: cancellationReasonId,
1565
+ notes: cancellationNotes.trim() || void 0,
1566
+ cancelledAt: (/* @__PURE__ */ new Date()).toISOString()
1567
+ });
1568
+ }
1514
1569
  onClose();
1515
1570
  }
1516
1571
  } catch {
@@ -1528,12 +1583,15 @@ function AppointmentModal({ open, mode, bookingId, prefill, initialTab, onClose,
1528
1583
  setDeleting(false);
1529
1584
  }
1530
1585
  const isPaidBooking = editPaymentStatus === "paid";
1586
+ const selectedCancellationReason = cancellationReasons.find((reason) => reason.id === cancellationReasonId);
1587
+ const needsCancellationReason = mode === "edit" && status === "cancelled" && !!config.cancellationDetails;
1588
+ const needsCancellationNotes = needsCancellationReason && !!selectedCancellationReason?.requiresNotes;
1531
1589
  const formSnapshot = useMemo(
1532
- () => JSON.stringify({ clientId, professionalId, locationId, date, startTime, status, notes, services: services.map((s) => ({ id: s.serviceId, dur: s.durationMinutes, price: s.price })) }),
1533
- [clientId, professionalId, locationId, date, startTime, status, notes, services]
1590
+ () => JSON.stringify({ title, clientId, professionalId, locationId, date, startTime, status, notes, cancellationReasonId, cancellationNotes, services: services.map((s) => ({ id: s.serviceId, dur: s.durationMinutes, price: s.price })) }),
1591
+ [title, clientId, professionalId, locationId, date, startTime, status, notes, cancellationReasonId, cancellationNotes, services]
1534
1592
  );
1535
1593
  const isDirty = mode === "create" || formSnapshot !== initialSnapshot.current;
1536
- const canSubmit = (!activeType.requiresClient || clientId) && (!activeType.fields.professional || professionalId) && (!activeType.requiresServices || services.length > 0) && !conflict && !saving;
1594
+ const canSubmit = (!activeType.fields.title || title.trim()) && (!activeType.requiresClient || clientId) && (!activeType.fields.professional || professionalId) && (!activeType.requiresServices || services.length > 0) && (!needsCancellationReason || !!cancellationReasonId) && (!needsCancellationNotes || !!cancellationNotes.trim()) && !conflict && !saving;
1537
1595
  const showTabs = config.bookingTypes.length > 1;
1538
1596
  return /* @__PURE__ */ jsx(Modal, { open, onOpenChange: (v) => {
1539
1597
  if (!v) onClose();
@@ -1708,6 +1766,20 @@ function AppointmentModal({ open, mode, bookingId, prefill, initialTab, onClose,
1708
1766
  /* @__PURE__ */ jsx("div", { className: "h-8 flex-1 rounded-lg bg-muted animate-pulse" })
1709
1767
  ] }, i)) }),
1710
1768
  !loading && /* @__PURE__ */ jsxs(Fragment, { children: [
1769
+ activeType.fields.title && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 py-1", children: [
1770
+ /* @__PURE__ */ jsx(Calendar, { className: "h-4 w-4 text-muted-foreground shrink-0" }),
1771
+ /* @__PURE__ */ jsx(
1772
+ "input",
1773
+ {
1774
+ type: "text",
1775
+ value: title,
1776
+ onChange: (e) => setTitle(e.target.value),
1777
+ placeholder: t("agenda.appointment.addTitle"),
1778
+ autoFocus: mode === "create",
1779
+ className: "w-full flex-1 rounded-input border border-input bg-card shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] px-2.5 py-1.5 text-sm font-medium focus:outline-none focus:ring-2 focus:ring-ring"
1780
+ }
1781
+ )
1782
+ ] }),
1711
1783
  activeType.fields.client && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 py-1", children: [
1712
1784
  /* @__PURE__ */ jsx(User, { className: "h-4 w-4 text-muted-foreground shrink-0" }),
1713
1785
  /* @__PURE__ */ jsx("div", { className: "flex-1", children: clientId && !quickCreate ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 rounded-md bg-muted/30 px-2.5 py-1.5 text-sm", children: [
@@ -1920,6 +1992,37 @@ function AppointmentModal({ open, mode, bookingId, prefill, initialTab, onClose,
1920
1992
  /* @__PURE__ */ jsx(CircleDot, { className: "h-4 w-4 text-muted-foreground shrink-0" }),
1921
1993
  /* @__PURE__ */ jsx(StatusSelect, { value: status, onChange: setStatus, statuses: config.statuses, bookingDate: date })
1922
1994
  ] }),
1995
+ needsCancellationReason && /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3 py-1", children: [
1996
+ /* @__PURE__ */ jsx(Ban, { className: "h-4 w-4 mt-2 text-muted-foreground shrink-0" }),
1997
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 space-y-2", children: [
1998
+ /* @__PURE__ */ jsxs(
1999
+ "select",
2000
+ {
2001
+ value: cancellationReasonId,
2002
+ onChange: (event) => setCancellationReasonId(event.target.value),
2003
+ disabled: cancellationReasonsLoading,
2004
+ className: "w-full rounded-input border border-input bg-card px-2.5 py-1.5 text-sm shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] focus:outline-none focus:ring-2 focus:ring-ring",
2005
+ children: [
2006
+ /* @__PURE__ */ jsx("option", { value: "", children: cancellationReasonsLoading ? t("agenda.cancellation.loadingReasons") : t("agenda.cancellation.selectReason") }),
2007
+ cancellationReasons.map((reason) => /* @__PURE__ */ jsxs("option", { value: reason.id, children: [
2008
+ reason.label,
2009
+ reason.requiresNotes ? " *" : ""
2010
+ ] }, reason.id))
2011
+ ]
2012
+ }
2013
+ ),
2014
+ /* @__PURE__ */ jsx(
2015
+ "textarea",
2016
+ {
2017
+ value: cancellationNotes,
2018
+ onChange: (event) => setCancellationNotes(event.target.value),
2019
+ placeholder: needsCancellationNotes ? t("agenda.cancellation.notesRequired") : t("agenda.cancellation.notesOptional"),
2020
+ rows: 2,
2021
+ className: "w-full rounded-input border border-input bg-card px-2.5 py-1.5 text-sm resize-none shadow-[inset_0_1px_0_rgb(0_0_0_/0.06)] focus:outline-none focus:ring-2 focus:ring-ring"
2022
+ }
2023
+ )
2024
+ ] })
2025
+ ] }),
1923
2026
  !showNotes ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 py-1", children: [
1924
2027
  /* @__PURE__ */ jsx(FileText, { className: "h-4 w-4 text-muted-foreground shrink-0" }),
1925
2028
  /* @__PURE__ */ jsx(
@@ -2234,7 +2337,7 @@ function AppointmentPopover({ booking, position, onClose, onEdit }) {
2234
2337
  /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
2235
2338
  /* @__PURE__ */ jsx("span", { className: "mt-1.5 h-3 w-3 rounded shrink-0", style: { backgroundColor: color } }),
2236
2339
  /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
2237
- /* @__PURE__ */ jsx(PersonLink, { personId: booking.clientId, name: booking.clientName ?? "Unknown", className: "text-base" }),
2340
+ config.capabilities.client ? /* @__PURE__ */ jsx(PersonLink, { personId: booking.clientId, name: booking.clientName ?? "Unknown", className: "text-base" }) : /* @__PURE__ */ jsx("p", { className: "text-base font-medium truncate", children: booking.clientName || t("agenda.appointment.untitled") }),
2238
2341
  /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground mt-0.5", children: [
2239
2342
  fmtDate(booking.startsAt),
2240
2343
  " \xB7 ",
@@ -2254,7 +2357,7 @@ function AppointmentPopover({ booking, position, onClose, onEdit }) {
2254
2357
  ] })
2255
2358
  ] }, svc.id)) })
2256
2359
  ] }),
2257
- booking.professionalName && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
2360
+ config.capabilities.professional && booking.professionalName && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
2258
2361
  /* @__PURE__ */ jsx(User, { className: "h-4 w-4 text-muted-foreground shrink-0" }),
2259
2362
  /* @__PURE__ */ jsx("span", { className: "text-sm", children: booking.professionalName })
2260
2363
  ] }),
@@ -2305,7 +2408,7 @@ function AppointmentPopover({ booking, position, onClose, onEdit }) {
2305
2408
  )
2306
2409
  ] });
2307
2410
  })(),
2308
- /* @__PURE__ */ jsx("div", { className: "pt-2 border-t fayz-glass-divider", children: /* @__PURE__ */ jsx(
2411
+ config.capabilities.status && /* @__PURE__ */ jsx("div", { className: "pt-2 border-t fayz-glass-divider", children: /* @__PURE__ */ jsx(
2309
2412
  PopoverStatusSelect,
2310
2413
  {
2311
2414
  value: booking.status,
@@ -2422,7 +2525,7 @@ function EventContextMenu({ booking, position, onClose, onEdit }) {
2422
2525
  }
2423
2526
  )
2424
2527
  ] }),
2425
- /* @__PURE__ */ jsxs("div", { className: "border-t px-4 py-3", children: [
2528
+ config.capabilities.status && /* @__PURE__ */ jsxs("div", { className: "border-t px-4 py-3", children: [
2426
2529
  /* @__PURE__ */ jsx("p", { className: "text-[11px] font-medium text-muted-foreground mb-2", children: t("agenda.contextMenu.changeStatus") }),
2427
2530
  /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1.5", children: config.statuses.map((s) => {
2428
2531
  const available = isStatusAvailable(s, booking.startsAt);
@@ -2446,6 +2549,66 @@ function EventContextMenu({ booking, position, onClose, onEdit }) {
2446
2549
  ] })
2447
2550
  ] }) });
2448
2551
  }
2552
+ function startOfDay(d) {
2553
+ const x = new Date(d);
2554
+ x.setHours(0, 0, 0, 0);
2555
+ return x;
2556
+ }
2557
+ function timeLabel(iso) {
2558
+ const d = new Date(iso);
2559
+ return `${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}`;
2560
+ }
2561
+ function AgendaMobileList({ bookings, statusColors, currencyCode, onSelect }) {
2562
+ const t = useTranslation();
2563
+ const locale = getCurrentLocale() === "pt-BR" ? "pt-BR" : "en";
2564
+ const groups = useMemo(() => {
2565
+ const todayStart = startOfDay(/* @__PURE__ */ new Date()).getTime();
2566
+ const sorted = bookings.filter((b) => !!b.startsAt).slice().sort((a, b) => a.startsAt < b.startsAt ? -1 : a.startsAt > b.startsAt ? 1 : 0);
2567
+ const map = /* @__PURE__ */ new Map();
2568
+ for (const b of sorted) {
2569
+ const day = startOfDay(new Date(b.startsAt));
2570
+ if (day.getTime() < todayStart) continue;
2571
+ const key = day.toISOString().slice(0, 10);
2572
+ const list = map.get(key) ?? [];
2573
+ list.push(b);
2574
+ map.set(key, list);
2575
+ }
2576
+ return Array.from(map.entries()).map(([key, items]) => ({ key, date: /* @__PURE__ */ new Date(key + "T00:00:00"), items }));
2577
+ }, [bookings]);
2578
+ function dayLabel(date) {
2579
+ const today = startOfDay(/* @__PURE__ */ new Date());
2580
+ const diff = Math.round((startOfDay(date).getTime() - today.getTime()) / 864e5);
2581
+ if (diff === 0) return t("agenda.list.today");
2582
+ if (diff === 1) return t("agenda.list.tomorrow");
2583
+ return date.toLocaleDateString(locale, { weekday: "long", day: "numeric", month: "long" });
2584
+ }
2585
+ if (groups.length === 0) {
2586
+ return /* @__PURE__ */ jsx("div", { className: "flex-1 flex flex-col items-center justify-center px-6 py-16 text-center text-muted-foreground", children: /* @__PURE__ */ jsx("p", { className: "text-sm", children: t("agenda.list.empty") }) });
2587
+ }
2588
+ return /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-y-auto px-3 py-3 space-y-5", children: groups.map((g) => /* @__PURE__ */ jsxs("div", { children: [
2589
+ /* @__PURE__ */ jsx("h3", { className: "px-1 pb-1.5 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: dayLabel(g.date) }),
2590
+ /* @__PURE__ */ jsx("div", { className: "space-y-1.5", children: g.items.map((b) => {
2591
+ const color = statusColors[b.status] ?? "#6b7280";
2592
+ const hasAmount = typeof b.orderTotal === "number" && b.orderTotal > 0;
2593
+ return /* @__PURE__ */ jsxs(
2594
+ "button",
2595
+ {
2596
+ onClick: () => onSelect(b),
2597
+ className: "flex w-full items-center gap-3 rounded-lg border bg-card px-3 py-2.5 text-left shadow-sm transition-colors active:bg-muted/50",
2598
+ children: [
2599
+ /* @__PURE__ */ jsx("span", { className: "h-2.5 w-2.5 shrink-0 rounded-full", style: { backgroundColor: color } }),
2600
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
2601
+ /* @__PURE__ */ jsx("p", { className: "truncate text-sm font-medium text-foreground", children: b.clientName ?? "\u2014" }),
2602
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: timeLabel(b.startsAt) })
2603
+ ] }),
2604
+ hasAmount && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-sm font-semibold tabular-nums text-foreground", children: formatCurrency(b.orderTotal, currencyCode) })
2605
+ ]
2606
+ },
2607
+ b.id
2608
+ );
2609
+ }) })
2610
+ ] }, g.key)) });
2611
+ }
2449
2612
  function bookingToEvent(booking, statusColors) {
2450
2613
  const color = statusColors[booking.status] ?? "#6b7280";
2451
2614
  const serviceNames = booking.services?.map((s) => s.name).join(", ") ?? "";
@@ -2568,11 +2731,37 @@ function CalendarSkeleton({ profCount = 2 }) {
2568
2731
  ] }, h)) })
2569
2732
  ] });
2570
2733
  }
2571
- var VIEW_OPTIONS = [
2734
+ var RESOURCE_VIEW_OPTIONS = [
2572
2735
  { key: "resourceTimeGridDay", labelKey: "agenda.calendar.viewDay" },
2573
2736
  { key: "resourceTimeGridWeek", labelKey: "agenda.calendar.viewWeek" },
2574
2737
  { key: "dayGridMonth", labelKey: "agenda.calendar.viewMonth" }
2575
2738
  ];
2739
+ var PLAIN_VIEW_OPTIONS = [
2740
+ { key: "timeGridDay", labelKey: "agenda.calendar.viewDay" },
2741
+ { key: "timeGridWeek", labelKey: "agenda.calendar.viewWeek" },
2742
+ { key: "dayGridMonth", labelKey: "agenda.calendar.viewMonth" },
2743
+ { key: "listMonth", labelKey: "agenda.calendar.viewList" }
2744
+ ];
2745
+ var MOBILE_LIST_VIEW = "__mobileList__";
2746
+ function viewForNoResources(view) {
2747
+ return view.startsWith("resource") ? "dayGridMonth" : view;
2748
+ }
2749
+ function viewForResources(view) {
2750
+ if (view === "timeGridWeek") return "resourceTimeGridWeek";
2751
+ if (view === "timeGridDay") return "resourceTimeGridDay";
2752
+ return view;
2753
+ }
2754
+ function useIsMobile() {
2755
+ const [isMobile, setIsMobile] = useState(() => typeof window !== "undefined" && window.matchMedia("(max-width: 767px)").matches);
2756
+ useEffect(() => {
2757
+ if (typeof window === "undefined") return;
2758
+ const mq = window.matchMedia("(max-width: 767px)");
2759
+ const onChange = () => setIsMobile(mq.matches);
2760
+ mq.addEventListener("change", onChange);
2761
+ return () => mq.removeEventListener("change", onChange);
2762
+ }, []);
2763
+ return isMobile;
2764
+ }
2576
2765
  function CalendarView() {
2577
2766
  injectCalendarStyles();
2578
2767
  const config = useAgendaConfig();
@@ -2605,6 +2794,18 @@ function CalendarView() {
2605
2794
  const _openModal = useAgendaStore((s) => s.openAppointmentModal);
2606
2795
  const closeModal = useAgendaStore((s) => s.closeAppointmentModal);
2607
2796
  const modalState = useAgendaStore((s) => s.appointmentModal);
2797
+ const isMobile = useIsMobile();
2798
+ const resourceCapable = professionals.length > 0;
2799
+ const viewOptions = resourceCapable ? RESOURCE_VIEW_OPTIONS : PLAIN_VIEW_OPTIONS;
2800
+ const [mobileView, setMobileView] = useState(MOBILE_LIST_VIEW);
2801
+ const mobileViewOptions = useMemo(
2802
+ () => [
2803
+ ...viewOptions.filter((o) => o.key !== "listMonth"),
2804
+ { key: MOBILE_LIST_VIEW, labelKey: "agenda.calendar.viewList" }
2805
+ ],
2806
+ [viewOptions]
2807
+ );
2808
+ const mobileGridActive = isMobile && mobileView !== MOBILE_LIST_VIEW;
2608
2809
  const [selectedBooking, setSelectedBooking] = useState(null);
2609
2810
  const [popoverAnchor, setPopoverAnchor] = useState(null);
2610
2811
  const [popoverVisible, _setPopoverVisible] = useState(false);
@@ -2644,6 +2845,24 @@ function CalendarView() {
2644
2845
  fetchSchedules();
2645
2846
  if (config.modules.locationSelection) fetchLocations();
2646
2847
  }, []);
2848
+ useEffect(() => {
2849
+ const api = calendarRef.current?.getApi();
2850
+ if (!api) return;
2851
+ if (!resourceCapable && currentView.startsWith("resource")) {
2852
+ api.changeView("dayGridMonth");
2853
+ } else if (resourceCapable && (currentView === "timeGridWeek" || currentView === "timeGridDay")) {
2854
+ api.changeView(viewForResources(currentView));
2855
+ }
2856
+ }, [resourceCapable, currentView]);
2857
+ useEffect(() => {
2858
+ if (!isMobile) return;
2859
+ const start = /* @__PURE__ */ new Date();
2860
+ start.setHours(0, 0, 0, 0);
2861
+ start.setDate(start.getDate() - 1);
2862
+ const end = new Date(start);
2863
+ end.setDate(end.getDate() + 91);
2864
+ fetchBookings({ start: start.toISOString(), end: end.toISOString() });
2865
+ }, [isMobile, fetchBookings]);
2647
2866
  const resources = useMemo(() => {
2648
2867
  const filtered = selectedProfIds.length > 0 ? professionals.filter((p) => selectedProfIds.includes(p.id)) : professionals;
2649
2868
  return filtered.map((p) => ({
@@ -2668,6 +2887,8 @@ function CalendarView() {
2668
2887
  [schedules, professionals, visibleRange, effectiveBusinessHours, locationMap]
2669
2888
  );
2670
2889
  const events = useMemo(() => [...bookingEvents, ...availabilityEvents], [bookingEvents, availabilityEvents]);
2890
+ const storedView = prefs.get("calendarView");
2891
+ const effectiveInitialView = resourceCapable ? viewForResources(storedView) : viewForNoResources(storedView);
2671
2892
  const handleDatesSet = useCallback((arg) => {
2672
2893
  setCalendarTitle(arg.view.title);
2673
2894
  setView(arg.view.type);
@@ -2784,12 +3005,12 @@ function CalendarView() {
2784
3005
  const locId = schedule?.locationId ?? schedule?.metadata?.locationId;
2785
3006
  openModal("create", { prefill: { startsAt: arg.startStr, endsAt: arg.endStr, professionalId, locationId: locId || void 0 } });
2786
3007
  };
2787
- if (!schedule) {
3008
+ if (config.modules.workingHours && !schedule) {
2788
3009
  setScheduleConfirm({ onConfirm: proceed });
2789
3010
  return;
2790
3011
  }
2791
3012
  proceed();
2792
- }, [openModal, findScheduleForSlot]);
3013
+ }, [openModal, findScheduleForSlot, config.modules.workingHours]);
2793
3014
  const handleEventDrop = useCallback(async (arg) => {
2794
3015
  const booking = arg.event.extendedProps.booking;
2795
3016
  try {
@@ -2802,6 +3023,12 @@ function CalendarView() {
2802
3023
  calendarRef.current?.getApi().changeView(v);
2803
3024
  prefs.set("calendarView", v);
2804
3025
  }, [prefs]);
3026
+ const handleMobileViewChange = useCallback((v) => {
3027
+ setMobileView(v);
3028
+ if (v === MOBILE_LIST_VIEW) return;
3029
+ setView(v);
3030
+ calendarRef.current?.getApi()?.changeView(v);
3031
+ }, [setView]);
2805
3032
  const handlePrev = useCallback(() => calendarRef.current?.getApi().prev(), []);
2806
3033
  const handleNext = useCallback(() => calendarRef.current?.getApi().next(), []);
2807
3034
  const handleToday = useCallback(() => {
@@ -2887,8 +3114,21 @@ function CalendarView() {
2887
3114
  }, [applyResourceStriping, currentView, visibleRange, bookings]);
2888
3115
  useEffect(() => {
2889
3116
  function handleOpenBooking(e) {
2890
- const bookingId = e.detail?.bookingId;
2891
- if (bookingId) openModal("edit", { bookingId });
3117
+ const detail = e.detail ?? {};
3118
+ const externalSource = detail.source ? { type: String(detail.source), id: detail.waitlistId, waitlistId: detail.waitlistId } : void 0;
3119
+ if (detail.bookingId) {
3120
+ openModal("edit", { bookingId: detail.bookingId, externalSource });
3121
+ return;
3122
+ }
3123
+ openModal("create", {
3124
+ prefill: detail.prefill ?? {
3125
+ clientId: detail.clientId,
3126
+ professionalId: detail.professionalId,
3127
+ locationId: detail.locationId,
3128
+ startsAt: detail.startsAt
3129
+ },
3130
+ externalSource
3131
+ });
2892
3132
  }
2893
3133
  window.addEventListener("agenda:open-booking", handleOpenBooking);
2894
3134
  return () => window.removeEventListener("agenda:open-booking", handleOpenBooking);
@@ -2962,110 +3202,135 @@ function CalendarView() {
2962
3202
  }
2963
3203
  ),
2964
3204
  /* @__PURE__ */ jsx(MiniCalendar, { selectedDate, onDateSelect: handleMiniDateSelect }),
2965
- /* @__PURE__ */ jsx("div", { className: "h-px bg-border my-4" }),
2966
- /* @__PURE__ */ jsxs(
2967
- "button",
2968
- {
2969
- onClick: () => setProfSectionOpen((p) => !p),
2970
- className: "flex items-center justify-between w-full text-xs font-medium text-muted-foreground hover:text-foreground py-1 transition-colors",
2971
- children: [
2972
- /* @__PURE__ */ jsx("span", { children: "Agendas" }),
2973
- /* @__PURE__ */ jsx(ChevronDown, { className: `h-3.5 w-3.5 transition-transform ${profSectionOpen ? "" : "-rotate-90"}` })
2974
- ]
2975
- }
2976
- ),
2977
- profSectionOpen && /* @__PURE__ */ jsx("div", { className: "mt-1.5 space-y-0.5", children: professionals.map((prof) => {
2978
- const active = selectedProfIds.length === 0 || selectedProfIds.includes(prof.id);
2979
- return /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2.5 rounded px-1 py-1 cursor-pointer hover:bg-muted/50 transition-colors", children: [
2980
- /* @__PURE__ */ jsx("span", { className: `flex h-4 w-4 shrink-0 items-center justify-center rounded-sm border-2 transition-colors ${active ? "border-primary bg-primary" : "border-muted-foreground/30"}`, children: active && /* @__PURE__ */ jsx("svg", { className: "h-2.5 w-2.5 text-primary-foreground", viewBox: "0 0 12 12", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M2 6l3 3 5-5", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }),
2981
- /* @__PURE__ */ jsx("span", { className: `text-xs truncate ${active ? "text-foreground" : "text-muted-foreground"}`, children: prof.name }),
2982
- /* @__PURE__ */ jsx("input", { type: "checkbox", className: "sr-only", checked: active, onChange: () => toggleProfessional(prof.id) })
2983
- ] }, prof.id);
2984
- }) }),
2985
- /* @__PURE__ */ jsx("div", { className: "h-px bg-border my-4" }),
2986
- /* @__PURE__ */ jsxs(
2987
- "button",
2988
- {
2989
- onClick: () => setStatusSectionOpen((p) => !p),
2990
- className: "flex items-center justify-between w-full text-xs font-medium text-muted-foreground hover:text-foreground py-1 transition-colors",
2991
- children: [
2992
- /* @__PURE__ */ jsx("span", { children: "Status" }),
2993
- /* @__PURE__ */ jsx(ChevronDown, { className: `h-3.5 w-3.5 transition-transform ${statusSectionOpen ? "" : "-rotate-90"}` })
2994
- ]
2995
- }
2996
- ),
2997
- statusSectionOpen && /* @__PURE__ */ jsx("div", { className: "mt-1.5 space-y-0.5", children: config.statuses.map((st) => {
2998
- const active = selectedStatuses.length === 0 || selectedStatuses.includes(st.value);
2999
- return /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2.5 rounded px-1 py-1 cursor-pointer hover:bg-muted/50 transition-colors", children: [
3000
- /* @__PURE__ */ jsx(
3001
- "span",
3002
- {
3003
- className: "flex h-4 w-4 shrink-0 items-center justify-center rounded-sm border-2 transition-colors",
3004
- style: { borderColor: active ? st.color : st.color + "40", backgroundColor: active ? st.color : "transparent" },
3005
- children: active && /* @__PURE__ */ jsx("svg", { className: "h-2.5 w-2.5 text-white", viewBox: "0 0 12 12", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M2 6l3 3 5-5", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })
3006
- }
3007
- ),
3008
- /* @__PURE__ */ jsx("span", { className: `text-xs ${active ? "text-foreground" : "text-muted-foreground"}`, children: st.label }),
3009
- /* @__PURE__ */ jsx("input", { type: "checkbox", className: "sr-only", checked: active, onChange: () => toggleStatus(st.value) })
3010
- ] }, st.value);
3011
- }) })
3205
+ config.capabilities.professional && /* @__PURE__ */ jsxs(Fragment, { children: [
3206
+ /* @__PURE__ */ jsx("div", { className: "h-px bg-border my-4" }),
3207
+ /* @__PURE__ */ jsxs(
3208
+ "button",
3209
+ {
3210
+ onClick: () => setProfSectionOpen((p) => !p),
3211
+ className: "flex items-center justify-between w-full text-xs font-medium text-muted-foreground hover:text-foreground py-1 transition-colors",
3212
+ children: [
3213
+ /* @__PURE__ */ jsx("span", { children: "Agendas" }),
3214
+ /* @__PURE__ */ jsx(ChevronDown, { className: `h-3.5 w-3.5 transition-transform ${profSectionOpen ? "" : "-rotate-90"}` })
3215
+ ]
3216
+ }
3217
+ ),
3218
+ profSectionOpen && /* @__PURE__ */ jsx("div", { className: "mt-1.5 space-y-0.5", children: professionals.map((prof) => {
3219
+ const active = selectedProfIds.length === 0 || selectedProfIds.includes(prof.id);
3220
+ return /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2.5 rounded px-1 py-1 cursor-pointer hover:bg-muted/50 transition-colors", children: [
3221
+ /* @__PURE__ */ jsx("span", { className: `flex h-4 w-4 shrink-0 items-center justify-center rounded-sm border-2 transition-colors ${active ? "border-primary bg-primary" : "border-muted-foreground/30"}`, children: active && /* @__PURE__ */ jsx("svg", { className: "h-2.5 w-2.5 text-primary-foreground", viewBox: "0 0 12 12", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M2 6l3 3 5-5", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }),
3222
+ /* @__PURE__ */ jsx("span", { className: `text-xs truncate ${active ? "text-foreground" : "text-muted-foreground"}`, children: prof.name }),
3223
+ /* @__PURE__ */ jsx("input", { type: "checkbox", className: "sr-only", checked: active, onChange: () => toggleProfessional(prof.id) })
3224
+ ] }, prof.id);
3225
+ }) })
3226
+ ] }),
3227
+ config.capabilities.status && /* @__PURE__ */ jsxs(Fragment, { children: [
3228
+ /* @__PURE__ */ jsx("div", { className: "h-px bg-border my-4" }),
3229
+ /* @__PURE__ */ jsxs(
3230
+ "button",
3231
+ {
3232
+ onClick: () => setStatusSectionOpen((p) => !p),
3233
+ className: "flex items-center justify-between w-full text-xs font-medium text-muted-foreground hover:text-foreground py-1 transition-colors",
3234
+ children: [
3235
+ /* @__PURE__ */ jsx("span", { children: "Status" }),
3236
+ /* @__PURE__ */ jsx(ChevronDown, { className: `h-3.5 w-3.5 transition-transform ${statusSectionOpen ? "" : "-rotate-90"}` })
3237
+ ]
3238
+ }
3239
+ ),
3240
+ statusSectionOpen && /* @__PURE__ */ jsx("div", { className: "mt-1.5 space-y-0.5", children: config.statuses.map((st) => {
3241
+ const active = selectedStatuses.length === 0 || selectedStatuses.includes(st.value);
3242
+ return /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2.5 rounded px-1 py-1 cursor-pointer hover:bg-muted/50 transition-colors", children: [
3243
+ /* @__PURE__ */ jsx(
3244
+ "span",
3245
+ {
3246
+ className: "flex h-4 w-4 shrink-0 items-center justify-center rounded-sm border-2 transition-colors",
3247
+ style: { borderColor: active ? st.color : st.color + "40", backgroundColor: active ? st.color : "transparent" },
3248
+ children: active && /* @__PURE__ */ jsx("svg", { className: "h-2.5 w-2.5 text-white", viewBox: "0 0 12 12", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M2 6l3 3 5-5", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })
3249
+ }
3250
+ ),
3251
+ /* @__PURE__ */ jsx("span", { className: `text-xs ${active ? "text-foreground" : "text-muted-foreground"}`, children: st.label }),
3252
+ /* @__PURE__ */ jsx("input", { type: "checkbox", className: "sr-only", checked: active, onChange: () => toggleStatus(st.value) })
3253
+ ] }, st.value);
3254
+ }) })
3255
+ ] })
3012
3256
  ] }),
3013
3257
  /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col min-w-0 overflow-hidden", children: [
3014
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 h-12 shrink-0 border-b", children: [
3015
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
3016
- /* @__PURE__ */ jsx(
3017
- "button",
3018
- {
3019
- onClick: () => openModal("create"),
3020
- className: "md:hidden flex h-8 w-8 items-center justify-center rounded-full bg-primary text-primary-foreground",
3021
- children: /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" })
3022
- }
3023
- ),
3024
- /* @__PURE__ */ jsx(
3025
- "button",
3026
- {
3027
- onClick: handleToday,
3028
- className: "rounded-md border px-3 py-1 text-sm font-medium hover:bg-muted bg-card shadow-button active:shadow-button-inset transition-colors",
3029
- children: t("agenda.toolbar.today")
3030
- }
3031
- ),
3032
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5", children: [
3033
- /* @__PURE__ */ jsx("button", { onClick: handlePrev, className: "flex h-7 w-7 items-center justify-center rounded-full hover:bg-muted transition-colors", children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-4 w-4" }) }),
3034
- /* @__PURE__ */ jsx("button", { onClick: handleNext, className: "flex h-7 w-7 items-center justify-center rounded-full hover:bg-muted transition-colors", children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4" }) })
3258
+ /* @__PURE__ */ jsxs("div", { className: "shrink-0 border-b", children: [
3259
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between pl-4 pr-14 md:px-4 h-12", children: [
3260
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 min-w-0", children: [
3261
+ /* @__PURE__ */ jsx(
3262
+ "button",
3263
+ {
3264
+ onClick: () => openModal("create"),
3265
+ className: "md:hidden flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-primary text-primary-foreground",
3266
+ children: /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" })
3267
+ }
3268
+ ),
3269
+ /* @__PURE__ */ jsxs("div", { className: `${mobileGridActive ? "flex" : "hidden"} md:flex items-center gap-3`, children: [
3270
+ /* @__PURE__ */ jsx(
3271
+ "button",
3272
+ {
3273
+ onClick: handleToday,
3274
+ className: "rounded-md border px-3 py-1 text-sm font-medium hover:bg-muted bg-card shadow-button active:shadow-button-inset transition-colors",
3275
+ children: t("agenda.toolbar.today")
3276
+ }
3277
+ ),
3278
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5", children: [
3279
+ /* @__PURE__ */ jsx("button", { onClick: handlePrev, className: "flex h-7 w-7 items-center justify-center rounded-full hover:bg-muted transition-colors", children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-4 w-4" }) }),
3280
+ /* @__PURE__ */ jsx("button", { onClick: handleNext, className: "flex h-7 w-7 items-center justify-center rounded-full hover:bg-muted transition-colors", children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4" }) })
3281
+ ] })
3282
+ ] }),
3283
+ /* @__PURE__ */ jsx("h1", { className: "text-base sm:text-lg font-normal truncate", children: isMobile && !mobileGridActive ? t("agenda.calendar.viewAgenda") : calendarTitle })
3035
3284
  ] }),
3036
- /* @__PURE__ */ jsx("h1", { className: "text-base sm:text-lg font-normal truncate", children: calendarTitle })
3285
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 shrink-0", children: [
3286
+ /* @__PURE__ */ jsx("div", { className: "hidden md:flex items-center gap-1", children: viewOptions.map((opt) => /* @__PURE__ */ jsx(
3287
+ "button",
3288
+ {
3289
+ onClick: () => handleViewChange(opt.key),
3290
+ className: `rounded-md px-3 py-1 text-sm transition-colors ${currentView === opt.key ? "bg-primary/10 text-primary font-medium" : "text-muted-foreground hover:bg-muted/50"}`,
3291
+ children: t(opt.labelKey)
3292
+ },
3293
+ opt.key
3294
+ )) }),
3295
+ /* @__PURE__ */ jsx(
3296
+ Button,
3297
+ {
3298
+ variant: "outline",
3299
+ size: "icon",
3300
+ onClick: () => window.location.hash = "/settings/agenda",
3301
+ title: "Agenda Settings",
3302
+ className: "ml-1",
3303
+ children: /* @__PURE__ */ jsx(Settings, { className: "h-4 w-4" })
3304
+ }
3305
+ )
3306
+ ] })
3037
3307
  ] }),
3038
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
3039
- /* @__PURE__ */ jsx("div", { className: "hidden sm:flex items-center gap-1", children: VIEW_OPTIONS.map((opt) => /* @__PURE__ */ jsx(
3040
- "button",
3041
- {
3042
- onClick: () => handleViewChange(opt.key),
3043
- className: `rounded-md px-3 py-1 text-sm transition-colors ${currentView === opt.key ? "bg-primary/10 text-primary font-medium" : "text-muted-foreground hover:bg-muted/50"}`,
3044
- children: t(opt.labelKey)
3045
- },
3046
- opt.key
3047
- )) }),
3048
- /* @__PURE__ */ jsx(
3049
- Button,
3050
- {
3051
- variant: "outline",
3052
- size: "icon",
3053
- onClick: () => window.location.hash = "/settings/agenda",
3054
- title: "Agenda Settings",
3055
- className: "ml-1",
3056
- children: /* @__PURE__ */ jsx(Settings, { className: "h-4 w-4" })
3057
- }
3058
- )
3059
- ] })
3308
+ /* @__PURE__ */ jsx("div", { className: "flex md:hidden items-center gap-1 overflow-x-auto px-3 pb-2", children: mobileViewOptions.map((opt) => /* @__PURE__ */ jsx(
3309
+ "button",
3310
+ {
3311
+ onClick: () => handleMobileViewChange(opt.key),
3312
+ className: `shrink-0 rounded-md px-3 py-1 text-sm transition-colors ${mobileView === opt.key ? "bg-primary/10 text-primary font-medium" : "text-muted-foreground hover:bg-muted/50"}`,
3313
+ children: t(opt.labelKey)
3314
+ },
3315
+ opt.key
3316
+ )) })
3060
3317
  ] }),
3061
- professionalsLoading && professionals.length === 0 ? /* @__PURE__ */ jsx(CalendarSkeleton, { profCount: 2 }) : /* @__PURE__ */ jsx("div", { ref: wrapperRef, className: "flex-1 overflow-hidden agenda-calendar", children: /* @__PURE__ */ jsx(
3318
+ isMobile && !mobileGridActive ? /* @__PURE__ */ jsx(
3319
+ AgendaMobileList,
3320
+ {
3321
+ bookings,
3322
+ statusColors,
3323
+ currencyCode: config.currency.code,
3324
+ onSelect: (b) => openModal("edit", { bookingId: b.id })
3325
+ }
3326
+ ) : professionalsLoading && professionals.length === 0 ? /* @__PURE__ */ jsx(CalendarSkeleton, { profCount: 2 }) : /* @__PURE__ */ jsx("div", { ref: wrapperRef, className: "flex-1 overflow-hidden agenda-calendar", children: /* @__PURE__ */ jsx(
3062
3327
  FullCalendar,
3063
3328
  {
3064
3329
  ref: calendarRef,
3065
3330
  plugins: [dayGridPlugin, timeGridPlugin, resourceTimeGridPlugin, interactionPlugin, listPlugin],
3066
- initialView: prefs.get("calendarView") === "timeGridWeek" ? "resourceTimeGridWeek" : prefs.get("calendarView"),
3331
+ initialView: mobileGridActive ? mobileView : effectiveInitialView,
3067
3332
  schedulerLicenseKey: "CC-Attribution-NonCommercial-NoDerivatives",
3068
- resources,
3333
+ resources: resourceCapable ? resources : void 0,
3069
3334
  events,
3070
3335
  headerToolbar: false,
3071
3336
  locale: fcLocale,
@@ -3155,8 +3420,14 @@ function CalendarView() {
3155
3420
  bookingId: modalState.bookingId,
3156
3421
  prefill: modalState.prefill,
3157
3422
  initialTab: modalState.initialTab,
3423
+ externalSource: modalState.externalSource,
3158
3424
  onClose: closeModal,
3159
- onCreated: (newId) => {
3425
+ onCreated: (newId, source) => {
3426
+ if (config.onBookingCreated) {
3427
+ void Promise.resolve(config.onBookingCreated({ bookingId: newId, source })).catch((error) => {
3428
+ console.error("Failed to run agenda booking-created bridge", error);
3429
+ });
3430
+ }
3160
3431
  setTimeout(() => {
3161
3432
  const booking = bookings.find((b) => b.id === newId);
3162
3433
  if (!booking) return;
@@ -3182,7 +3453,7 @@ function CalendarView() {
3182
3453
  function AgendaPage({ config, provider: provider2, store }) {
3183
3454
  const runtime = usePluginRuntimeOptional();
3184
3455
  const tenantId = runtime?.context.tenant?.id;
3185
- React11.useEffect(() => {
3456
+ React12.useEffect(() => {
3186
3457
  setAgendaTenantId(tenantId);
3187
3458
  return () => setAgendaTenantId(void 0);
3188
3459
  }, [tenantId]);
@@ -3297,7 +3568,8 @@ async function hydrateCanonicalBookings(core, bookings) {
3297
3568
  locationId: booking.location_id,
3298
3569
  metadata: booking.metadata ?? {},
3299
3570
  clientId: booking.party_id,
3300
- clientName: client?.name ?? null,
3571
+ // Simple events (no party) fall back to the title stored in metadata.
3572
+ clientName: client?.name ?? booking.metadata?.title ?? null,
3301
3573
  clientPhone: client?.phone ?? null,
3302
3574
  clientEmail: client?.email ?? null,
3303
3575
  clientAvatarUrl: client?.avatar_url ?? null,
@@ -3375,6 +3647,7 @@ function createSupabaseAgendaProvider() {
3375
3647
  const { data: person } = await core.from("persons").select("name").eq("id", input.clientId).single();
3376
3648
  contactName = person?.name;
3377
3649
  }
3650
+ const eventTitle = input.title?.trim() || void 0;
3378
3651
  const { data: order, error: orderErr } = await core.from("orders").insert({
3379
3652
  tenant_id: tenantId,
3380
3653
  kind: input.kind ?? "appointment",
@@ -3388,7 +3661,8 @@ function createSupabaseAgendaProvider() {
3388
3661
  metadata: {
3389
3662
  source: "agenda",
3390
3663
  ...serviceNames ? { serviceNames, itemsSummary: serviceNames } : {},
3391
- ...contactName ? { contactName } : {}
3664
+ ...contactName ? { contactName } : {},
3665
+ ...eventTitle ? { title: eventTitle } : {}
3392
3666
  }
3393
3667
  }).select("id").single();
3394
3668
  if (orderErr) throw orderErr;
@@ -3406,7 +3680,8 @@ function createSupabaseAgendaProvider() {
3406
3680
  metadata: {
3407
3681
  source: "agenda",
3408
3682
  ...serviceNames ? { serviceNames, itemsSummary: serviceNames } : {},
3409
- ...contactName ? { contactName } : {}
3683
+ ...contactName ? { contactName } : {},
3684
+ ...eventTitle ? { title: eventTitle } : {}
3410
3685
  }
3411
3686
  }).select("id").single();
3412
3687
  if (bookingErr) throw bookingErr;
@@ -3431,11 +3706,14 @@ function createSupabaseAgendaProvider() {
3431
3706
  },
3432
3707
  async updateBooking(id, data) {
3433
3708
  const { core } = getClients();
3434
- const { data: existing, error: existingErr } = await core.from("bookings").select("id, order_id, starts_at, assignee_id").eq("id", id).single();
3709
+ const { data: existing, error: existingErr } = await core.from("bookings").select("id, order_id, starts_at, assignee_id, metadata").eq("id", id).single();
3435
3710
  if (existingErr) throw existingErr;
3436
3711
  const updates = {};
3437
3712
  if (data.startsAt) updates.starts_at = data.startsAt;
3438
3713
  if (data.endsAt) updates.ends_at = data.endsAt;
3714
+ if (data.title !== void 0) {
3715
+ updates.metadata = { ...existing?.metadata ?? {}, title: data.title };
3716
+ }
3439
3717
  if (data.status) {
3440
3718
  updates.status = data.status;
3441
3719
  }
@@ -3841,10 +4119,11 @@ function createSampleSchedules() {
3841
4119
  }
3842
4120
  return schedules;
3843
4121
  }
3844
- function createMockAgendaProvider() {
3845
- const bookings = createSampleBookings();
3846
- const schedules = createSampleSchedules();
3847
- const professionals = [...SAMPLE_PROFESSIONALS];
4122
+ function createMockAgendaProvider(options) {
4123
+ const seed = options?.seed;
4124
+ const bookings = seed?.bookings ? [...seed.bookings] : createSampleBookings();
4125
+ const schedules = seed?.schedules ? [...seed.schedules] : createSampleSchedules();
4126
+ const professionals = seed?.professionals ? [...seed.professionals] : [...SAMPLE_PROFESSIONALS];
3848
4127
  return {
3849
4128
  async getLocations() {
3850
4129
  return [];
@@ -3879,7 +4158,7 @@ function createMockAgendaProvider() {
3879
4158
  locationId: input.locationId ?? null,
3880
4159
  metadata: {},
3881
4160
  clientId: input.clientId,
3882
- clientName: "New Client",
4161
+ clientName: input.title?.trim() || "New Client",
3883
4162
  clientPhone: null,
3884
4163
  clientEmail: null,
3885
4164
  clientAvatarUrl: null,
@@ -3925,6 +4204,7 @@ function createMockAgendaProvider() {
3925
4204
  ...existing,
3926
4205
  ...data.startsAt && { startsAt: data.startsAt },
3927
4206
  ...data.endsAt && { endsAt: data.endsAt },
4207
+ ...data.title !== void 0 && { clientName: data.title },
3928
4208
  ...data.status && { status: data.status },
3929
4209
  ...data.notes !== void 0 && { notes: data.notes ?? null },
3930
4210
  ...data.professionalId && { professionalId: data.professionalId },
@@ -4233,7 +4513,7 @@ function createAgendaStore(provider2, financialBridge) {
4233
4513
  set({ selectedDate: date });
4234
4514
  },
4235
4515
  openAppointmentModal(mode, options) {
4236
- set({ appointmentModal: { open: true, mode, bookingId: options?.bookingId, prefill: options?.prefill, initialTab: options?.initialTab } });
4516
+ set({ appointmentModal: { open: true, mode, bookingId: options?.bookingId, prefill: options?.prefill, initialTab: options?.initialTab, externalSource: options?.externalSource } });
4237
4517
  },
4238
4518
  closeAppointmentModal() {
4239
4519
  set((state) => ({ appointmentModal: { ...state.appointmentModal, open: false } }));
@@ -4424,8 +4704,12 @@ var en = {
4424
4704
  "agenda.calendar.today": "Today",
4425
4705
  "agenda.calendar.viewAgenda": "Agenda",
4426
4706
  "agenda.calendar.viewDay": "Day",
4707
+ "agenda.calendar.viewList": "List",
4427
4708
  "agenda.calendar.viewMonth": "Month",
4428
4709
  "agenda.calendar.viewWeek": "Week",
4710
+ "agenda.list.today": "Today",
4711
+ "agenda.list.tomorrow": "Tomorrow",
4712
+ "agenda.list.empty": "No upcoming items",
4429
4713
  "agenda.confirmations.confirmed": "Confirmed:",
4430
4714
  "agenda.confirmations.empty": "No pending confirmations",
4431
4715
  "agenda.confirmations.emptySubtitle": "All upcoming appointments have been confirmed",
@@ -4436,6 +4720,10 @@ var en = {
4436
4720
  "agenda.confirmations.call": "Call",
4437
4721
  "agenda.confirmations.markConfirmed": "Mark Confirmed",
4438
4722
  "agenda.confirmations.markCancelled": "Mark Cancelled",
4723
+ "agenda.cancellation.loadingReasons": "Loading reasons...",
4724
+ "agenda.cancellation.notesOptional": "Cancellation notes (optional)",
4725
+ "agenda.cancellation.notesRequired": "Cancellation notes required",
4726
+ "agenda.cancellation.selectReason": "Select cancellation reason",
4439
4727
  "agenda.contextMenu.changeStatus": "Change status",
4440
4728
  "agenda.contextMenu.delete": "Delete",
4441
4729
  "agenda.contextMenu.edit": "Edit",
@@ -4536,7 +4824,11 @@ var en = {
4536
4824
  "agenda.appointment.addNotes": "Add notes",
4537
4825
  "agenda.appointment.duration": "Duration (minutes)",
4538
4826
  "agenda.appointment.price": "Price",
4827
+ "agenda.appointment.title": "Title",
4828
+ "agenda.appointment.addTitle": "Add a title",
4829
+ "agenda.appointment.untitled": "(no title)",
4539
4830
  "agenda.bookingType.appointment": "Appointment",
4831
+ "agenda.bookingType.event": "Event",
4540
4832
  "agenda.bookingType.task": "Task",
4541
4833
  "agenda.bookingType.out_of_office": "Out of Office",
4542
4834
  "agenda.bookingType.block": "Block",
@@ -4632,8 +4924,12 @@ var ptBR = {
4632
4924
  "agenda.calendar.today": "Hoje",
4633
4925
  "agenda.calendar.viewAgenda": "Agenda",
4634
4926
  "agenda.calendar.viewDay": "Dia",
4927
+ "agenda.calendar.viewList": "Lista",
4635
4928
  "agenda.calendar.viewMonth": "M\xEAs",
4636
4929
  "agenda.calendar.viewWeek": "Semana",
4930
+ "agenda.list.today": "Hoje",
4931
+ "agenda.list.tomorrow": "Amanh\xE3",
4932
+ "agenda.list.empty": "Nenhum item pr\xF3ximo",
4637
4933
  "agenda.confirmations.confirmed": "Confirmado:",
4638
4934
  "agenda.confirmations.empty": "Nenhuma confirma\xE7\xE3o pendente",
4639
4935
  "agenda.confirmations.emptySubtitle": "Todos os agendamentos futuros foram confirmados",
@@ -4644,6 +4940,10 @@ var ptBR = {
4644
4940
  "agenda.confirmations.call": "Ligar",
4645
4941
  "agenda.confirmations.markConfirmed": "Marcar Confirmado",
4646
4942
  "agenda.confirmations.markCancelled": "Marcar Cancelado",
4943
+ "agenda.cancellation.loadingReasons": "Carregando motivos...",
4944
+ "agenda.cancellation.notesOptional": "Observa\xE7\xF5es do cancelamento (opcional)",
4945
+ "agenda.cancellation.notesRequired": "Observa\xE7\xF5es do cancelamento obrigat\xF3rias",
4946
+ "agenda.cancellation.selectReason": "Selecionar motivo do cancelamento",
4647
4947
  "agenda.contextMenu.changeStatus": "Alterar status",
4648
4948
  "agenda.contextMenu.delete": "Excluir",
4649
4949
  "agenda.contextMenu.edit": "Editar",
@@ -4744,7 +5044,11 @@ var ptBR = {
4744
5044
  "agenda.appointment.addNotes": "Adicionar observa\xE7\xF5es",
4745
5045
  "agenda.appointment.duration": "Dura\xE7\xE3o (minutos)",
4746
5046
  "agenda.appointment.price": "Pre\xE7o",
5047
+ "agenda.appointment.title": "T\xEDtulo",
5048
+ "agenda.appointment.addTitle": "Adicionar um t\xEDtulo",
5049
+ "agenda.appointment.untitled": "(sem t\xEDtulo)",
4747
5050
  "agenda.bookingType.appointment": "Agendamento",
5051
+ "agenda.bookingType.event": "Evento",
4748
5052
  "agenda.bookingType.task": "Tarefa",
4749
5053
  "agenda.bookingType.out_of_office": "Aus\xEAncia",
4750
5054
  "agenda.bookingType.block": "Bloqueio",
@@ -5180,6 +5484,7 @@ function createAgendaPlugin(options) {
5180
5484
  () => createMockAgendaProvider()
5181
5485
  );
5182
5486
  const store = createAgendaStore(provider2, options?.financialBridge);
5487
+ const registries = [...agendaRegistries, ...options?.settingsRegistries ?? []];
5183
5488
  setScheduleBlockConfig({
5184
5489
  defaults: config.scheduleBlockDefaults,
5185
5490
  showServices: !!config.serviceLookup,
@@ -5195,7 +5500,7 @@ function createAgendaPlugin(options) {
5195
5500
  return locations;
5196
5501
  } : void 0
5197
5502
  });
5198
- const PageComponent = () => React11.createElement(AgendaPage, { config, provider: provider2, store });
5503
+ const PageComponent = () => React12.createElement(AgendaPage, { config, provider: provider2, store });
5199
5504
  return {
5200
5505
  id: "agenda",
5201
5506
  name: config.labels.pageTitle,
@@ -5295,18 +5600,18 @@ function createAgendaPlugin(options) {
5295
5600
  permission: { feature: "appointments", action: "read" }
5296
5601
  }
5297
5602
  ],
5298
- registries: agendaRegistries,
5603
+ registries,
5299
5604
  settings: [
5300
5605
  {
5301
5606
  id: "agenda",
5302
5607
  label: "Agenda",
5303
5608
  icon: "Calendar",
5304
- // Standard layout: General | Integrations (Google Calendar addon) | Properties (holidays).
5609
+ // Standard layout: General | Integrations (Google Calendar addon) | Properties.
5305
5610
  component: (() => {
5306
- const AgendaSettingsTab = () => React11.createElement(PluginSettingsPanel, {
5611
+ const AgendaSettingsTab = () => React12.createElement(PluginSettingsPanel, {
5307
5612
  title: "Agenda",
5308
- generalSettings: React11.createElement(AgendaGeneralSettings),
5309
- registries: agendaRegistries,
5613
+ generalSettings: React12.createElement(AgendaGeneralSettings),
5614
+ registries,
5310
5615
  hostPluginId: "agenda",
5311
5616
  routeBase: "/settings/agenda"
5312
5617
  });
@@ -5321,6 +5626,6 @@ function createAgendaPlugin(options) {
5321
5626
  };
5322
5627
  }
5323
5628
 
5324
- export { bookingToEvent2 as bookingToEvent, computeCommissionAmount, createAgendaPlugin, createFinancialBridge, createGoogleCalendarPlugin, createGoogleCalendarProvider, eventToBookingPatch, googleCalendarConnector };
5629
+ export { bookingToEvent2 as bookingToEvent, computeCommissionAmount, createAgendaPlugin, createFinancialBridge, createGoogleCalendarPlugin, createGoogleCalendarProvider, createMockAgendaProvider, eventToBookingPatch, googleCalendarConnector };
5325
5630
  //# sourceMappingURL=index.js.map
5326
5631
  //# sourceMappingURL=index.js.map