@fayz-ai/plugin-agenda 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/index.cjs +412 -201
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +254 -48
- package/dist/index.js.map +1 -1
- package/dist/integrations/google-calendar/GoogleCalendarSettings.d.ts +3 -0
- package/dist/integrations/google-calendar/GoogleCalendarSettings.d.ts.map +1 -0
- package/dist/integrations/google-calendar/connector.d.ts +3 -0
- package/dist/integrations/google-calendar/connector.d.ts.map +1 -0
- package/dist/integrations/google-calendar/connectorDef.d.ts +3 -0
- package/dist/integrations/google-calendar/connectorDef.d.ts.map +1 -0
- package/dist/integrations/google-calendar/data/supabase.d.ts +16 -0
- package/dist/integrations/google-calendar/data/supabase.d.ts.map +1 -0
- package/dist/integrations/google-calendar/index.d.ts +8 -0
- package/dist/integrations/google-calendar/index.d.ts.map +1 -0
- package/dist/integrations/google-calendar/integration.test.d.ts +2 -0
- package/dist/integrations/google-calendar/integration.test.d.ts.map +1 -0
- package/dist/integrations/google-calendar/mapping.d.ts +25 -0
- package/dist/integrations/google-calendar/mapping.d.ts.map +1 -0
- package/dist/integrations/google-calendar/types.d.ts +36 -0
- package/dist/integrations/google-calendar/types.d.ts.map +1 -0
- package/package.json +10 -7
- package/src/index.ts +12 -2
- package/src/integrations/google-calendar/GoogleCalendarSettings.tsx +136 -0
- package/src/integrations/google-calendar/connector.ts +20 -0
- package/src/integrations/google-calendar/connectorDef.tsx +94 -0
- package/src/integrations/google-calendar/data/supabase.ts +74 -0
- package/src/integrations/google-calendar/index.ts +36 -0
- package/src/integrations/google-calendar/integration.test.ts +74 -0
- package/src/integrations/google-calendar/mapping.ts +43 -0
- package/src/integrations/google-calendar/migrations/001_google_calendar.sql +94 -0
- package/src/integrations/google-calendar/types.ts +31 -0
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chunkSYDBDI3Q_cjs = require('./chunk-SYDBDI3Q.cjs');
|
|
4
|
-
var
|
|
4
|
+
var React11 = require('react');
|
|
5
5
|
var core = require('@fayz-ai/core');
|
|
6
6
|
var saas = require('@fayz-ai/saas');
|
|
7
7
|
var FullCalendar = require('@fullcalendar/react');
|
|
@@ -19,7 +19,7 @@ var vanilla = require('zustand/vanilla');
|
|
|
19
19
|
|
|
20
20
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
21
21
|
|
|
22
|
-
var
|
|
22
|
+
var React11__default = /*#__PURE__*/_interopDefault(React11);
|
|
23
23
|
var FullCalendar__default = /*#__PURE__*/_interopDefault(FullCalendar);
|
|
24
24
|
var dayGridPlugin__default = /*#__PURE__*/_interopDefault(dayGridPlugin);
|
|
25
25
|
var timeGridPlugin__default = /*#__PURE__*/_interopDefault(timeGridPlugin);
|
|
@@ -431,10 +431,10 @@ function toDateLocale(locale) {
|
|
|
431
431
|
}
|
|
432
432
|
function MiniCalendar({ selectedDate, onDateSelect, onMonthChange }) {
|
|
433
433
|
const locale = core.getCurrentLocale();
|
|
434
|
-
const [viewMonth, setViewMonth] =
|
|
434
|
+
const [viewMonth, setViewMonth] = React11__default.default.useState(() => new Date(selectedDate.getFullYear(), selectedDate.getMonth(), 1));
|
|
435
435
|
const monthLabel = viewMonth.toLocaleDateString(toDateLocale(locale), { month: "long", year: "numeric" });
|
|
436
436
|
const dayLabels = DAY_LABELS[locale] ?? DAY_LABELS.en;
|
|
437
|
-
const weeks =
|
|
437
|
+
const weeks = React11.useMemo(() => {
|
|
438
438
|
const year = viewMonth.getFullYear();
|
|
439
439
|
const month = viewMonth.getMonth();
|
|
440
440
|
const firstDay = new Date(year, month, 1);
|
|
@@ -505,14 +505,14 @@ function SearchCombobox({
|
|
|
505
505
|
loading,
|
|
506
506
|
onFocus: onFocusProp
|
|
507
507
|
}) {
|
|
508
|
-
const [open, setOpen] =
|
|
509
|
-
const [activeIndex, setActiveIndex] =
|
|
510
|
-
const [expanded, setExpanded] =
|
|
511
|
-
const [dropRect, setDropRect] =
|
|
512
|
-
const inputRef =
|
|
513
|
-
const wrapperRef =
|
|
514
|
-
const listRef =
|
|
515
|
-
|
|
508
|
+
const [open, setOpen] = React11.useState(false);
|
|
509
|
+
const [activeIndex, setActiveIndex] = React11.useState(-1);
|
|
510
|
+
const [expanded, setExpanded] = React11.useState(!inlineLabel);
|
|
511
|
+
const [dropRect, setDropRect] = React11.useState(null);
|
|
512
|
+
const inputRef = React11.useRef(null);
|
|
513
|
+
const wrapperRef = React11.useRef(null);
|
|
514
|
+
const listRef = React11.useRef(null);
|
|
515
|
+
React11.useEffect(() => {
|
|
516
516
|
if (value && inlineLabel) setExpanded(true);
|
|
517
517
|
if (!value && inlineLabel && !open) setExpanded(false);
|
|
518
518
|
}, [value, open]);
|
|
@@ -521,13 +521,13 @@ function SearchCombobox({
|
|
|
521
521
|
}
|
|
522
522
|
const showCreate = open && allowCreate && onCreateNew && value.trim().length > 0 && !options.some((o) => o.label.toLowerCase() === value.trim().toLowerCase());
|
|
523
523
|
const totalItems = options.length + (showCreate ? 1 : 0);
|
|
524
|
-
|
|
524
|
+
React11.useEffect(() => {
|
|
525
525
|
setActiveIndex(-1);
|
|
526
526
|
}, [options]);
|
|
527
|
-
|
|
527
|
+
React11.useEffect(() => {
|
|
528
528
|
if ((options.length > 0 || showCreate || loading) && document.activeElement === inputRef.current) setOpen(true);
|
|
529
529
|
}, [options, showCreate, loading]);
|
|
530
|
-
const handleKeyDown =
|
|
530
|
+
const handleKeyDown = React11.useCallback((e) => {
|
|
531
531
|
if (!open || totalItems === 0) {
|
|
532
532
|
if (e.key === "ArrowDown" && totalItems > 0) {
|
|
533
533
|
e.preventDefault();
|
|
@@ -564,7 +564,7 @@ function SearchCombobox({
|
|
|
564
564
|
break;
|
|
565
565
|
}
|
|
566
566
|
}, [open, options, totalItems, activeIndex, onSelect, showCreate, onCreateNew, value]);
|
|
567
|
-
|
|
567
|
+
React11.useEffect(() => {
|
|
568
568
|
if (activeIndex < 0 || !listRef.current) return;
|
|
569
569
|
const items = listRef.current.children;
|
|
570
570
|
if (items[activeIndex]) items[activeIndex].scrollIntoView({ block: "nearest" });
|
|
@@ -724,23 +724,23 @@ function BookingPaymentPanel({ orderId, orderTotal, services, onClose, onPayment
|
|
|
724
724
|
const t = core.useTranslation();
|
|
725
725
|
const config = useAgendaConfig();
|
|
726
726
|
const bridge = config.financialBridge;
|
|
727
|
-
const [visible, setVisible] =
|
|
728
|
-
const [loading, setLoading] =
|
|
729
|
-
const [detail, setDetail] =
|
|
730
|
-
const [selectedTypeId, setSelectedTypeId] =
|
|
731
|
-
const [paymentTypes, setPaymentTypes] =
|
|
732
|
-
const [bankAccounts, setBankAccounts] =
|
|
733
|
-
const [filteredMethods, setFilteredMethods] =
|
|
734
|
-
const [selectedBankId, setSelectedBankId] =
|
|
735
|
-
const [paymentMethodId, setPaymentMethodId] =
|
|
736
|
-
const [cardBrand, setCardBrand] =
|
|
737
|
-
const [cardInstallments, setCardInstallments] =
|
|
738
|
-
const [processing, setProcessing] =
|
|
739
|
-
const [justPaid, setJustPaid] =
|
|
740
|
-
|
|
727
|
+
const [visible, setVisible] = React11.useState(false);
|
|
728
|
+
const [loading, setLoading] = React11.useState(true);
|
|
729
|
+
const [detail, setDetail] = React11.useState(null);
|
|
730
|
+
const [selectedTypeId, setSelectedTypeId] = React11.useState("");
|
|
731
|
+
const [paymentTypes, setPaymentTypes] = React11.useState([]);
|
|
732
|
+
const [bankAccounts, setBankAccounts] = React11.useState([]);
|
|
733
|
+
const [filteredMethods, setFilteredMethods] = React11.useState([]);
|
|
734
|
+
const [selectedBankId, setSelectedBankId] = React11.useState("");
|
|
735
|
+
const [paymentMethodId, setPaymentMethodId] = React11.useState("");
|
|
736
|
+
const [cardBrand, setCardBrand] = React11.useState("");
|
|
737
|
+
const [cardInstallments, setCardInstallments] = React11.useState(1);
|
|
738
|
+
const [processing, setProcessing] = React11.useState(false);
|
|
739
|
+
const [justPaid, setJustPaid] = React11.useState(false);
|
|
740
|
+
React11.useEffect(() => {
|
|
741
741
|
requestAnimationFrame(() => setVisible(true));
|
|
742
742
|
}, []);
|
|
743
|
-
|
|
743
|
+
React11.useEffect(() => {
|
|
744
744
|
let cancelled = false;
|
|
745
745
|
setLoading(true);
|
|
746
746
|
Promise.all([
|
|
@@ -1043,9 +1043,9 @@ function formatCompactDate(dateStr, locale) {
|
|
|
1043
1043
|
});
|
|
1044
1044
|
}
|
|
1045
1045
|
function InlineNumber({ value, onChange, min = 0, step = 1, className, disabled, tooltip }) {
|
|
1046
|
-
const [draft, setDraft] =
|
|
1047
|
-
const [focused, setFocused] =
|
|
1048
|
-
|
|
1046
|
+
const [draft, setDraft] = React11.useState(String(value));
|
|
1047
|
+
const [focused, setFocused] = React11.useState(false);
|
|
1048
|
+
React11.useEffect(() => {
|
|
1049
1049
|
if (!focused) setDraft(String(value));
|
|
1050
1050
|
}, [value, focused]);
|
|
1051
1051
|
function commit() {
|
|
@@ -1089,11 +1089,11 @@ function InlineNumber({ value, onChange, min = 0, step = 1, className, disabled,
|
|
|
1089
1089
|
] }) });
|
|
1090
1090
|
}
|
|
1091
1091
|
function StatusSelect({ value, onChange, statuses, bookingDate }) {
|
|
1092
|
-
const [open, setOpen] =
|
|
1093
|
-
const ref =
|
|
1094
|
-
const dropdownRef =
|
|
1092
|
+
const [open, setOpen] = React11.useState(false);
|
|
1093
|
+
const ref = React11.useRef(null);
|
|
1094
|
+
const dropdownRef = React11.useRef(null);
|
|
1095
1095
|
const current = statuses.find((s) => s.value === value);
|
|
1096
|
-
|
|
1096
|
+
React11.useEffect(() => {
|
|
1097
1097
|
if (!open) return;
|
|
1098
1098
|
const handler = (e) => {
|
|
1099
1099
|
const target = e.target;
|
|
@@ -1104,8 +1104,8 @@ function StatusSelect({ value, onChange, statuses, bookingDate }) {
|
|
|
1104
1104
|
document.addEventListener("mousedown", handler);
|
|
1105
1105
|
return () => document.removeEventListener("mousedown", handler);
|
|
1106
1106
|
}, [open]);
|
|
1107
|
-
const btnRef =
|
|
1108
|
-
const [dropRect, setDropRect] =
|
|
1107
|
+
const btnRef = React11.useRef(null);
|
|
1108
|
+
const [dropRect, setDropRect] = React11.useState(null);
|
|
1109
1109
|
function handleOpen() {
|
|
1110
1110
|
if (btnRef.current) setDropRect(btnRef.current.getBoundingClientRect());
|
|
1111
1111
|
setOpen((p) => !p);
|
|
@@ -1165,10 +1165,10 @@ function StatusSelect({ value, onChange, statuses, bookingDate }) {
|
|
|
1165
1165
|
}
|
|
1166
1166
|
function ProfessionalSelect({ value, onChange, professionals }) {
|
|
1167
1167
|
const t = core.useTranslation();
|
|
1168
|
-
const [open, setOpen] =
|
|
1169
|
-
const ref =
|
|
1168
|
+
const [open, setOpen] = React11.useState(false);
|
|
1169
|
+
const ref = React11.useRef(null);
|
|
1170
1170
|
const current = professionals.find((p) => p.id === value);
|
|
1171
|
-
|
|
1171
|
+
React11.useEffect(() => {
|
|
1172
1172
|
if (!open) return;
|
|
1173
1173
|
const handler = (e) => {
|
|
1174
1174
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
@@ -1206,10 +1206,10 @@ function ProfessionalSelect({ value, onChange, professionals }) {
|
|
|
1206
1206
|
}
|
|
1207
1207
|
function LocationSelect({ value, onChange, locations }) {
|
|
1208
1208
|
const t = core.useTranslation();
|
|
1209
|
-
const [open, setOpen] =
|
|
1210
|
-
const ref =
|
|
1209
|
+
const [open, setOpen] = React11.useState(false);
|
|
1210
|
+
const ref = React11.useRef(null);
|
|
1211
1211
|
const current = locations.find((l) => l.id === value);
|
|
1212
|
-
|
|
1212
|
+
React11.useEffect(() => {
|
|
1213
1213
|
if (!open) return;
|
|
1214
1214
|
const handler = (e) => {
|
|
1215
1215
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
@@ -1249,8 +1249,8 @@ function AppointmentModal({ open, mode, bookingId, prefill, initialTab, onClose,
|
|
|
1249
1249
|
const t = core.useTranslation();
|
|
1250
1250
|
const locale = core.getCurrentLocale();
|
|
1251
1251
|
const config = useAgendaConfig();
|
|
1252
|
-
const
|
|
1253
|
-
const initialSnapshot =
|
|
1252
|
+
const provider2 = useAgendaProvider();
|
|
1253
|
+
const initialSnapshot = React11.useRef("");
|
|
1254
1254
|
const createBooking = useAgendaStore((s) => s.createBooking);
|
|
1255
1255
|
const updateBooking = useAgendaStore((s) => s.updateBooking);
|
|
1256
1256
|
const deleteBooking = useAgendaStore((s) => s.deleteBooking);
|
|
@@ -1258,54 +1258,54 @@ function AppointmentModal({ open, mode, bookingId, prefill, initialTab, onClose,
|
|
|
1258
1258
|
const agendaDateRange = useAgendaStore((s) => s.dateRange);
|
|
1259
1259
|
const professionals = useAgendaStore((s) => s.professionals);
|
|
1260
1260
|
const storeLocations = useAgendaStore((s) => s.locations);
|
|
1261
|
-
const [loading, setLoading] =
|
|
1262
|
-
const [bookingType, setBookingType] =
|
|
1263
|
-
const [clientId, setClientId] =
|
|
1264
|
-
const [clientSearch, setClientSearch] =
|
|
1265
|
-
const [clientPhone, setClientPhone] =
|
|
1266
|
-
const [professionalId, setProfessionalId] =
|
|
1267
|
-
const [locationId, setLocationId] =
|
|
1268
|
-
const [services, setServices] =
|
|
1269
|
-
const [serviceSearch, setServiceSearch] =
|
|
1270
|
-
const [date, setDate] =
|
|
1261
|
+
const [loading, setLoading] = React11.useState(mode === "edit");
|
|
1262
|
+
const [bookingType, setBookingType] = React11.useState(prefill?.kind ?? "appointment");
|
|
1263
|
+
const [clientId, setClientId] = React11.useState(prefill?.clientId ?? "");
|
|
1264
|
+
const [clientSearch, setClientSearch] = React11.useState("");
|
|
1265
|
+
const [clientPhone, setClientPhone] = React11.useState("");
|
|
1266
|
+
const [professionalId, setProfessionalId] = React11.useState(prefill?.professionalId ?? "");
|
|
1267
|
+
const [locationId, setLocationId] = React11.useState(prefill?.locationId ?? "");
|
|
1268
|
+
const [services, setServices] = React11.useState([]);
|
|
1269
|
+
const [serviceSearch, setServiceSearch] = React11.useState("");
|
|
1270
|
+
const [date, setDate] = React11.useState(() => {
|
|
1271
1271
|
if (prefill?.startsAt) return prefill.startsAt.slice(0, 10);
|
|
1272
1272
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
1273
1273
|
});
|
|
1274
|
-
const [startTime, setStartTime] =
|
|
1274
|
+
const [startTime, setStartTime] = React11.useState(() => {
|
|
1275
1275
|
if (prefill?.startsAt) {
|
|
1276
1276
|
const d = new Date(prefill.startsAt);
|
|
1277
1277
|
return `${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}`;
|
|
1278
1278
|
}
|
|
1279
1279
|
return "09:00";
|
|
1280
1280
|
});
|
|
1281
|
-
const [status, setStatus] =
|
|
1282
|
-
const [notes, setNotes] =
|
|
1283
|
-
const [showNotes, setShowNotes] =
|
|
1284
|
-
const [saving, setSaving] =
|
|
1285
|
-
const [conflict, setConflict] =
|
|
1286
|
-
const [quickCreate, setQuickCreate] =
|
|
1287
|
-
const [newClientName, setNewClientName] =
|
|
1288
|
-
const [newClientPhone, setNewClientPhone] =
|
|
1289
|
-
const [newClientEmail, setNewClientEmail] =
|
|
1290
|
-
const [creatingClient, setCreatingClient] =
|
|
1291
|
-
const [clientOptions, setClientOptions] =
|
|
1292
|
-
const [clientSearching, setClientSearching] =
|
|
1293
|
-
const [serviceOptions, setServiceOptions] =
|
|
1294
|
-
const [initialServiceOptions, setInitialServiceOptions] =
|
|
1295
|
-
const [editingDate, setEditingDate] =
|
|
1296
|
-
const [editingTime, setEditingTime] =
|
|
1297
|
-
const [confirmingDelete, setConfirmingDelete] =
|
|
1298
|
-
const [deleting, setDeleting] =
|
|
1299
|
-
const [editOrderId, setEditOrderId] =
|
|
1300
|
-
const [editOrderTotal, setEditOrderTotal] =
|
|
1301
|
-
const [editPaymentStatus, setEditPaymentStatus] =
|
|
1302
|
-
const [paymentStatusLoading, setPaymentStatusLoading] =
|
|
1303
|
-
const [modalTab, setModalTab] =
|
|
1304
|
-
const [clientData, setClientData] =
|
|
1305
|
-
const [clientDataLoading, setClientDataLoading] =
|
|
1306
|
-
const [clientEditing, setClientEditing] =
|
|
1281
|
+
const [status, setStatus] = React11.useState("scheduled");
|
|
1282
|
+
const [notes, setNotes] = React11.useState("");
|
|
1283
|
+
const [showNotes, setShowNotes] = React11.useState(false);
|
|
1284
|
+
const [saving, setSaving] = React11.useState(false);
|
|
1285
|
+
const [conflict, setConflict] = React11.useState(false);
|
|
1286
|
+
const [quickCreate, setQuickCreate] = React11.useState(false);
|
|
1287
|
+
const [newClientName, setNewClientName] = React11.useState("");
|
|
1288
|
+
const [newClientPhone, setNewClientPhone] = React11.useState("");
|
|
1289
|
+
const [newClientEmail, setNewClientEmail] = React11.useState("");
|
|
1290
|
+
const [creatingClient, setCreatingClient] = React11.useState(false);
|
|
1291
|
+
const [clientOptions, setClientOptions] = React11.useState([]);
|
|
1292
|
+
const [clientSearching, setClientSearching] = React11.useState(false);
|
|
1293
|
+
const [serviceOptions, setServiceOptions] = React11.useState([]);
|
|
1294
|
+
const [initialServiceOptions, setInitialServiceOptions] = React11.useState([]);
|
|
1295
|
+
const [editingDate, setEditingDate] = React11.useState(false);
|
|
1296
|
+
const [editingTime, setEditingTime] = React11.useState(false);
|
|
1297
|
+
const [confirmingDelete, setConfirmingDelete] = React11.useState(false);
|
|
1298
|
+
const [deleting, setDeleting] = React11.useState(false);
|
|
1299
|
+
const [editOrderId, setEditOrderId] = React11.useState(null);
|
|
1300
|
+
const [editOrderTotal, setEditOrderTotal] = React11.useState(0);
|
|
1301
|
+
const [editPaymentStatus, setEditPaymentStatus] = React11.useState("none");
|
|
1302
|
+
const [paymentStatusLoading, setPaymentStatusLoading] = React11.useState(false);
|
|
1303
|
+
const [modalTab, setModalTab] = React11.useState("appointment");
|
|
1304
|
+
const [clientData, setClientData] = React11.useState(null);
|
|
1305
|
+
const [clientDataLoading, setClientDataLoading] = React11.useState(false);
|
|
1306
|
+
const [clientEditing, setClientEditing] = React11.useState(false);
|
|
1307
1307
|
const activeType = config.bookingTypes.find((bt) => bt.id === bookingType) ?? config.bookingTypes[0];
|
|
1308
|
-
|
|
1308
|
+
React11.useEffect(() => {
|
|
1309
1309
|
if (!open) return;
|
|
1310
1310
|
setClientId(prefill?.clientId ?? "");
|
|
1311
1311
|
setClientSearch("");
|
|
@@ -1350,10 +1350,10 @@ function AppointmentModal({ open, mode, bookingId, prefill, initialTab, onClose,
|
|
|
1350
1350
|
return "09:00";
|
|
1351
1351
|
});
|
|
1352
1352
|
}, [open]);
|
|
1353
|
-
|
|
1353
|
+
React11.useEffect(() => {
|
|
1354
1354
|
if (!open || mode !== "edit" || !bookingId) return;
|
|
1355
1355
|
setLoading(true);
|
|
1356
|
-
|
|
1356
|
+
provider2.getBookingById(bookingId).then((b) => {
|
|
1357
1357
|
if (!b) {
|
|
1358
1358
|
setLoading(false);
|
|
1359
1359
|
return;
|
|
@@ -1403,7 +1403,7 @@ function AppointmentModal({ open, mode, bookingId, prefill, initialTab, onClose,
|
|
|
1403
1403
|
}
|
|
1404
1404
|
}).catch(() => setLoading(false));
|
|
1405
1405
|
}, [open, mode, bookingId]);
|
|
1406
|
-
|
|
1406
|
+
React11.useEffect(() => {
|
|
1407
1407
|
if (modalTab !== "client" || !clientId || !config.contactLookup || clientData) return;
|
|
1408
1408
|
setClientDataLoading(true);
|
|
1409
1409
|
config.contactLookup.getById(clientId).then((result) => {
|
|
@@ -1411,7 +1411,7 @@ function AppointmentModal({ open, mode, bookingId, prefill, initialTab, onClose,
|
|
|
1411
1411
|
setClientDataLoading(false);
|
|
1412
1412
|
}).catch(() => setClientDataLoading(false));
|
|
1413
1413
|
}, [modalTab, clientId]);
|
|
1414
|
-
|
|
1414
|
+
React11.useEffect(() => {
|
|
1415
1415
|
if (!open || !config.serviceLookup) return;
|
|
1416
1416
|
const lookup = config.serviceLookup;
|
|
1417
1417
|
const fetch = lookup.list ? () => lookup.list() : () => lookup.search("");
|
|
@@ -1420,7 +1420,7 @@ function AppointmentModal({ open, mode, bookingId, prefill, initialTab, onClose,
|
|
|
1420
1420
|
setInitialServiceOptions(opts);
|
|
1421
1421
|
}).catch(() => setInitialServiceOptions([]));
|
|
1422
1422
|
}, [open]);
|
|
1423
|
-
|
|
1423
|
+
React11.useEffect(() => {
|
|
1424
1424
|
if (!config.contactLookup || clientSearch.length < 1 || clientId) {
|
|
1425
1425
|
setClientOptions([]);
|
|
1426
1426
|
setClientSearching(false);
|
|
@@ -1438,7 +1438,7 @@ function AppointmentModal({ open, mode, bookingId, prefill, initialTab, onClose,
|
|
|
1438
1438
|
}, 250);
|
|
1439
1439
|
return () => clearTimeout(timer);
|
|
1440
1440
|
}, [clientSearch, clientId]);
|
|
1441
|
-
|
|
1441
|
+
React11.useEffect(() => {
|
|
1442
1442
|
if (!config.serviceLookup || serviceSearch.length < 1) {
|
|
1443
1443
|
setServiceOptions([]);
|
|
1444
1444
|
return;
|
|
@@ -1454,25 +1454,25 @@ function AppointmentModal({ open, mode, bookingId, prefill, initialTab, onClose,
|
|
|
1454
1454
|
return () => clearTimeout(timer);
|
|
1455
1455
|
}, [serviceSearch]);
|
|
1456
1456
|
const serviceDuration = services.reduce((sum, s) => sum + s.durationMinutes, 0);
|
|
1457
|
-
const selectionDuration =
|
|
1457
|
+
const selectionDuration = React11.useMemo(() => {
|
|
1458
1458
|
if (!prefill?.startsAt || !prefill?.endsAt) return 0;
|
|
1459
1459
|
return Math.round((new Date(prefill.endsAt).getTime() - new Date(prefill.startsAt).getTime()) / 6e4);
|
|
1460
1460
|
}, [prefill?.startsAt, prefill?.endsAt]);
|
|
1461
1461
|
const totalDuration = serviceDuration > 0 ? serviceDuration : selectionDuration;
|
|
1462
1462
|
const totalPrice = services.reduce((sum, s) => sum + s.price, 0);
|
|
1463
1463
|
const { currency } = config;
|
|
1464
|
-
const endTime =
|
|
1464
|
+
const endTime = React11.useMemo(() => {
|
|
1465
1465
|
const [h, m] = startTime.split(":").map(Number);
|
|
1466
1466
|
const total = h * 60 + m + totalDuration;
|
|
1467
1467
|
return `${String(Math.floor(total / 60) % 24).padStart(2, "0")}:${String(total % 60).padStart(2, "0")}`;
|
|
1468
1468
|
}, [startTime, totalDuration]);
|
|
1469
|
-
|
|
1469
|
+
React11.useEffect(() => {
|
|
1470
1470
|
if (!professionalId || totalDuration === 0) {
|
|
1471
1471
|
setConflict(false);
|
|
1472
1472
|
return;
|
|
1473
1473
|
}
|
|
1474
1474
|
const timer = setTimeout(() => {
|
|
1475
|
-
|
|
1475
|
+
provider2.checkConflict({
|
|
1476
1476
|
assigneeId: professionalId,
|
|
1477
1477
|
startsAt: `${date}T${startTime}:00`,
|
|
1478
1478
|
endsAt: `${date}T${endTime}:00`,
|
|
@@ -1541,7 +1541,7 @@ function AppointmentModal({ open, mode, bookingId, prefill, initialTab, onClose,
|
|
|
1541
1541
|
setDeleting(false);
|
|
1542
1542
|
}
|
|
1543
1543
|
const isPaidBooking = editPaymentStatus === "paid";
|
|
1544
|
-
const formSnapshot =
|
|
1544
|
+
const formSnapshot = React11.useMemo(
|
|
1545
1545
|
() => JSON.stringify({ clientId, professionalId, locationId, date, startTime, status, notes, services: services.map((s) => ({ id: s.serviceId, dur: s.durationMinutes, price: s.price })) }),
|
|
1546
1546
|
[clientId, professionalId, locationId, date, startTime, status, notes, services]
|
|
1547
1547
|
);
|
|
@@ -1667,8 +1667,8 @@ function AppointmentModal({ open, mode, bookingId, prefill, initialTab, onClose,
|
|
|
1667
1667
|
onCancel: () => setClientEditing(false),
|
|
1668
1668
|
onSubmit: async (data) => {
|
|
1669
1669
|
try {
|
|
1670
|
-
const { getSupabaseClientOptional:
|
|
1671
|
-
const supabase =
|
|
1670
|
+
const { getSupabaseClientOptional: getSupabaseClientOptional4 } = await import('@fayz-ai/core');
|
|
1671
|
+
const supabase = getSupabaseClientOptional4();
|
|
1672
1672
|
if (!supabase) return;
|
|
1673
1673
|
const dbData = {};
|
|
1674
1674
|
for (const [k, v] of Object.entries(data)) {
|
|
@@ -1815,9 +1815,9 @@ function AppointmentModal({ open, mode, bookingId, prefill, initialTab, onClose,
|
|
|
1815
1815
|
onClick: async () => {
|
|
1816
1816
|
setCreatingClient(true);
|
|
1817
1817
|
try {
|
|
1818
|
-
const { getSupabaseClientOptional:
|
|
1818
|
+
const { getSupabaseClientOptional: getSupabaseClientOptional4 } = await import('@fayz-ai/core');
|
|
1819
1819
|
const { getAgendaTenantId: getAgendaTenantId2 } = await import('./tenant-222EHYUC.cjs');
|
|
1820
|
-
const supabase =
|
|
1820
|
+
const supabase = getSupabaseClientOptional4();
|
|
1821
1821
|
const tenantId = getAgendaTenantId2();
|
|
1822
1822
|
if (!supabase || !tenantId) throw new Error("Not initialized");
|
|
1823
1823
|
const { data: personRow, error: personError } = await supabase.schema("saas_core").from("persons").insert({
|
|
@@ -1840,8 +1840,8 @@ function AppointmentModal({ open, mode, bookingId, prefill, initialTab, onClose,
|
|
|
1840
1840
|
setClientSearch(personRow.name);
|
|
1841
1841
|
setQuickCreate(false);
|
|
1842
1842
|
} catch (err) {
|
|
1843
|
-
const { toast:
|
|
1844
|
-
|
|
1843
|
+
const { toast: toast3 } = await import('@fayz-ai/ui');
|
|
1844
|
+
toast3.error(t("agenda.appointment.createClientFailed"), { description: err?.message });
|
|
1845
1845
|
}
|
|
1846
1846
|
setCreatingClient(false);
|
|
1847
1847
|
},
|
|
@@ -2060,19 +2060,19 @@ function FloatingPanel({
|
|
|
2060
2060
|
children,
|
|
2061
2061
|
zIndex = 100
|
|
2062
2062
|
}) {
|
|
2063
|
-
const ref =
|
|
2064
|
-
const [phase, setPhase] =
|
|
2065
|
-
const phaseRef =
|
|
2063
|
+
const ref = React11.useRef(null);
|
|
2064
|
+
const [phase, setPhase] = React11.useState("visible");
|
|
2065
|
+
const phaseRef = React11.useRef("visible");
|
|
2066
2066
|
phaseRef.current = phase;
|
|
2067
|
-
const onCloseRef =
|
|
2067
|
+
const onCloseRef = React11.useRef(onClose);
|
|
2068
2068
|
onCloseRef.current = onClose;
|
|
2069
|
-
const expandCallbackRef =
|
|
2070
|
-
const dismiss =
|
|
2069
|
+
const expandCallbackRef = React11.useRef(null);
|
|
2070
|
+
const dismiss = React11.useCallback(() => {
|
|
2071
2071
|
if (phaseRef.current !== "visible") return;
|
|
2072
2072
|
setPhase("dismissing");
|
|
2073
2073
|
setTimeout(() => onCloseRef.current(), 150);
|
|
2074
2074
|
}, []);
|
|
2075
|
-
const expandThen =
|
|
2075
|
+
const expandThen = React11.useCallback((callback) => {
|
|
2076
2076
|
if (phaseRef.current !== "visible") return;
|
|
2077
2077
|
expandCallbackRef.current = callback;
|
|
2078
2078
|
setPhase("expanding");
|
|
@@ -2081,7 +2081,7 @@ function FloatingPanel({
|
|
|
2081
2081
|
onCloseRef.current();
|
|
2082
2082
|
}, 220);
|
|
2083
2083
|
}, []);
|
|
2084
|
-
|
|
2084
|
+
React11.useEffect(() => {
|
|
2085
2085
|
function handleClick(e) {
|
|
2086
2086
|
if (phaseRef.current !== "visible") return;
|
|
2087
2087
|
if (ref.current && !ref.current.contains(e.target)) {
|
|
@@ -2132,10 +2132,10 @@ function fmtCurrency2(amount, locale, code) {
|
|
|
2132
2132
|
return new Intl.NumberFormat(locale, { style: "currency", currency: code }).format(amount);
|
|
2133
2133
|
}
|
|
2134
2134
|
function PopoverStatusSelect({ value, statuses, bookingStartsAt, onChange }) {
|
|
2135
|
-
const [open, setOpen] =
|
|
2136
|
-
const ref =
|
|
2135
|
+
const [open, setOpen] = React11.useState(false);
|
|
2136
|
+
const ref = React11.useRef(null);
|
|
2137
2137
|
const current = statuses.find((s) => s.value === value);
|
|
2138
|
-
|
|
2138
|
+
React11.useEffect(() => {
|
|
2139
2139
|
if (!open) return;
|
|
2140
2140
|
const h = (e) => {
|
|
2141
2141
|
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
|
|
@@ -2188,8 +2188,8 @@ function AppointmentPopover({ booking, position, onClose, onEdit }) {
|
|
|
2188
2188
|
const deleteBooking = useAgendaStore((s) => s.deleteBooking);
|
|
2189
2189
|
const updateStatus = useAgendaStore((s) => s.updateBookingStatus);
|
|
2190
2190
|
const openModal = useAgendaStore((s) => s.openAppointmentModal);
|
|
2191
|
-
const [confirmingDelete, setConfirmingDelete] =
|
|
2192
|
-
const [deleting, setDeleting] =
|
|
2191
|
+
const [confirmingDelete, setConfirmingDelete] = React11.useState(false);
|
|
2192
|
+
const [deleting, setDeleting] = React11.useState(false);
|
|
2193
2193
|
const statusConfig = config.statuses.find((s) => s.value === booking.status);
|
|
2194
2194
|
const color = statusConfig?.color ?? "#6b7280";
|
|
2195
2195
|
const timeRange = `${fmtTime(booking.startsAt)}${booking.endsAt ? " \u2013 " + fmtTime(booking.endsAt) : ""}`;
|
|
@@ -2347,9 +2347,9 @@ function Tooltip2({ anchor, label }) {
|
|
|
2347
2347
|
);
|
|
2348
2348
|
}
|
|
2349
2349
|
function StatusDot({ color, label, isActive, disabled, onClick }) {
|
|
2350
|
-
const [hover, setHover] =
|
|
2351
|
-
const btnRef =
|
|
2352
|
-
const [rect, setRect] =
|
|
2350
|
+
const [hover, setHover] = React11.useState(false);
|
|
2351
|
+
const btnRef = React11.useRef(null);
|
|
2352
|
+
const [rect, setRect] = React11.useState(null);
|
|
2353
2353
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2354
2354
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2355
2355
|
"button",
|
|
@@ -2376,8 +2376,8 @@ function EventContextMenu({ booking, position, onClose, onEdit }) {
|
|
|
2376
2376
|
const config = useAgendaConfig();
|
|
2377
2377
|
const updateStatus = useAgendaStore((s) => s.updateBookingStatus);
|
|
2378
2378
|
const deleteBooking = useAgendaStore((s) => s.deleteBooking);
|
|
2379
|
-
const [confirming, setConfirming] =
|
|
2380
|
-
const [deleting, setDeleting] =
|
|
2379
|
+
const [confirming, setConfirming] = React11.useState(false);
|
|
2380
|
+
const [deleting, setDeleting] = React11.useState(false);
|
|
2381
2381
|
async function handleDelete() {
|
|
2382
2382
|
setDeleting(true);
|
|
2383
2383
|
try {
|
|
@@ -2592,7 +2592,7 @@ function CalendarView() {
|
|
|
2592
2592
|
const t = core.useTranslation();
|
|
2593
2593
|
const currentLocale = core.getCurrentLocale();
|
|
2594
2594
|
const fcLocale = currentLocale === "pt-BR" ? ptBrLocale__default.default : void 0;
|
|
2595
|
-
const calendarRef =
|
|
2595
|
+
const calendarRef = React11.useRef(null);
|
|
2596
2596
|
const prefs = saas.usePluginPrefs("agenda", { calendarView: config.defaultCalendarView ?? "resourceTimeGridWeek" });
|
|
2597
2597
|
const agendaSettings = useAgendaSettings();
|
|
2598
2598
|
const effectiveBusinessHours = {
|
|
@@ -2618,28 +2618,28 @@ function CalendarView() {
|
|
|
2618
2618
|
const _openModal = useAgendaStore((s) => s.openAppointmentModal);
|
|
2619
2619
|
const closeModal = useAgendaStore((s) => s.closeAppointmentModal);
|
|
2620
2620
|
const modalState = useAgendaStore((s) => s.appointmentModal);
|
|
2621
|
-
const [selectedBooking, setSelectedBooking] =
|
|
2622
|
-
const [popoverAnchor, setPopoverAnchor] =
|
|
2623
|
-
const [popoverVisible, _setPopoverVisible] =
|
|
2624
|
-
const popoverVisibleRef =
|
|
2625
|
-
const setPopoverVisible =
|
|
2621
|
+
const [selectedBooking, setSelectedBooking] = React11.useState(null);
|
|
2622
|
+
const [popoverAnchor, setPopoverAnchor] = React11.useState(null);
|
|
2623
|
+
const [popoverVisible, _setPopoverVisible] = React11.useState(false);
|
|
2624
|
+
const popoverVisibleRef = React11.useRef(false);
|
|
2625
|
+
const setPopoverVisible = React11.useCallback((v) => {
|
|
2626
2626
|
popoverVisibleRef.current = v;
|
|
2627
2627
|
_setPopoverVisible(v);
|
|
2628
2628
|
}, []);
|
|
2629
|
-
const [contextMenu, setContextMenu] =
|
|
2630
|
-
const [contextMenuVisible, _setContextMenuVisible] =
|
|
2631
|
-
const contextMenuVisibleRef =
|
|
2632
|
-
const setContextMenuVisible =
|
|
2629
|
+
const [contextMenu, setContextMenu] = React11.useState(null);
|
|
2630
|
+
const [contextMenuVisible, _setContextMenuVisible] = React11.useState(false);
|
|
2631
|
+
const contextMenuVisibleRef = React11.useRef(false);
|
|
2632
|
+
const setContextMenuVisible = React11.useCallback((v) => {
|
|
2633
2633
|
contextMenuVisibleRef.current = v;
|
|
2634
2634
|
_setContextMenuVisible(v);
|
|
2635
2635
|
}, []);
|
|
2636
|
-
const [scheduleConfirm, setScheduleConfirm] =
|
|
2637
|
-
const [calendarTitle, setCalendarTitle] =
|
|
2638
|
-
const [selectedDate, setSelectedDate] =
|
|
2639
|
-
const [profSectionOpen, setProfSectionOpen] =
|
|
2640
|
-
const [statusSectionOpen, setStatusSectionOpen] =
|
|
2641
|
-
const [visibleRange, setVisibleRange] =
|
|
2642
|
-
const openModal =
|
|
2636
|
+
const [scheduleConfirm, setScheduleConfirm] = React11.useState(null);
|
|
2637
|
+
const [calendarTitle, setCalendarTitle] = React11.useState("");
|
|
2638
|
+
const [selectedDate, setSelectedDate] = React11.useState(/* @__PURE__ */ new Date());
|
|
2639
|
+
const [profSectionOpen, setProfSectionOpen] = React11.useState(true);
|
|
2640
|
+
const [statusSectionOpen, setStatusSectionOpen] = React11.useState(false);
|
|
2641
|
+
const [visibleRange, setVisibleRange] = React11.useState(null);
|
|
2642
|
+
const openModal = React11.useCallback((...args) => {
|
|
2643
2643
|
setPopoverVisible(false);
|
|
2644
2644
|
setSelectedBooking(null);
|
|
2645
2645
|
setPopoverAnchor(null);
|
|
@@ -2647,17 +2647,17 @@ function CalendarView() {
|
|
|
2647
2647
|
setContextMenu(null);
|
|
2648
2648
|
_openModal(...args);
|
|
2649
2649
|
}, [_openModal]);
|
|
2650
|
-
const statusColors =
|
|
2650
|
+
const statusColors = React11.useMemo(() => {
|
|
2651
2651
|
const map = {};
|
|
2652
2652
|
for (const s of config.statuses) map[s.value] = s.color;
|
|
2653
2653
|
return map;
|
|
2654
2654
|
}, [config.statuses]);
|
|
2655
|
-
|
|
2655
|
+
React11.useEffect(() => {
|
|
2656
2656
|
fetchProfessionals();
|
|
2657
2657
|
fetchSchedules();
|
|
2658
2658
|
if (config.modules.locationSelection) fetchLocations();
|
|
2659
2659
|
}, []);
|
|
2660
|
-
const resources =
|
|
2660
|
+
const resources = React11.useMemo(() => {
|
|
2661
2661
|
const filtered = selectedProfIds.length > 0 ? professionals.filter((p) => selectedProfIds.includes(p.id)) : professionals;
|
|
2662
2662
|
return filtered.map((p) => ({
|
|
2663
2663
|
id: p.id,
|
|
@@ -2665,29 +2665,29 @@ function CalendarView() {
|
|
|
2665
2665
|
extendedProps: { avatarUrl: p.avatarUrl, locationName: p.locationName }
|
|
2666
2666
|
}));
|
|
2667
2667
|
}, [professionals, selectedProfIds]);
|
|
2668
|
-
const bookingEvents =
|
|
2669
|
-
const allLocations =
|
|
2668
|
+
const bookingEvents = React11.useMemo(() => bookings.map((b) => bookingToEvent(b, statusColors)), [bookings, statusColors]);
|
|
2669
|
+
const allLocations = React11.useMemo(() => {
|
|
2670
2670
|
const map = /* @__PURE__ */ new Map();
|
|
2671
2671
|
for (const loc of config.locations) map.set(loc.id, loc.name);
|
|
2672
2672
|
for (const loc of storeLocations) map.set(loc.id, loc.name);
|
|
2673
2673
|
return map;
|
|
2674
2674
|
}, [config.locations, storeLocations]);
|
|
2675
|
-
const locationMap =
|
|
2675
|
+
const locationMap = React11.useMemo(() => {
|
|
2676
2676
|
if (!config.modules.locationSelection || allLocations.size === 0) return void 0;
|
|
2677
2677
|
return allLocations;
|
|
2678
2678
|
}, [config.modules.locationSelection, allLocations]);
|
|
2679
|
-
const availabilityEvents =
|
|
2679
|
+
const availabilityEvents = React11.useMemo(
|
|
2680
2680
|
() => generateAvailabilityEvents(schedules, professionals, visibleRange, effectiveBusinessHours, locationMap),
|
|
2681
2681
|
[schedules, professionals, visibleRange, effectiveBusinessHours, locationMap]
|
|
2682
2682
|
);
|
|
2683
|
-
const events =
|
|
2684
|
-
const handleDatesSet =
|
|
2683
|
+
const events = React11.useMemo(() => [...bookingEvents, ...availabilityEvents], [bookingEvents, availabilityEvents]);
|
|
2684
|
+
const handleDatesSet = React11.useCallback((arg) => {
|
|
2685
2685
|
setCalendarTitle(arg.view.title);
|
|
2686
2686
|
setView(arg.view.type);
|
|
2687
2687
|
setVisibleRange({ start: arg.startStr, end: arg.endStr });
|
|
2688
2688
|
fetchBookings({ start: arg.startStr, end: arg.endStr });
|
|
2689
2689
|
}, [fetchBookings, setView]);
|
|
2690
|
-
const handleEventDidMount =
|
|
2690
|
+
const handleEventDidMount = React11.useCallback((arg) => {
|
|
2691
2691
|
const booking = arg.event.extendedProps?.booking;
|
|
2692
2692
|
if (booking) arg.el.setAttribute("data-booking-id", booking.id);
|
|
2693
2693
|
arg.el.addEventListener("dblclick", (e) => {
|
|
@@ -2714,9 +2714,9 @@ function CalendarView() {
|
|
|
2714
2714
|
setPopoverAnchor(null);
|
|
2715
2715
|
});
|
|
2716
2716
|
}, []);
|
|
2717
|
-
const skipClickRef =
|
|
2718
|
-
const hoverTimerRef =
|
|
2719
|
-
const handleEventMouseEnter =
|
|
2717
|
+
const skipClickRef = React11.useRef(false);
|
|
2718
|
+
const hoverTimerRef = React11.useRef(null);
|
|
2719
|
+
const handleEventMouseEnter = React11.useCallback((arg) => {
|
|
2720
2720
|
if (arg.event.display === "background") return;
|
|
2721
2721
|
if (arg.event.extendedProps?.isLocationLabel) return;
|
|
2722
2722
|
const booking = arg.event.extendedProps.booking;
|
|
@@ -2735,13 +2735,13 @@ function CalendarView() {
|
|
|
2735
2735
|
setPopoverVisible(true);
|
|
2736
2736
|
}, 3e3);
|
|
2737
2737
|
}, []);
|
|
2738
|
-
const handleEventMouseLeave =
|
|
2738
|
+
const handleEventMouseLeave = React11.useCallback(() => {
|
|
2739
2739
|
if (hoverTimerRef.current) {
|
|
2740
2740
|
clearTimeout(hoverTimerRef.current);
|
|
2741
2741
|
hoverTimerRef.current = null;
|
|
2742
2742
|
}
|
|
2743
2743
|
}, []);
|
|
2744
|
-
const handleEventClick =
|
|
2744
|
+
const handleEventClick = React11.useCallback((arg) => {
|
|
2745
2745
|
if (skipClickRef.current) {
|
|
2746
2746
|
skipClickRef.current = false;
|
|
2747
2747
|
return;
|
|
@@ -2764,7 +2764,7 @@ function CalendarView() {
|
|
|
2764
2764
|
setPopoverAnchor({ x, y });
|
|
2765
2765
|
setPopoverVisible(true);
|
|
2766
2766
|
}, []);
|
|
2767
|
-
const findScheduleForSlot =
|
|
2767
|
+
const findScheduleForSlot = React11.useCallback((professionalId, dateTimeStr) => {
|
|
2768
2768
|
if (!professionalId) return null;
|
|
2769
2769
|
const dt = new Date(dateTimeStr);
|
|
2770
2770
|
const dateStr = dt.toISOString().slice(0, 10);
|
|
@@ -2781,7 +2781,7 @@ function CalendarView() {
|
|
|
2781
2781
|
}
|
|
2782
2782
|
return null;
|
|
2783
2783
|
}, [schedules]);
|
|
2784
|
-
const handleSelect =
|
|
2784
|
+
const handleSelect = React11.useCallback((arg) => {
|
|
2785
2785
|
calendarRef.current?.getApi().unselect();
|
|
2786
2786
|
if (popoverVisibleRef.current || contextMenuVisibleRef.current) {
|
|
2787
2787
|
setPopoverVisible(false);
|
|
@@ -2803,7 +2803,7 @@ function CalendarView() {
|
|
|
2803
2803
|
}
|
|
2804
2804
|
proceed();
|
|
2805
2805
|
}, [openModal, findScheduleForSlot]);
|
|
2806
|
-
const handleEventDrop =
|
|
2806
|
+
const handleEventDrop = React11.useCallback(async (arg) => {
|
|
2807
2807
|
const booking = arg.event.extendedProps.booking;
|
|
2808
2808
|
try {
|
|
2809
2809
|
await rescheduleBooking(booking.id, arg.event.startStr, arg.event.endStr, arg.newResource?.id ?? void 0);
|
|
@@ -2811,13 +2811,13 @@ function CalendarView() {
|
|
|
2811
2811
|
arg.revert();
|
|
2812
2812
|
}
|
|
2813
2813
|
}, [rescheduleBooking]);
|
|
2814
|
-
const handleViewChange =
|
|
2814
|
+
const handleViewChange = React11.useCallback((v) => {
|
|
2815
2815
|
calendarRef.current?.getApi().changeView(v);
|
|
2816
2816
|
prefs.set("calendarView", v);
|
|
2817
2817
|
}, [prefs]);
|
|
2818
|
-
const handlePrev =
|
|
2819
|
-
const handleNext =
|
|
2820
|
-
const handleToday =
|
|
2818
|
+
const handlePrev = React11.useCallback(() => calendarRef.current?.getApi().prev(), []);
|
|
2819
|
+
const handleNext = React11.useCallback(() => calendarRef.current?.getApi().next(), []);
|
|
2820
|
+
const handleToday = React11.useCallback(() => {
|
|
2821
2821
|
calendarRef.current?.getApi().today();
|
|
2822
2822
|
setSelectedDate(/* @__PURE__ */ new Date());
|
|
2823
2823
|
}, []);
|
|
@@ -2833,9 +2833,9 @@ function CalendarView() {
|
|
|
2833
2833
|
const next = selectedStatuses.includes(value) ? selectedStatuses.filter((s) => s !== value) : [...selectedStatuses, value];
|
|
2834
2834
|
setFilters({ statuses: next });
|
|
2835
2835
|
}
|
|
2836
|
-
const wrapperRef =
|
|
2837
|
-
const [dayHeaderCompact, setDayHeaderCompact] =
|
|
2838
|
-
|
|
2836
|
+
const wrapperRef = React11.useRef(null);
|
|
2837
|
+
const [dayHeaderCompact, setDayHeaderCompact] = React11.useState(false);
|
|
2838
|
+
React11.useEffect(() => {
|
|
2839
2839
|
const container = wrapperRef.current;
|
|
2840
2840
|
if (!container) return;
|
|
2841
2841
|
let frame = 0;
|
|
@@ -2878,7 +2878,7 @@ function CalendarView() {
|
|
|
2878
2878
|
ro.disconnect();
|
|
2879
2879
|
};
|
|
2880
2880
|
}, [resources, currentView, visibleRange]);
|
|
2881
|
-
const applyResourceStriping =
|
|
2881
|
+
const applyResourceStriping = React11.useCallback(() => {
|
|
2882
2882
|
const container = wrapperRef.current;
|
|
2883
2883
|
if (!container) return;
|
|
2884
2884
|
const resourceIds = resources.map((r) => r.id);
|
|
@@ -2889,7 +2889,7 @@ function CalendarView() {
|
|
|
2889
2889
|
el.classList.toggle("fc-resource-alt", idx % 2 === 1);
|
|
2890
2890
|
});
|
|
2891
2891
|
}, [resources]);
|
|
2892
|
-
|
|
2892
|
+
React11.useEffect(() => {
|
|
2893
2893
|
applyResourceStriping();
|
|
2894
2894
|
const t1 = setTimeout(applyResourceStriping, 100);
|
|
2895
2895
|
const t2 = setTimeout(applyResourceStriping, 300);
|
|
@@ -2898,7 +2898,7 @@ function CalendarView() {
|
|
|
2898
2898
|
clearTimeout(t2);
|
|
2899
2899
|
};
|
|
2900
2900
|
}, [applyResourceStriping, currentView, visibleRange, bookings]);
|
|
2901
|
-
|
|
2901
|
+
React11.useEffect(() => {
|
|
2902
2902
|
function handleOpenBooking(e) {
|
|
2903
2903
|
const bookingId = e.detail?.bookingId;
|
|
2904
2904
|
if (bookingId) openModal("edit", { bookingId });
|
|
@@ -2906,7 +2906,7 @@ function CalendarView() {
|
|
|
2906
2906
|
window.addEventListener("agenda:open-booking", handleOpenBooking);
|
|
2907
2907
|
return () => window.removeEventListener("agenda:open-booking", handleOpenBooking);
|
|
2908
2908
|
}, [openModal]);
|
|
2909
|
-
const dayHeaderContent =
|
|
2909
|
+
const dayHeaderContent = React11.useCallback((arg) => {
|
|
2910
2910
|
const date = arg.date;
|
|
2911
2911
|
const dateLocale = currentLocale === "pt-BR" ? "pt-BR" : "en";
|
|
2912
2912
|
const wrapStyle = { display: "flex", flexDirection: "column", alignItems: "center", lineHeight: 1.15 };
|
|
@@ -2924,7 +2924,7 @@ function CalendarView() {
|
|
|
2924
2924
|
/* @__PURE__ */ jsxRuntime.jsx("span", { style: dateStyle, children: `${date.getMonth() + 1}/${date.getDate()}` })
|
|
2925
2925
|
] });
|
|
2926
2926
|
}, [dayHeaderCompact, currentLocale]);
|
|
2927
|
-
const resourceLabelContent =
|
|
2927
|
+
const resourceLabelContent = React11.useCallback((arg) => {
|
|
2928
2928
|
const { id, title, extendedProps } = arg.resource;
|
|
2929
2929
|
const initials = title.split(" ").map((n) => n[0]).join("").slice(0, 2);
|
|
2930
2930
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 px-2 py-1.5", children: [
|
|
@@ -2944,7 +2944,7 @@ function CalendarView() {
|
|
|
2944
2944
|
] })
|
|
2945
2945
|
] });
|
|
2946
2946
|
}, []);
|
|
2947
|
-
const eventContent =
|
|
2947
|
+
const eventContent = React11.useCallback((arg) => {
|
|
2948
2948
|
if (arg.event.extendedProps?.isLocationLabel) {
|
|
2949
2949
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-1.5 py-0.5 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[10px] font-medium truncate", children: arg.event.title }) });
|
|
2950
2950
|
}
|
|
@@ -3192,14 +3192,14 @@ function CalendarView() {
|
|
|
3192
3192
|
)
|
|
3193
3193
|
] });
|
|
3194
3194
|
}
|
|
3195
|
-
function AgendaPage({ config, provider, store }) {
|
|
3195
|
+
function AgendaPage({ config, provider: provider2, store }) {
|
|
3196
3196
|
const runtime = core.usePluginRuntimeOptional();
|
|
3197
3197
|
const tenantId = runtime?.context.tenant?.id;
|
|
3198
|
-
|
|
3198
|
+
React11__default.default.useEffect(() => {
|
|
3199
3199
|
chunkSYDBDI3Q_cjs.setAgendaTenantId(tenantId);
|
|
3200
3200
|
return () => chunkSYDBDI3Q_cjs.setAgendaTenantId(void 0);
|
|
3201
3201
|
}, [tenantId]);
|
|
3202
|
-
return /* @__PURE__ */ jsxRuntime.jsx(AgendaContextProvider, { config, provider, store, children: /* @__PURE__ */ jsxRuntime.jsx(CalendarView, {}) });
|
|
3202
|
+
return /* @__PURE__ */ jsxRuntime.jsx(AgendaContextProvider, { config, provider: provider2, store, children: /* @__PURE__ */ jsxRuntime.jsx(CalendarView, {}) });
|
|
3203
3203
|
}
|
|
3204
3204
|
function getTenantId() {
|
|
3205
3205
|
return chunkSYDBDI3Q_cjs.getAgendaTenantId() ?? core.getActiveTenantId();
|
|
@@ -4059,7 +4059,7 @@ function getCurrentBookingQuery(state, dateRange = state.dateRange) {
|
|
|
4059
4059
|
statuses: state.selectedStatuses.length ? state.selectedStatuses : void 0
|
|
4060
4060
|
};
|
|
4061
4061
|
}
|
|
4062
|
-
function createAgendaStore(
|
|
4062
|
+
function createAgendaStore(provider2, financialBridge) {
|
|
4063
4063
|
return vanilla.createStore((set, get) => ({
|
|
4064
4064
|
bookings: [],
|
|
4065
4065
|
bookingsLoading: false,
|
|
@@ -4083,7 +4083,7 @@ function createAgendaStore(provider, financialBridge) {
|
|
|
4083
4083
|
set({ bookingsLoading: true, dateRange: range });
|
|
4084
4084
|
const state = get();
|
|
4085
4085
|
const query = getCurrentBookingQuery(state, range);
|
|
4086
|
-
let bookings = await
|
|
4086
|
+
let bookings = await provider2.getBookings(query);
|
|
4087
4087
|
if (financialBridge) {
|
|
4088
4088
|
const orderIds = bookings.map((b) => b.orderId).filter((id) => !!id);
|
|
4089
4089
|
if (orderIds.length > 0) {
|
|
@@ -4104,14 +4104,14 @@ function createAgendaStore(provider, financialBridge) {
|
|
|
4104
4104
|
async fetchProfessionals() {
|
|
4105
4105
|
return saas.dedup("agenda:professionals", async () => {
|
|
4106
4106
|
set({ professionalsLoading: true });
|
|
4107
|
-
const professionals = await
|
|
4107
|
+
const professionals = await provider2.getProfessionals();
|
|
4108
4108
|
set({ professionals, professionalsLoading: false });
|
|
4109
4109
|
});
|
|
4110
4110
|
},
|
|
4111
4111
|
async fetchLocations() {
|
|
4112
4112
|
return saas.dedup("agenda:locations", async () => {
|
|
4113
|
-
if (!
|
|
4114
|
-
const locations = await
|
|
4113
|
+
if (!provider2.getLocations) return;
|
|
4114
|
+
const locations = await provider2.getLocations();
|
|
4115
4115
|
set({ locations });
|
|
4116
4116
|
const current = saas.getScheduleBlockConfig();
|
|
4117
4117
|
if (current) {
|
|
@@ -4122,23 +4122,23 @@ function createAgendaStore(provider, financialBridge) {
|
|
|
4122
4122
|
async fetchSchedules(professionalId) {
|
|
4123
4123
|
return saas.dedup("agenda:schedules:" + (professionalId ?? "all"), async () => {
|
|
4124
4124
|
set({ schedulesLoading: true });
|
|
4125
|
-
const schedules = await
|
|
4125
|
+
const schedules = await provider2.getSchedules(professionalId);
|
|
4126
4126
|
set({ schedules, schedulesLoading: false });
|
|
4127
4127
|
});
|
|
4128
4128
|
},
|
|
4129
4129
|
async fetchConfirmations() {
|
|
4130
4130
|
return saas.dedup("agenda:confirmations", async () => {
|
|
4131
4131
|
set({ confirmationsLoading: true });
|
|
4132
|
-
const pendingConfirmations = await
|
|
4132
|
+
const pendingConfirmations = await provider2.getConfirmationsPending();
|
|
4133
4133
|
set({ pendingConfirmations, confirmationsLoading: false });
|
|
4134
4134
|
});
|
|
4135
4135
|
},
|
|
4136
4136
|
async createBooking(input) {
|
|
4137
4137
|
try {
|
|
4138
|
-
const booking = await
|
|
4138
|
+
const booking = await provider2.createBooking(input);
|
|
4139
4139
|
const state = get();
|
|
4140
4140
|
if (state.dateRange.start && state.dateRange.end) {
|
|
4141
|
-
const bookings = await
|
|
4141
|
+
const bookings = await provider2.getBookings(getCurrentBookingQuery(state));
|
|
4142
4142
|
set({ bookings });
|
|
4143
4143
|
}
|
|
4144
4144
|
ui.toast.success("Appointment created");
|
|
@@ -4150,10 +4150,10 @@ function createAgendaStore(provider, financialBridge) {
|
|
|
4150
4150
|
},
|
|
4151
4151
|
async updateBooking(id, data) {
|
|
4152
4152
|
try {
|
|
4153
|
-
const booking = await
|
|
4153
|
+
const booking = await provider2.updateBooking(id, data);
|
|
4154
4154
|
const state = get();
|
|
4155
4155
|
if (state.dateRange.start && state.dateRange.end) {
|
|
4156
|
-
const bookings = await
|
|
4156
|
+
const bookings = await provider2.getBookings(getCurrentBookingQuery(state));
|
|
4157
4157
|
set({ bookings });
|
|
4158
4158
|
}
|
|
4159
4159
|
ui.toast.success("Appointment updated");
|
|
@@ -4165,10 +4165,10 @@ function createAgendaStore(provider, financialBridge) {
|
|
|
4165
4165
|
},
|
|
4166
4166
|
async deleteBooking(id) {
|
|
4167
4167
|
try {
|
|
4168
|
-
await
|
|
4168
|
+
await provider2.deleteBooking(id);
|
|
4169
4169
|
const state = get();
|
|
4170
4170
|
if (state.dateRange.start && state.dateRange.end) {
|
|
4171
|
-
const bookings = await
|
|
4171
|
+
const bookings = await provider2.getBookings(getCurrentBookingQuery(state));
|
|
4172
4172
|
set({ bookings });
|
|
4173
4173
|
}
|
|
4174
4174
|
ui.toast.success("Appointment deleted");
|
|
@@ -4181,10 +4181,10 @@ function createAgendaStore(provider, financialBridge) {
|
|
|
4181
4181
|
const prev = get().bookings;
|
|
4182
4182
|
set({ bookings: prev.map((b) => b.id === id ? { ...b, status } : b) });
|
|
4183
4183
|
try {
|
|
4184
|
-
await
|
|
4184
|
+
await provider2.updateBookingStatus(id, status);
|
|
4185
4185
|
const state = get();
|
|
4186
4186
|
if (state.dateRange.start && state.dateRange.end) {
|
|
4187
|
-
const bookings = await
|
|
4187
|
+
const bookings = await provider2.getBookings(getCurrentBookingQuery(state));
|
|
4188
4188
|
set({ bookings });
|
|
4189
4189
|
}
|
|
4190
4190
|
ui.toast.success("Status updated");
|
|
@@ -4199,7 +4199,7 @@ function createAgendaStore(provider, financialBridge) {
|
|
|
4199
4199
|
const existing = get().bookings.find((b) => b.id === id);
|
|
4200
4200
|
const assigneeId = newProfessionalId ?? existing?.professionalId;
|
|
4201
4201
|
if (assigneeId) {
|
|
4202
|
-
const hasConflict = await
|
|
4202
|
+
const hasConflict = await provider2.checkConflict({
|
|
4203
4203
|
assigneeId,
|
|
4204
4204
|
startsAt: newStart,
|
|
4205
4205
|
endsAt: newEnd,
|
|
@@ -4210,14 +4210,14 @@ function createAgendaStore(provider, financialBridge) {
|
|
|
4210
4210
|
throw new Error("Time conflict");
|
|
4211
4211
|
}
|
|
4212
4212
|
}
|
|
4213
|
-
await
|
|
4213
|
+
await provider2.updateBooking(id, {
|
|
4214
4214
|
startsAt: newStart,
|
|
4215
4215
|
endsAt: newEnd,
|
|
4216
4216
|
...newProfessionalId && { professionalId: newProfessionalId }
|
|
4217
4217
|
});
|
|
4218
4218
|
const state = get();
|
|
4219
4219
|
if (state.dateRange.start && state.dateRange.end) {
|
|
4220
|
-
const bookings = await
|
|
4220
|
+
const bookings = await provider2.getBookings(getCurrentBookingQuery(state));
|
|
4221
4221
|
set({ bookings });
|
|
4222
4222
|
}
|
|
4223
4223
|
ui.toast.success("Appointment rescheduled");
|
|
@@ -4793,7 +4793,7 @@ function computeStatus(movements) {
|
|
|
4793
4793
|
if (anyPaid) return "partial";
|
|
4794
4794
|
return "pending";
|
|
4795
4795
|
}
|
|
4796
|
-
function createFinancialBridge(
|
|
4796
|
+
function createFinancialBridge(provider2) {
|
|
4797
4797
|
return {
|
|
4798
4798
|
async resolvePaymentStatuses(orderIds) {
|
|
4799
4799
|
const result = /* @__PURE__ */ new Map();
|
|
@@ -4878,7 +4878,7 @@ function createFinancialBridge(provider) {
|
|
|
4878
4878
|
return orderId;
|
|
4879
4879
|
},
|
|
4880
4880
|
async payMovement(input) {
|
|
4881
|
-
await
|
|
4881
|
+
await provider2.payMovement({
|
|
4882
4882
|
movementId: input.movementId,
|
|
4883
4883
|
amount: input.amount,
|
|
4884
4884
|
paymentDate: input.paymentDate,
|
|
@@ -4941,15 +4941,15 @@ function createFinancialBridge(provider) {
|
|
|
4941
4941
|
return await this.getPaymentDetail(invoiceId);
|
|
4942
4942
|
},
|
|
4943
4943
|
async getPaymentMethodTypes() {
|
|
4944
|
-
const types = await
|
|
4944
|
+
const types = await provider2.getPaymentMethodTypes();
|
|
4945
4945
|
return types.map((t) => ({ id: t.id, name: t.name, transactionType: t.transactionType }));
|
|
4946
4946
|
},
|
|
4947
4947
|
async getBankAccounts() {
|
|
4948
|
-
const accounts = await
|
|
4948
|
+
const accounts = await provider2.getBankAccounts();
|
|
4949
4949
|
return accounts.filter((a) => a.isActive).map((a) => ({ id: a.id, name: a.name, accountType: a.accountType }));
|
|
4950
4950
|
},
|
|
4951
4951
|
async getPaymentMethods(paymentMethodTypeId) {
|
|
4952
|
-
const methods = await
|
|
4952
|
+
const methods = await provider2.getPaymentMethods();
|
|
4953
4953
|
return methods.filter((m) => m.paymentMethodTypeId === paymentMethodTypeId && m.isActive).map((m) => ({ id: m.id, name: m.name }));
|
|
4954
4954
|
}
|
|
4955
4955
|
};
|
|
@@ -4984,16 +4984,215 @@ function mapInvoiceStatus(status) {
|
|
|
4984
4984
|
return "pending";
|
|
4985
4985
|
}
|
|
4986
4986
|
}
|
|
4987
|
+
var FUNCTION = "google-calendar-sync";
|
|
4988
|
+
function sb() {
|
|
4989
|
+
const supabase = core.getSupabaseClientOptional();
|
|
4990
|
+
if (!supabase) throw new Error("Supabase not initialized");
|
|
4991
|
+
return supabase;
|
|
4992
|
+
}
|
|
4993
|
+
function createGoogleCalendarProvider() {
|
|
4994
|
+
return {
|
|
4995
|
+
async getIntegration() {
|
|
4996
|
+
const { data } = await sb().from("calendar_integrations").select("*").eq("provider", "google").limit(1).maybeSingle();
|
|
4997
|
+
if (!data) return null;
|
|
4998
|
+
return {
|
|
4999
|
+
id: data.id,
|
|
5000
|
+
provider: data.provider,
|
|
5001
|
+
calendarId: data.calendar_id ?? "primary",
|
|
5002
|
+
active: data.active ?? true,
|
|
5003
|
+
connected: !!data.oauth_refresh_token,
|
|
5004
|
+
lastSyncAt: data.last_sync_at ?? void 0
|
|
5005
|
+
};
|
|
5006
|
+
},
|
|
5007
|
+
async getConnectUrl(redirectTo) {
|
|
5008
|
+
const { data, error } = await sb().functions.invoke(FUNCTION, {
|
|
5009
|
+
body: { action: "oauth_start", redirectTo: redirectTo ?? window.location.href }
|
|
5010
|
+
});
|
|
5011
|
+
if (error) throw new Error(error.message);
|
|
5012
|
+
return data.url;
|
|
5013
|
+
},
|
|
5014
|
+
async setCalendar(calendarId) {
|
|
5015
|
+
await sb().from("calendar_integrations").update({ calendar_id: calendarId, updated_at: (/* @__PURE__ */ new Date()).toISOString() }).eq("provider", "google");
|
|
5016
|
+
},
|
|
5017
|
+
async disconnect() {
|
|
5018
|
+
await sb().from("calendar_integrations").update({ active: false, oauth_refresh_token: null, oauth_access_token: null }).eq("provider", "google");
|
|
5019
|
+
},
|
|
5020
|
+
async syncNow() {
|
|
5021
|
+
const { data, error } = await sb().functions.invoke(FUNCTION, { body: { action: "pull_events", trigger: "manual" } });
|
|
5022
|
+
if (error) throw new Error(error.message);
|
|
5023
|
+
return data;
|
|
5024
|
+
},
|
|
5025
|
+
async getSyncLog() {
|
|
5026
|
+
const { data } = await sb().from("calendar_sync_log").select("*").order("created_at", { ascending: false }).limit(20);
|
|
5027
|
+
return (data ?? []).map((r) => ({
|
|
5028
|
+
id: r.id,
|
|
5029
|
+
direction: r.direction,
|
|
5030
|
+
trigger: r.trigger ?? void 0,
|
|
5031
|
+
status: r.status,
|
|
5032
|
+
fetched: r.fetched ?? 0,
|
|
5033
|
+
written: r.written ?? 0,
|
|
5034
|
+
error: r.error ?? void 0,
|
|
5035
|
+
createdAt: r.created_at
|
|
5036
|
+
}));
|
|
5037
|
+
}
|
|
5038
|
+
};
|
|
5039
|
+
}
|
|
5040
|
+
var provider = createGoogleCalendarProvider();
|
|
5041
|
+
function GoogleCalendarExtraPanel() {
|
|
5042
|
+
const [connected, setConnected] = React11.useState(false);
|
|
5043
|
+
const [calendarId, setCalendarId] = React11.useState("primary");
|
|
5044
|
+
const [syncing, setSyncing] = React11.useState(false);
|
|
5045
|
+
const [log, setLog] = React11.useState([]);
|
|
5046
|
+
const [loaded, setLoaded] = React11.useState(false);
|
|
5047
|
+
async function load() {
|
|
5048
|
+
const integ = await provider.getIntegration();
|
|
5049
|
+
setConnected(!!integ?.connected);
|
|
5050
|
+
if (integ) {
|
|
5051
|
+
setCalendarId(integ.calendarId);
|
|
5052
|
+
void provider.getSyncLog().then(setLog);
|
|
5053
|
+
}
|
|
5054
|
+
setLoaded(true);
|
|
5055
|
+
}
|
|
5056
|
+
React11.useEffect(() => {
|
|
5057
|
+
void load();
|
|
5058
|
+
}, []);
|
|
5059
|
+
if (!loaded || !connected) return null;
|
|
5060
|
+
async function handleSaveCalendar() {
|
|
5061
|
+
await provider.setCalendar(calendarId);
|
|
5062
|
+
ui.toast.success("Saved");
|
|
5063
|
+
}
|
|
5064
|
+
async function handleSyncNow() {
|
|
5065
|
+
setSyncing(true);
|
|
5066
|
+
try {
|
|
5067
|
+
const r = await provider.syncNow();
|
|
5068
|
+
ui.toast.success(`Synced \u2014 ${r.written} updated`);
|
|
5069
|
+
void provider.getSyncLog().then(setLog);
|
|
5070
|
+
} catch (e) {
|
|
5071
|
+
ui.toast.error(e?.message ?? "Sync failed");
|
|
5072
|
+
} finally {
|
|
5073
|
+
setSyncing(false);
|
|
5074
|
+
}
|
|
5075
|
+
}
|
|
5076
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4 border-t pt-4", children: [
|
|
5077
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-end gap-3", children: [
|
|
5078
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "block flex-1 min-w-[200px]", children: [
|
|
5079
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Calendar ID" }),
|
|
5080
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5081
|
+
"input",
|
|
5082
|
+
{
|
|
5083
|
+
value: calendarId,
|
|
5084
|
+
onChange: (e) => setCalendarId(e.target.value),
|
|
5085
|
+
placeholder: "primary",
|
|
5086
|
+
className: "w-full mt-1 rounded-input border border-input bg-card px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring"
|
|
5087
|
+
}
|
|
5088
|
+
)
|
|
5089
|
+
] }),
|
|
5090
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "outline", size: "sm", onClick: handleSaveCalendar, children: "Save" }),
|
|
5091
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { variant: "outline", size: "sm", onClick: handleSyncNow, disabled: syncing, children: [
|
|
5092
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { className: `h-3.5 w-3.5 ${syncing ? "animate-spin" : ""}` }),
|
|
5093
|
+
" Sync now"
|
|
5094
|
+
] })
|
|
5095
|
+
] }),
|
|
5096
|
+
log.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
5097
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
5098
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.History, { className: "h-4 w-4 text-muted-foreground" }),
|
|
5099
|
+
/* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-sm font-semibold", children: "History" })
|
|
5100
|
+
] }),
|
|
5101
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border divide-y text-sm", children: log.map((r) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 px-3 py-2", children: [
|
|
5102
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground text-xs", children: new Date(r.createdAt).toLocaleString() }),
|
|
5103
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] uppercase tracking-wide px-1 py-px rounded bg-muted text-muted-foreground", children: r.direction }),
|
|
5104
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ml-auto text-xs", children: [
|
|
5105
|
+
r.written,
|
|
5106
|
+
" written / ",
|
|
5107
|
+
r.fetched,
|
|
5108
|
+
" fetched"
|
|
5109
|
+
] }),
|
|
5110
|
+
r.status === "success" ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckCircle2, { className: "h-3.5 w-3.5 text-success" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlertCircle, { className: "h-3.5 w-3.5 text-warning" })
|
|
5111
|
+
] }, r.id)) })
|
|
5112
|
+
] })
|
|
5113
|
+
] });
|
|
5114
|
+
}
|
|
5115
|
+
var googleCalendarConnectorDef = {
|
|
5116
|
+
id: "google-calendar",
|
|
5117
|
+
hostPluginId: "agenda",
|
|
5118
|
+
name: "Google Calendar",
|
|
5119
|
+
description: "Two-way sync between your bookings and Google Calendar.",
|
|
5120
|
+
icon: "Calendar",
|
|
5121
|
+
authKind: "oauth",
|
|
5122
|
+
async getStatus() {
|
|
5123
|
+
const integ = await provider.getIntegration();
|
|
5124
|
+
return { connected: !!integ?.connected };
|
|
5125
|
+
},
|
|
5126
|
+
startOAuth: (redirectTo) => provider.getConnectUrl(redirectTo),
|
|
5127
|
+
disconnect: () => provider.disconnect(),
|
|
5128
|
+
ExtraPanel: GoogleCalendarExtraPanel
|
|
5129
|
+
};
|
|
5130
|
+
|
|
5131
|
+
// src/integrations/google-calendar/connector.ts
|
|
5132
|
+
var googleCalendarConnector = {
|
|
5133
|
+
id: "google-calendar",
|
|
5134
|
+
provider: "google",
|
|
5135
|
+
pluginId: "agenda",
|
|
5136
|
+
authKind: "oauth",
|
|
5137
|
+
capabilities: [
|
|
5138
|
+
{
|
|
5139
|
+
entity: "booking",
|
|
5140
|
+
direction: "bidirectional",
|
|
5141
|
+
triggers: ["on-write", "scheduled", "webhook"]
|
|
5142
|
+
}
|
|
5143
|
+
]
|
|
5144
|
+
};
|
|
5145
|
+
|
|
5146
|
+
// src/integrations/google-calendar/mapping.ts
|
|
5147
|
+
function bookingSummary(b) {
|
|
5148
|
+
const services = (b.services ?? []).map((s) => s.name).filter(Boolean).join(", ");
|
|
5149
|
+
const who = b.clientName ?? "";
|
|
5150
|
+
if (services && who) return `${services} \u2014 ${who}`;
|
|
5151
|
+
return services || who || "Appointment";
|
|
5152
|
+
}
|
|
5153
|
+
function bookingToEvent2(b, timeZone) {
|
|
5154
|
+
if (!b.startsAt || !b.endsAt) return null;
|
|
5155
|
+
const notes = [b.notes, b.professionalName ? `Pro: ${b.professionalName}` : "", b.locationName ?? ""].filter(Boolean).join("\n");
|
|
5156
|
+
return {
|
|
5157
|
+
summary: bookingSummary(b),
|
|
5158
|
+
description: notes || void 0,
|
|
5159
|
+
start: { dateTime: b.startsAt, timeZone },
|
|
5160
|
+
end: { dateTime: b.endsAt, timeZone }
|
|
5161
|
+
};
|
|
5162
|
+
}
|
|
5163
|
+
function eventToBookingPatch(ev) {
|
|
5164
|
+
if (ev.status === "cancelled") return { status: "cancelled" };
|
|
5165
|
+
return {
|
|
5166
|
+
startsAt: ev.start?.dateTime,
|
|
5167
|
+
endsAt: ev.end?.dateTime
|
|
5168
|
+
};
|
|
5169
|
+
}
|
|
5170
|
+
|
|
5171
|
+
// src/integrations/google-calendar/index.ts
|
|
5172
|
+
function createGoogleCalendarPlugin() {
|
|
5173
|
+
return {
|
|
5174
|
+
id: "google-calendar",
|
|
5175
|
+
name: "Google Calendar",
|
|
5176
|
+
icon: "Calendar",
|
|
5177
|
+
version: "0.1.0",
|
|
5178
|
+
scope: "addon",
|
|
5179
|
+
defaultEnabled: true,
|
|
5180
|
+
dependencies: ["agenda"],
|
|
5181
|
+
navigation: [],
|
|
5182
|
+
routes: [],
|
|
5183
|
+
connectors: [googleCalendarConnectorDef]
|
|
5184
|
+
};
|
|
5185
|
+
}
|
|
4987
5186
|
|
|
4988
5187
|
// src/index.ts
|
|
4989
5188
|
function createAgendaPlugin(options) {
|
|
4990
5189
|
const config = resolveConfig(options);
|
|
4991
5190
|
core.registerTranslations(agendaLocales);
|
|
4992
|
-
const
|
|
5191
|
+
const provider2 = options?.dataProvider ?? core.createSafeDataProvider(
|
|
4993
5192
|
() => createSupabaseAgendaProvider(),
|
|
4994
5193
|
() => createMockAgendaProvider()
|
|
4995
5194
|
);
|
|
4996
|
-
const store = createAgendaStore(
|
|
5195
|
+
const store = createAgendaStore(provider2, options?.financialBridge);
|
|
4997
5196
|
saas.setScheduleBlockConfig({
|
|
4998
5197
|
defaults: config.scheduleBlockDefaults,
|
|
4999
5198
|
showServices: !!config.serviceLookup,
|
|
@@ -5002,14 +5201,14 @@ function createAgendaPlugin(options) {
|
|
|
5002
5201
|
showLocations: config.modules.locationSelection,
|
|
5003
5202
|
locations: config.locations.map((l) => ({ id: l.id, name: l.name })),
|
|
5004
5203
|
// Lazy fetcher — called by ScheduleEditor when locations are needed but empty
|
|
5005
|
-
fetchLocations: config.modules.locationSelection &&
|
|
5006
|
-
const locations = await
|
|
5204
|
+
fetchLocations: config.modules.locationSelection && provider2.getLocations ? async () => {
|
|
5205
|
+
const locations = await provider2.getLocations();
|
|
5007
5206
|
const current = saas.getScheduleBlockConfig();
|
|
5008
5207
|
if (current) saas.setScheduleBlockConfig({ ...current, locations });
|
|
5009
5208
|
return locations;
|
|
5010
5209
|
} : void 0
|
|
5011
5210
|
});
|
|
5012
|
-
const PageComponent = () =>
|
|
5211
|
+
const PageComponent = () => React11__default.default.createElement(AgendaPage, { config, provider: provider2, store });
|
|
5013
5212
|
return {
|
|
5014
5213
|
id: "agenda",
|
|
5015
5214
|
name: config.labels.pageTitle,
|
|
@@ -5115,8 +5314,15 @@ function createAgendaPlugin(options) {
|
|
|
5115
5314
|
id: "agenda",
|
|
5116
5315
|
label: "Agenda",
|
|
5117
5316
|
icon: "Calendar",
|
|
5317
|
+
// Standard layout: General | Integrations (Google Calendar addon) | Properties (holidays).
|
|
5118
5318
|
component: (() => {
|
|
5119
|
-
const AgendaSettingsTab = () =>
|
|
5319
|
+
const AgendaSettingsTab = () => React11__default.default.createElement(saas.PluginSettingsPanel, {
|
|
5320
|
+
title: "Agenda",
|
|
5321
|
+
generalSettings: React11__default.default.createElement(AgendaGeneralSettings),
|
|
5322
|
+
registries: agendaRegistries,
|
|
5323
|
+
hostPluginId: "agenda",
|
|
5324
|
+
routeBase: "/settings/agenda"
|
|
5325
|
+
});
|
|
5120
5326
|
AgendaSettingsTab.displayName = "AgendaSettingsTab";
|
|
5121
5327
|
return AgendaSettingsTab;
|
|
5122
5328
|
})(),
|
|
@@ -5128,8 +5334,13 @@ function createAgendaPlugin(options) {
|
|
|
5128
5334
|
};
|
|
5129
5335
|
}
|
|
5130
5336
|
|
|
5337
|
+
exports.bookingToEvent = bookingToEvent2;
|
|
5131
5338
|
exports.computeCommissionAmount = computeCommissionAmount;
|
|
5132
5339
|
exports.createAgendaPlugin = createAgendaPlugin;
|
|
5133
5340
|
exports.createFinancialBridge = createFinancialBridge;
|
|
5341
|
+
exports.createGoogleCalendarPlugin = createGoogleCalendarPlugin;
|
|
5342
|
+
exports.createGoogleCalendarProvider = createGoogleCalendarProvider;
|
|
5343
|
+
exports.eventToBookingPatch = eventToBookingPatch;
|
|
5344
|
+
exports.googleCalendarConnector = googleCalendarConnector;
|
|
5134
5345
|
//# sourceMappingURL=index.cjs.map
|
|
5135
5346
|
//# sourceMappingURL=index.cjs.map
|