@aranova/tracking-next 0.20.2 → 0.22.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.
- package/README.md +80 -1
- package/dist/blog-server.js +12 -0
- package/dist/blog-server.js.map +1 -1
- package/dist/blog-server.mjs +12 -0
- package/dist/blog-server.mjs.map +1 -1
- package/dist/blog.js +7 -0
- package/dist/blog.js.map +1 -1
- package/dist/blog.mjs +7 -0
- package/dist/blog.mjs.map +1 -1
- package/dist/calendar-server.d.mts +53 -0
- package/dist/calendar-server.d.ts +53 -0
- package/dist/calendar-server.js +206 -0
- package/dist/calendar-server.js.map +1 -0
- package/dist/calendar-server.mjs +180 -0
- package/dist/calendar-server.mjs.map +1 -0
- package/dist/calendar.d.mts +112 -0
- package/dist/calendar.d.ts +112 -0
- package/dist/calendar.js +524 -0
- package/dist/calendar.js.map +1 -0
- package/dist/calendar.mjs +464 -0
- package/dist/calendar.mjs.map +1 -0
- package/dist/date-BHetnL7s.d.mts +26 -0
- package/dist/date-BHetnL7s.d.ts +26 -0
- package/dist/index.d.mts +62 -5
- package/dist/index.d.ts +62 -5
- package/dist/index.js +566 -21
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +529 -21
- package/dist/index.mjs.map +1 -1
- package/dist/{phone-utils-B2vHJkNz.d.mts → phone-utils-BhWfNuPS.d.mts} +8 -0
- package/dist/{phone-utils-B2vHJkNz.d.ts → phone-utils-BhWfNuPS.d.ts} +8 -0
- package/dist/phone.d.mts +1 -1
- package/dist/phone.d.ts +1 -1
- package/dist/request-Doq36Rt0.d.mts +19 -0
- package/dist/request-Doq36Rt0.d.ts +19 -0
- package/dist/{sales-DrH6dY5F.d.mts → sales-C7tPnqbq.d.ts} +9 -48
- package/dist/{sales-DrH6dY5F.d.ts → sales-H_6bHrL-.d.mts} +9 -48
- package/dist/sales.d.mts +3 -1
- package/dist/sales.d.ts +3 -1
- package/dist/sales.js +29 -17
- package/dist/sales.js.map +1 -1
- package/dist/sales.mjs +29 -17
- package/dist/sales.mjs.map +1 -1
- package/dist/server.d.mts +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/transport-C-_rFSR4.d.ts +721 -0
- package/dist/transport-yUF5Wize.d.mts +721 -0
- package/package.json +21 -1
package/dist/index.js
CHANGED
|
@@ -32,39 +32,71 @@ var src_exports = {};
|
|
|
32
32
|
__export(src_exports, {
|
|
33
33
|
AdPlatformTracking: () => AdPlatformTracking,
|
|
34
34
|
AranovaApiError: () => AranovaApiError,
|
|
35
|
+
BOOKING_SOURCES: () => BOOKING_SOURCES,
|
|
36
|
+
BOOKING_STATUSES: () => BOOKING_STATUSES,
|
|
37
|
+
CALENDAR_ERROR_CODES: () => CALENDAR_ERROR_CODES,
|
|
38
|
+
CALENDAR_METADATA_SCHEMA_VERSION: () => CALENDAR_METADATA_SCHEMA_VERSION,
|
|
39
|
+
CALENDAR_SYNC_STATUSES: () => CALENDAR_SYNC_STATUSES,
|
|
40
|
+
CalendarClientProvider: () => CalendarClientProvider,
|
|
35
41
|
ConsentBanner: () => ConsentBanner,
|
|
36
42
|
DEFAULT_DECLINE_TTL_DAYS: () => DEFAULT_DECLINE_TTL_DAYS,
|
|
37
43
|
DEFAULT_PHONE_COUNTRY: () => DEFAULT_PHONE_COUNTRY,
|
|
38
44
|
EVENT_SEMANTICS: () => EVENT_SEMANTICS,
|
|
45
|
+
GOOGLE_SYNC_STATES: () => GOOGLE_SYNC_STATES,
|
|
39
46
|
GoogleAdsTracking: () => GoogleAdsTracking,
|
|
47
|
+
MAX_ATTENDEES: () => MAX_ATTENDEES,
|
|
48
|
+
MAX_BOOKING_MINUTES: () => MAX_BOOKING_MINUTES,
|
|
49
|
+
MAX_REMINDER_MINUTES: () => MAX_REMINDER_MINUTES,
|
|
50
|
+
MAX_REMINDER_OVERRIDES: () => MAX_REMINDER_OVERRIDES,
|
|
40
51
|
NAMED_RANGES: () => NAMED_RANGES,
|
|
41
52
|
PhoneField: () => PhoneField,
|
|
42
53
|
SUPPORTED_CURRENCIES: () => SUPPORTED_CURRENCIES,
|
|
43
54
|
TRACKING_PARAM_KEYS: () => TRACKING_PARAM_KEYS,
|
|
44
55
|
TRACKING_RANGES: () => TRACKING_RANGES,
|
|
56
|
+
bookingAttendeeSchema: () => bookingAttendeeSchema,
|
|
57
|
+
bookingCancelSchema: () => bookingCancelSchema,
|
|
58
|
+
bookingCreateSchema: () => bookingCreateSchema,
|
|
59
|
+
bookingCustomerSchema: () => bookingCustomerSchema,
|
|
60
|
+
bookingLocationNullableSchema: () => bookingLocationNullableSchema,
|
|
61
|
+
bookingLocationSchema: () => bookingLocationSchema,
|
|
62
|
+
bookingMetadataSchema: () => bookingMetadataSchema,
|
|
63
|
+
bookingReminderSchema: () => bookingReminderSchema,
|
|
64
|
+
bookingRemindersSchema: () => bookingRemindersSchema,
|
|
65
|
+
bookingRescheduleSchema: () => bookingRescheduleSchema,
|
|
45
66
|
captureTrackingParamsFromLocation: () => captureTrackingParamsFromLocation,
|
|
46
67
|
clearStashedUserData: () => clearStashedUserData,
|
|
68
|
+
computeSlots: () => computeSlots,
|
|
69
|
+
createCalendarReadClient: () => createCalendarReadClient,
|
|
47
70
|
createSalesClient: () => createSalesClient,
|
|
48
71
|
createTracking: () => createTracking,
|
|
49
72
|
createTrackingClientContext: () => createTrackingClientContext,
|
|
50
73
|
createTrackingEventCreatePayload: () => createTrackingEventCreatePayload,
|
|
51
74
|
createTrackingSessionUpsertPayload: () => createTrackingSessionUpsertPayload,
|
|
75
|
+
durationMinutes: () => durationMinutes,
|
|
76
|
+
endOfDayInTz: () => endOfDayInTz,
|
|
52
77
|
fetchServices: () => fetchServices,
|
|
53
78
|
formatDateInTz: () => formatDateInTz,
|
|
54
79
|
formatMoney: () => formatMoney,
|
|
55
80
|
formatPhone: () => formatPhone,
|
|
56
81
|
formatPhoneAsTyped: () => formatPhoneAsTyped,
|
|
82
|
+
formatSlotRange: () => formatSlotRange,
|
|
57
83
|
fromMinor: () => fromMinor,
|
|
58
84
|
getConsentChoice: () => getConsentChoice,
|
|
59
85
|
getConsentState: () => getConsentState,
|
|
60
86
|
getEventSemantics: () => getEventSemantics,
|
|
61
87
|
getTrackingConfigRuntime: () => getTrackingConfigRuntime,
|
|
88
|
+
groupSlotsByDay: () => groupSlotsByDay,
|
|
89
|
+
instantFromWallClock: () => instantFromWallClock,
|
|
90
|
+
isCalendarError: () => isCalendarError,
|
|
91
|
+
localDateKey: () => localDateKey,
|
|
92
|
+
offsetMinutesAt: () => offsetMinutesAt,
|
|
62
93
|
onConsentChange: () => onConsentChange,
|
|
63
94
|
optIn: () => optIn,
|
|
64
95
|
optOut: () => optOut,
|
|
65
96
|
parsePhone: () => parsePhone,
|
|
66
97
|
phoneField: () => phoneField,
|
|
67
98
|
resetConsent: () => resetConsent,
|
|
99
|
+
resolveBrowserTimeZone: () => resolveBrowserTimeZone,
|
|
68
100
|
resolveConversionConfig: () => resolveConversionConfig,
|
|
69
101
|
saleCreateSchema: () => saleCreateSchema,
|
|
70
102
|
saleItemSchema: () => saleItemSchema,
|
|
@@ -72,15 +104,20 @@ __export(src_exports, {
|
|
|
72
104
|
saleUpdateSchema: () => saleUpdateSchema,
|
|
73
105
|
salesRequest: () => salesRequest,
|
|
74
106
|
setConsentState: () => setConsentState,
|
|
107
|
+
startOfDayInTz: () => startOfDayInTz,
|
|
75
108
|
stashUserData: () => stashUserData,
|
|
76
109
|
toE164: () => toE164,
|
|
77
110
|
toMinor: () => toMinor,
|
|
111
|
+
useBookingForm: () => useBookingForm,
|
|
112
|
+
useCalendarBusy: () => useCalendarBusy,
|
|
113
|
+
useCalendarClient: () => useCalendarClient,
|
|
78
114
|
useConsent: () => useConsent,
|
|
79
115
|
useConsentState: () => useConsentState,
|
|
80
116
|
useCookiePreferences: () => useCookiePreferences,
|
|
81
117
|
useGclid: () => useGclid,
|
|
82
118
|
usePhoneConfig: () => usePhoneConfig,
|
|
83
119
|
usePhoneField: () => usePhoneField,
|
|
120
|
+
useSlots: () => useSlots,
|
|
84
121
|
useTrackingParams: () => useTrackingParams
|
|
85
122
|
});
|
|
86
123
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -345,6 +382,43 @@ var aranovaConsent = (function () {
|
|
|
345
382
|
`.trim();
|
|
346
383
|
}
|
|
347
384
|
|
|
385
|
+
// ../tracking-core/src/capabilities.ts
|
|
386
|
+
var TRACKING_CAPABILITIES = [
|
|
387
|
+
"ad_tags_google",
|
|
388
|
+
"ad_tags_meta",
|
|
389
|
+
"base_tracking",
|
|
390
|
+
"blog_rendering",
|
|
391
|
+
"calendar_read",
|
|
392
|
+
"calendar_write",
|
|
393
|
+
"consent_controls",
|
|
394
|
+
"conversion_goals_auto",
|
|
395
|
+
"conversion_goals_manual",
|
|
396
|
+
"cta_click_capture",
|
|
397
|
+
"form_capture",
|
|
398
|
+
"phone_click_capture",
|
|
399
|
+
"phone_fields"
|
|
400
|
+
];
|
|
401
|
+
var CAPABILITY_DOM_ATTRIBUTE = "data-aranova-capability";
|
|
402
|
+
var registered = /* @__PURE__ */ new Set();
|
|
403
|
+
function registerCapability(capability) {
|
|
404
|
+
registered.add(capability);
|
|
405
|
+
}
|
|
406
|
+
function getRegisteredCapabilities() {
|
|
407
|
+
const all = new Set(registered);
|
|
408
|
+
for (const marker of readDomMarkers()) all.add(marker);
|
|
409
|
+
return Array.from(all).sort();
|
|
410
|
+
}
|
|
411
|
+
function readDomMarkers() {
|
|
412
|
+
if (typeof document === "undefined") return [];
|
|
413
|
+
const known = new Set(TRACKING_CAPABILITIES);
|
|
414
|
+
const found = [];
|
|
415
|
+
for (const node of document.querySelectorAll(`[${CAPABILITY_DOM_ATTRIBUTE}]`)) {
|
|
416
|
+
const value = node.getAttribute(CAPABILITY_DOM_ATTRIBUTE);
|
|
417
|
+
if (value && known.has(value)) found.push(value);
|
|
418
|
+
}
|
|
419
|
+
return found;
|
|
420
|
+
}
|
|
421
|
+
|
|
348
422
|
// ../tracking-core/src/tracking.ts
|
|
349
423
|
var TRACKING_COOKIE_MAX_AGE_SECONDS = 7776e3;
|
|
350
424
|
var TRACKING_PARAM_KEYS = [
|
|
@@ -689,7 +763,8 @@ function createTrackingClientContext(surface, input = {}) {
|
|
|
689
763
|
page_title: input.pageTitle ?? (typeof document === "undefined" ? null : document.title || null),
|
|
690
764
|
referrer: input.referrer ?? (typeof document === "undefined" ? null : document.referrer || null),
|
|
691
765
|
environment: input.environment ?? "production",
|
|
692
|
-
active_gtag_ids: input.activeGtagIds ?? null
|
|
766
|
+
active_gtag_ids: input.activeGtagIds ?? null,
|
|
767
|
+
capabilities: getRegisteredCapabilities()
|
|
693
768
|
};
|
|
694
769
|
}
|
|
695
770
|
function createTrackingSessionUpsertPayload(trackingParams, input, context) {
|
|
@@ -1033,6 +1108,21 @@ function automaticThresholdMet(goal, eventType, metadata) {
|
|
|
1033
1108
|
}
|
|
1034
1109
|
}
|
|
1035
1110
|
|
|
1111
|
+
// ../tracking-core/src/resources/intl/date.ts
|
|
1112
|
+
function formatDateInTz(iso, timeZone, opts, locale) {
|
|
1113
|
+
const date = new Date(iso);
|
|
1114
|
+
if (Number.isNaN(date.getTime())) return iso;
|
|
1115
|
+
return new Intl.DateTimeFormat(locale, {
|
|
1116
|
+
year: "numeric",
|
|
1117
|
+
month: "short",
|
|
1118
|
+
day: "2-digit",
|
|
1119
|
+
hour: "2-digit",
|
|
1120
|
+
minute: "2-digit",
|
|
1121
|
+
...opts,
|
|
1122
|
+
timeZone
|
|
1123
|
+
}).format(date);
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1036
1126
|
// ../tracking-core/src/resources/sales/money.ts
|
|
1037
1127
|
var MINOR_UNIT_EXPONENT = {
|
|
1038
1128
|
USD: 2,
|
|
@@ -1052,19 +1142,6 @@ function formatMoney(cents, currency, locale) {
|
|
|
1052
1142
|
fromMinor(cents, currency)
|
|
1053
1143
|
);
|
|
1054
1144
|
}
|
|
1055
|
-
function formatDateInTz(iso, timeZone, opts, locale) {
|
|
1056
|
-
const date = new Date(iso);
|
|
1057
|
-
if (Number.isNaN(date.getTime())) return iso;
|
|
1058
|
-
return new Intl.DateTimeFormat(locale, {
|
|
1059
|
-
year: "numeric",
|
|
1060
|
-
month: "short",
|
|
1061
|
-
day: "2-digit",
|
|
1062
|
-
hour: "2-digit",
|
|
1063
|
-
minute: "2-digit",
|
|
1064
|
-
...opts,
|
|
1065
|
-
timeZone
|
|
1066
|
-
}).format(date);
|
|
1067
|
-
}
|
|
1068
1145
|
|
|
1069
1146
|
// ../tracking-core/src/resources/tracking-config-runtime.ts
|
|
1070
1147
|
var CACHE_PREFIX2 = "_aranova_cfg_runtime_";
|
|
@@ -1681,7 +1758,10 @@ function buildContext(surface, sdkVersion, packageName, environment, activeGtagI
|
|
|
1681
1758
|
page_title: typeof document === "undefined" ? null : document.title || null,
|
|
1682
1759
|
referrer: typeof document === "undefined" ? null : document.referrer || null,
|
|
1683
1760
|
environment,
|
|
1684
|
-
active_gtag_ids: activeGtagIds
|
|
1761
|
+
active_gtag_ids: activeGtagIds,
|
|
1762
|
+
// Rebuilt per flush (this runs inside the payload builder), so a client
|
|
1763
|
+
// constructed later on a deeper route still gets reported.
|
|
1764
|
+
capabilities: getRegisteredCapabilities()
|
|
1685
1765
|
};
|
|
1686
1766
|
}
|
|
1687
1767
|
function readTrackingParams() {
|
|
@@ -2274,8 +2354,9 @@ function getEventDefinition(name) {
|
|
|
2274
2354
|
}
|
|
2275
2355
|
|
|
2276
2356
|
// ../tracking-core/src/ingest-typed.ts
|
|
2277
|
-
function createTypedClient(raw,
|
|
2357
|
+
function createTypedClient(raw, registry, options = {}) {
|
|
2278
2358
|
const debug = options.debug ?? false;
|
|
2359
|
+
if (registry.manual?.form_submit) registerCapability("form_capture");
|
|
2279
2360
|
return {
|
|
2280
2361
|
trackEvent(eventType, metadata, opts) {
|
|
2281
2362
|
if (debug) {
|
|
@@ -2682,6 +2763,7 @@ function attachCtaClickCapture(client, config) {
|
|
|
2682
2763
|
return () => {
|
|
2683
2764
|
};
|
|
2684
2765
|
}
|
|
2766
|
+
registerCapability("cta_click_capture");
|
|
2685
2767
|
const selector = autoCapture.selector ?? DEFAULT_CTA_SELECTOR;
|
|
2686
2768
|
function onClick(event) {
|
|
2687
2769
|
const target = event.target;
|
|
@@ -2738,6 +2820,7 @@ function attachPhoneClickCapture(client, config) {
|
|
|
2738
2820
|
return () => {
|
|
2739
2821
|
};
|
|
2740
2822
|
}
|
|
2823
|
+
registerCapability("phone_click_capture");
|
|
2741
2824
|
const selector = autoCapture.selector ?? DEFAULT_TEL_SELECTOR;
|
|
2742
2825
|
function onClick(event) {
|
|
2743
2826
|
const target = event.target;
|
|
@@ -2767,7 +2850,7 @@ function attachPhoneClickCapture(client, config) {
|
|
|
2767
2850
|
};
|
|
2768
2851
|
}
|
|
2769
2852
|
|
|
2770
|
-
// ../tracking-core/src/resources/
|
|
2853
|
+
// ../tracking-core/src/resources/http/errors.ts
|
|
2771
2854
|
var AranovaApiError = class extends Error {
|
|
2772
2855
|
constructor(message, options) {
|
|
2773
2856
|
super(message);
|
|
@@ -2778,7 +2861,7 @@ var AranovaApiError = class extends Error {
|
|
|
2778
2861
|
}
|
|
2779
2862
|
};
|
|
2780
2863
|
|
|
2781
|
-
// ../tracking-core/src/resources/
|
|
2864
|
+
// ../tracking-core/src/resources/http/request.ts
|
|
2782
2865
|
function identityHeaders(config) {
|
|
2783
2866
|
const headers = { [API_KEY_HEADER]: config.apiKey };
|
|
2784
2867
|
if (config.sdkVersion) headers[SDK_VERSION_HEADER] = config.sdkVersion;
|
|
@@ -2790,8 +2873,8 @@ function identityHeaders(config) {
|
|
|
2790
2873
|
function joinUrl(endpoint, path) {
|
|
2791
2874
|
return `${endpoint.replace(/\/$/, "")}${path}`;
|
|
2792
2875
|
}
|
|
2793
|
-
async function
|
|
2794
|
-
const headers = identityHeaders(config);
|
|
2876
|
+
async function apiRequest(config, method, path, body, extraHeaders) {
|
|
2877
|
+
const headers = { ...identityHeaders(config), ...extraHeaders };
|
|
2795
2878
|
if (body !== void 0) headers["Content-Type"] = "application/json";
|
|
2796
2879
|
const response = await fetch(joinUrl(config.endpoint, path), {
|
|
2797
2880
|
method,
|
|
@@ -2820,6 +2903,9 @@ async function salesRequest(config, method, path, body) {
|
|
|
2820
2903
|
return await response.json();
|
|
2821
2904
|
}
|
|
2822
2905
|
|
|
2906
|
+
// ../tracking-core/src/resources/sales/transport.ts
|
|
2907
|
+
var salesRequest = apiRequest;
|
|
2908
|
+
|
|
2823
2909
|
// ../tracking-core/src/resources/sales/client.ts
|
|
2824
2910
|
function fireRecordedConversions(firing, input, recorded, sale, currency) {
|
|
2825
2911
|
if (!firing) return;
|
|
@@ -2851,6 +2937,7 @@ function fireRecordedConversions(firing, input, recorded, sale, currency) {
|
|
|
2851
2937
|
}
|
|
2852
2938
|
}
|
|
2853
2939
|
function createSalesClient(config) {
|
|
2940
|
+
if (config.firing) registerCapability("conversion_goals_manual");
|
|
2854
2941
|
async function record(input) {
|
|
2855
2942
|
const currency = input.currency ?? config.defaultCurrency;
|
|
2856
2943
|
if (!currency) {
|
|
@@ -3150,6 +3237,7 @@ var DEFAULT_CHOICE2 = {
|
|
|
3150
3237
|
expiresAt: null
|
|
3151
3238
|
};
|
|
3152
3239
|
function useCookiePreferences(options) {
|
|
3240
|
+
registerCapability("consent_controls");
|
|
3153
3241
|
const [choice, setChoice] = (0, import_react.useState)(DEFAULT_CHOICE2);
|
|
3154
3242
|
const ttlDays = options?.declineTtlDays;
|
|
3155
3243
|
(0, import_react.useEffect)(() => {
|
|
@@ -3417,6 +3505,8 @@ function AdPlatformTracking({
|
|
|
3417
3505
|
}, [trackingConfigKey, standalonePageView]);
|
|
3418
3506
|
const gtagAll = trackingConfig ? [] : gtagIds ? Object.values(gtagIds).filter((id) => id != null) : gtagId ? [gtagId] : [];
|
|
3419
3507
|
const metaAll = metaPixelIds ? Object.values(metaPixelIds).filter((id) => id != null) : metaPixelId ? [metaPixelId] : [];
|
|
3508
|
+
if (trackingConfig || gtagAll.length > 0) registerCapability("ad_tags_google");
|
|
3509
|
+
if (metaAll.length > 0) registerCapability("ad_tags_meta");
|
|
3420
3510
|
const gtagLoaderId = gtagAll[0];
|
|
3421
3511
|
const gtagInitScript = gtagAll.length === 1 ? createGtagInitScript(gtagAll[0]) : createGtagInitScriptMulti(gtagAll);
|
|
3422
3512
|
const metaInitScript = metaAll.length === 1 ? createMetaPixelInitScript(metaAll[0]) : createMetaPixelInitScriptMulti(metaAll);
|
|
@@ -3465,7 +3555,7 @@ function GoogleAdsTracking(props) {
|
|
|
3465
3555
|
var import_navigation3 = require("next/navigation");
|
|
3466
3556
|
|
|
3467
3557
|
// package.json
|
|
3468
|
-
var version = "0.
|
|
3558
|
+
var version = "0.22.0";
|
|
3469
3559
|
|
|
3470
3560
|
// src/factory.tsx
|
|
3471
3561
|
var import_react5 = require("react");
|
|
@@ -3492,6 +3582,7 @@ function usePhoneConfig() {
|
|
|
3492
3582
|
};
|
|
3493
3583
|
}
|
|
3494
3584
|
function usePhoneField(opts = {}) {
|
|
3585
|
+
registerCapability("phone_fields");
|
|
3495
3586
|
const cfg = usePhoneConfig();
|
|
3496
3587
|
const country = opts.country ?? cfg.defaultCountry;
|
|
3497
3588
|
const display = opts.display ?? cfg.display;
|
|
@@ -3578,6 +3669,8 @@ function createTracking(options) {
|
|
|
3578
3669
|
conversionConfig,
|
|
3579
3670
|
trackingConfig
|
|
3580
3671
|
} = options;
|
|
3672
|
+
registerCapability("base_tracking");
|
|
3673
|
+
if (trackingConfig) registerCapability("conversion_goals_auto");
|
|
3581
3674
|
if (!apiKey || !endpoint) {
|
|
3582
3675
|
if (apiKey || endpoint) {
|
|
3583
3676
|
console.warn(
|
|
@@ -3746,43 +3839,490 @@ function createTracking(options) {
|
|
|
3746
3839
|
}
|
|
3747
3840
|
return { TrackingProvider, useTracking };
|
|
3748
3841
|
}
|
|
3842
|
+
|
|
3843
|
+
// ../tracking-core/src/resources/calendar/transport.ts
|
|
3844
|
+
async function calendarRequest(config, method, path, body) {
|
|
3845
|
+
return apiRequest(config, method, `/calendar${path}`, body);
|
|
3846
|
+
}
|
|
3847
|
+
|
|
3848
|
+
// ../tracking-core/src/resources/calendar/time.ts
|
|
3849
|
+
function resolveBrowserTimeZone() {
|
|
3850
|
+
try {
|
|
3851
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
|
|
3852
|
+
} catch {
|
|
3853
|
+
return "UTC";
|
|
3854
|
+
}
|
|
3855
|
+
}
|
|
3856
|
+
function partsInTz(date, timeZone) {
|
|
3857
|
+
const formatter = new Intl.DateTimeFormat("en-US", {
|
|
3858
|
+
timeZone,
|
|
3859
|
+
hour12: false,
|
|
3860
|
+
year: "numeric",
|
|
3861
|
+
month: "2-digit",
|
|
3862
|
+
day: "2-digit",
|
|
3863
|
+
hour: "2-digit",
|
|
3864
|
+
minute: "2-digit",
|
|
3865
|
+
second: "2-digit"
|
|
3866
|
+
});
|
|
3867
|
+
const out = {};
|
|
3868
|
+
for (const part of formatter.formatToParts(date)) {
|
|
3869
|
+
if (part.type !== "literal") out[part.type] = Number(part.value);
|
|
3870
|
+
}
|
|
3871
|
+
if (out.hour === 24) out.hour = 0;
|
|
3872
|
+
return out;
|
|
3873
|
+
}
|
|
3874
|
+
function offsetMinutesAt(date, timeZone) {
|
|
3875
|
+
const p = partsInTz(date, timeZone);
|
|
3876
|
+
const asUtc = Date.UTC(p.year, p.month - 1, p.day, p.hour, p.minute, p.second);
|
|
3877
|
+
return (asUtc - Math.floor(date.getTime() / 1e3) * 1e3) / 6e4;
|
|
3878
|
+
}
|
|
3879
|
+
function instantFromWallClock(timeZone, year, month, day, hour = 0, minute = 0) {
|
|
3880
|
+
const naive = Date.UTC(year, month - 1, day, hour, minute);
|
|
3881
|
+
const firstGuess = new Date(naive - offsetMinutesAt(new Date(naive), timeZone) * 6e4);
|
|
3882
|
+
const corrected = naive - offsetMinutesAt(firstGuess, timeZone) * 6e4;
|
|
3883
|
+
return new Date(corrected);
|
|
3884
|
+
}
|
|
3885
|
+
function localDateKey(iso, timeZone) {
|
|
3886
|
+
const p = partsInTz(new Date(iso), timeZone);
|
|
3887
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
3888
|
+
return `${p.year}-${pad(p.month)}-${pad(p.day)}`;
|
|
3889
|
+
}
|
|
3890
|
+
function startOfDayInTz(dateKey, timeZone) {
|
|
3891
|
+
const [year, month, day] = dateKey.split("-").map(Number);
|
|
3892
|
+
return instantFromWallClock(timeZone, year, month, day, 0, 0);
|
|
3893
|
+
}
|
|
3894
|
+
function endOfDayInTz(dateKey, timeZone) {
|
|
3895
|
+
const start = startOfDayInTz(dateKey, timeZone);
|
|
3896
|
+
const p = partsInTz(start, timeZone);
|
|
3897
|
+
return instantFromWallClock(timeZone, p.year, p.month, p.day + 1, 0, 0);
|
|
3898
|
+
}
|
|
3899
|
+
function durationMinutes(startIso, endIso) {
|
|
3900
|
+
return Math.round((new Date(endIso).getTime() - new Date(startIso).getTime()) / 6e4);
|
|
3901
|
+
}
|
|
3902
|
+
function formatSlotRange(startIso, endIso, timeZone, locale) {
|
|
3903
|
+
const opts = { hour: "2-digit", minute: "2-digit", timeZone };
|
|
3904
|
+
const fmt = new Intl.DateTimeFormat(locale, opts);
|
|
3905
|
+
return `${fmt.format(new Date(startIso))} \u2013 ${fmt.format(new Date(endIso))}`;
|
|
3906
|
+
}
|
|
3907
|
+
|
|
3908
|
+
// ../tracking-core/src/resources/calendar/read-client.ts
|
|
3909
|
+
function withBusiness(config, path) {
|
|
3910
|
+
if (!config.businessId) return path;
|
|
3911
|
+
const separator = path.includes("?") ? "&" : "?";
|
|
3912
|
+
return `${path}${separator}business_id=${encodeURIComponent(config.businessId)}`;
|
|
3913
|
+
}
|
|
3914
|
+
function createCalendarReadClient(config) {
|
|
3915
|
+
registerCapability("calendar_read");
|
|
3916
|
+
return {
|
|
3917
|
+
async listCalendars() {
|
|
3918
|
+
return calendarRequest(config, "GET", withBusiness(config, "/calendars"));
|
|
3919
|
+
},
|
|
3920
|
+
async busy(calendarKey, query) {
|
|
3921
|
+
const params = new URLSearchParams({
|
|
3922
|
+
since: query.since,
|
|
3923
|
+
until: query.until
|
|
3924
|
+
});
|
|
3925
|
+
const timeZone = query.timeZone ?? config.defaultTimeZone ?? resolveBrowserTimeZone();
|
|
3926
|
+
params.set("time_zone", timeZone);
|
|
3927
|
+
return calendarRequest(
|
|
3928
|
+
config,
|
|
3929
|
+
"GET",
|
|
3930
|
+
withBusiness(config, `/${encodeURIComponent(calendarKey)}/busy?${params.toString()}`)
|
|
3931
|
+
);
|
|
3932
|
+
}
|
|
3933
|
+
};
|
|
3934
|
+
}
|
|
3935
|
+
function isCalendarError(error, code) {
|
|
3936
|
+
if (!(error instanceof AranovaApiError)) return false;
|
|
3937
|
+
return code === void 0 || error.code === code;
|
|
3938
|
+
}
|
|
3939
|
+
|
|
3940
|
+
// ../tracking-core/src/resources/calendar/schema.ts
|
|
3941
|
+
var import_zod13 = require("zod");
|
|
3942
|
+
var CALENDAR_METADATA_SCHEMA_VERSION = 1;
|
|
3943
|
+
var MAX_ATTENDEES = 20;
|
|
3944
|
+
var MAX_REMINDER_OVERRIDES = 5;
|
|
3945
|
+
var MAX_REMINDER_MINUTES = 40320;
|
|
3946
|
+
var MAX_BOOKING_MINUTES = 1440;
|
|
3947
|
+
var BOOKING_SOURCES = ["website", "phone", "walk_in", "import", "operator"];
|
|
3948
|
+
var BOOKING_STATUSES = ["pending", "confirmed", "cancelled", "no_show"];
|
|
3949
|
+
var GOOGLE_SYNC_STATES = ["queued", "synced", "uncertain", "failed", "drifted"];
|
|
3950
|
+
var CALENDAR_SYNC_STATUSES = [
|
|
3951
|
+
"pending_invite",
|
|
3952
|
+
"awaiting_calendar_selection",
|
|
3953
|
+
"connected",
|
|
3954
|
+
"needs_reconnect",
|
|
3955
|
+
"revoked",
|
|
3956
|
+
"disabled"
|
|
3957
|
+
];
|
|
3958
|
+
var CALENDAR_ERROR_CODES = [
|
|
3959
|
+
"slot_unavailable",
|
|
3960
|
+
"calendar_not_connected",
|
|
3961
|
+
"calendar_disconnected",
|
|
3962
|
+
"booking_not_found",
|
|
3963
|
+
"outside_booking_window",
|
|
3964
|
+
"rate_limited",
|
|
3965
|
+
"google_error"
|
|
3966
|
+
];
|
|
3967
|
+
var isoInstant = import_zod13.z.string().datetime({ offset: true });
|
|
3968
|
+
function isKnownTimeZone(timeZone) {
|
|
3969
|
+
try {
|
|
3970
|
+
new Intl.DateTimeFormat(void 0, { timeZone });
|
|
3971
|
+
return true;
|
|
3972
|
+
} catch {
|
|
3973
|
+
return false;
|
|
3974
|
+
}
|
|
3975
|
+
}
|
|
3976
|
+
var ianaTz = import_zod13.z.string().min(1).max(64).regex(/^[A-Za-z0-9_+\-/]+$/).refine(isKnownTimeZone, { message: "unknown IANA time zone" });
|
|
3977
|
+
var bookingAttendeeSchema = import_zod13.z.object({
|
|
3978
|
+
email: import_zod13.z.string().max(320).email(),
|
|
3979
|
+
display_name: import_zod13.z.string().max(200).nullable().optional(),
|
|
3980
|
+
optional: import_zod13.z.boolean().default(false)
|
|
3981
|
+
}).strict();
|
|
3982
|
+
var bookingReminderSchema = import_zod13.z.object({
|
|
3983
|
+
method: import_zod13.z.enum(["email", "popup"]),
|
|
3984
|
+
minutes_before: import_zod13.z.number().int().min(0).max(MAX_REMINDER_MINUTES)
|
|
3985
|
+
}).strict();
|
|
3986
|
+
var bookingRemindersSchema = import_zod13.z.object({
|
|
3987
|
+
use_calendar_defaults: import_zod13.z.boolean().default(true),
|
|
3988
|
+
overrides: import_zod13.z.array(bookingReminderSchema).max(MAX_REMINDER_OVERRIDES).default([])
|
|
3989
|
+
}).strict();
|
|
3990
|
+
var bookingLocationSchema = import_zod13.z.union([
|
|
3991
|
+
import_zod13.z.object({ kind: import_zod13.z.literal("google_meet") }).strict(),
|
|
3992
|
+
import_zod13.z.object({ kind: import_zod13.z.literal("physical"), address: import_zod13.z.string().max(1024) }).strict(),
|
|
3993
|
+
import_zod13.z.object({ kind: import_zod13.z.literal("phone"), phone: import_zod13.z.string().max(64) }).strict(),
|
|
3994
|
+
import_zod13.z.object({ kind: import_zod13.z.literal("custom"), text: import_zod13.z.string().max(1024) }).strict()
|
|
3995
|
+
]);
|
|
3996
|
+
var bookingLocationNullableSchema = import_zod13.z.union([...bookingLocationSchema.options, import_zod13.z.null()]);
|
|
3997
|
+
var bookingCustomerSchema = import_zod13.z.object({
|
|
3998
|
+
// Required: Google needs an address to send the invite that confirms the
|
|
3999
|
+
// booking, and that invite is the whole confirmation mechanism.
|
|
4000
|
+
email: import_zod13.z.string().max(320).email(),
|
|
4001
|
+
name: import_zod13.z.string().max(200).nullable().optional(),
|
|
4002
|
+
phone: import_zod13.z.string().max(64).nullable().optional(),
|
|
4003
|
+
sms_consent: import_zod13.z.boolean().default(false)
|
|
4004
|
+
}).strict();
|
|
4005
|
+
var jsonScalar = import_zod13.z.union([import_zod13.z.string(), import_zod13.z.number(), import_zod13.z.boolean(), import_zod13.z.null()]);
|
|
4006
|
+
var bookingMetadataSchema = import_zod13.z.object({
|
|
4007
|
+
schema_version: import_zod13.z.number().int().default(CALENDAR_METADATA_SCHEMA_VERSION),
|
|
4008
|
+
source: import_zod13.z.enum(BOOKING_SOURCES).nullable().optional(),
|
|
4009
|
+
service: import_zod13.z.string().max(64).nullable().optional(),
|
|
4010
|
+
visitor_id: import_zod13.z.string().max(64).nullable().optional(),
|
|
4011
|
+
session_id: import_zod13.z.string().max(64).nullable().optional(),
|
|
4012
|
+
gclid: import_zod13.z.string().max(256).nullable().optional(),
|
|
4013
|
+
fbclid: import_zod13.z.string().max(256).nullable().optional(),
|
|
4014
|
+
utm_source: import_zod13.z.string().max(128).nullable().optional(),
|
|
4015
|
+
utm_medium: import_zod13.z.string().max(128).nullable().optional(),
|
|
4016
|
+
utm_campaign: import_zod13.z.string().max(128).nullable().optional(),
|
|
4017
|
+
utm_term: import_zod13.z.string().max(128).nullable().optional(),
|
|
4018
|
+
utm_content: import_zod13.z.string().max(128).nullable().optional(),
|
|
4019
|
+
landing_page: import_zod13.z.string().max(2048).nullable().optional(),
|
|
4020
|
+
referrer: import_zod13.z.string().max(2048).nullable().optional(),
|
|
4021
|
+
notes: import_zod13.z.string().max(2e3).nullable().optional(),
|
|
4022
|
+
custom: import_zod13.z.record(jsonScalar).nullable().optional()
|
|
4023
|
+
}).strict();
|
|
4024
|
+
function refineEndXor(value, ctx) {
|
|
4025
|
+
const hasEnd = value.end_at !== void 0 && value.end_at !== null;
|
|
4026
|
+
const hasDuration = value.duration_minutes !== void 0 && value.duration_minutes !== null;
|
|
4027
|
+
if (hasEnd === hasDuration) {
|
|
4028
|
+
ctx.addIssue({
|
|
4029
|
+
code: import_zod13.z.ZodIssueCode.custom,
|
|
4030
|
+
message: "provide exactly one of end_at or duration_minutes",
|
|
4031
|
+
path: ["end_at"]
|
|
4032
|
+
});
|
|
4033
|
+
return;
|
|
4034
|
+
}
|
|
4035
|
+
if (hasEnd && new Date(value.end_at) <= new Date(value.start_at)) {
|
|
4036
|
+
ctx.addIssue({
|
|
4037
|
+
code: import_zod13.z.ZodIssueCode.custom,
|
|
4038
|
+
message: "end_at must be after start_at",
|
|
4039
|
+
path: ["end_at"]
|
|
4040
|
+
});
|
|
4041
|
+
}
|
|
4042
|
+
}
|
|
4043
|
+
var bookingCreateSchema = import_zod13.z.object({
|
|
4044
|
+
calendar_key: import_zod13.z.string().min(1).max(64),
|
|
4045
|
+
// Free-form: appointment types are the client site's own vocabulary, not
|
|
4046
|
+
// configuration the dashboard holds.
|
|
4047
|
+
appointment_type: import_zod13.z.string().max(64).nullable().optional(),
|
|
4048
|
+
start_at: isoInstant,
|
|
4049
|
+
end_at: isoInstant.nullable().optional(),
|
|
4050
|
+
duration_minutes: import_zod13.z.number().int().positive().max(MAX_BOOKING_MINUTES).nullable().optional(),
|
|
4051
|
+
/** The booker's zone — distinct from the business's and the calendar's. */
|
|
4052
|
+
time_zone: ianaTz,
|
|
4053
|
+
title: import_zod13.z.string().max(300).nullable().optional(),
|
|
4054
|
+
description: import_zod13.z.string().max(8e3).nullable().optional(),
|
|
4055
|
+
location: bookingLocationNullableSchema.optional(),
|
|
4056
|
+
customer: bookingCustomerSchema,
|
|
4057
|
+
attendees: import_zod13.z.array(bookingAttendeeSchema).max(MAX_ATTENDEES).default([]),
|
|
4058
|
+
send_invites: import_zod13.z.boolean().default(true),
|
|
4059
|
+
reminders: bookingRemindersSchema.nullable().optional(),
|
|
4060
|
+
metadata: bookingMetadataSchema.nullable().optional(),
|
|
4061
|
+
idempotency_key: import_zod13.z.string().max(128).nullable().optional(),
|
|
4062
|
+
buffer_before_minutes: import_zod13.z.number().int().min(0).max(MAX_BOOKING_MINUTES).default(0),
|
|
4063
|
+
buffer_after_minutes: import_zod13.z.number().int().min(0).max(MAX_BOOKING_MINUTES).default(0)
|
|
4064
|
+
}).strict().superRefine(refineEndXor);
|
|
4065
|
+
var bookingRescheduleSchema = import_zod13.z.object({
|
|
4066
|
+
start_at: isoInstant,
|
|
4067
|
+
end_at: isoInstant.nullable().optional(),
|
|
4068
|
+
duration_minutes: import_zod13.z.number().int().positive().max(MAX_BOOKING_MINUTES).nullable().optional(),
|
|
4069
|
+
time_zone: ianaTz,
|
|
4070
|
+
notify_attendees: import_zod13.z.boolean().default(true),
|
|
4071
|
+
reason: import_zod13.z.string().max(500).nullable().optional()
|
|
4072
|
+
}).strict().superRefine(refineEndXor);
|
|
4073
|
+
var bookingCancelSchema = import_zod13.z.object({
|
|
4074
|
+
reason: import_zod13.z.string().max(500).nullable().optional(),
|
|
4075
|
+
notify_attendees: import_zod13.z.boolean().default(true)
|
|
4076
|
+
}).strict();
|
|
4077
|
+
|
|
4078
|
+
// ../tracking-core/src/resources/calendar/slots.ts
|
|
4079
|
+
function parseHhMm(value) {
|
|
4080
|
+
const [hour, minute] = value.split(":").map(Number);
|
|
4081
|
+
return [hour || 0, minute || 0];
|
|
4082
|
+
}
|
|
4083
|
+
function dateKeyOf(date, timeZone) {
|
|
4084
|
+
const fmt = new Intl.DateTimeFormat("en-CA", {
|
|
4085
|
+
timeZone,
|
|
4086
|
+
year: "numeric",
|
|
4087
|
+
month: "2-digit",
|
|
4088
|
+
day: "2-digit"
|
|
4089
|
+
});
|
|
4090
|
+
return fmt.format(date);
|
|
4091
|
+
}
|
|
4092
|
+
function weekdayFromDateKey(dateKey) {
|
|
4093
|
+
const [year, month, day] = dateKey.split("-").map(Number);
|
|
4094
|
+
return new Date(Date.UTC(year, month - 1, day, 12)).getUTCDay();
|
|
4095
|
+
}
|
|
4096
|
+
function startOfLocalDay(at, timeZone) {
|
|
4097
|
+
const [year, month, day] = dateKeyOf(at, timeZone).split("-").map(Number);
|
|
4098
|
+
return instantFromWallClock(timeZone, year, month, day, 12, 0);
|
|
4099
|
+
}
|
|
4100
|
+
function overlaps(aStart, aEnd, bStart, bEnd) {
|
|
4101
|
+
return aStart < bEnd && aEnd > bStart;
|
|
4102
|
+
}
|
|
4103
|
+
function computeSlots(options) {
|
|
4104
|
+
const {
|
|
4105
|
+
busy,
|
|
4106
|
+
openingHours,
|
|
4107
|
+
timeZone,
|
|
4108
|
+
durationMinutes: durationMinutes2,
|
|
4109
|
+
granularityMinutes = 15,
|
|
4110
|
+
minNoticeMinutes = 0,
|
|
4111
|
+
bufferBeforeMinutes = 0,
|
|
4112
|
+
bufferAfterMinutes = 0,
|
|
4113
|
+
windowDays = 30,
|
|
4114
|
+
now = /* @__PURE__ */ new Date()
|
|
4115
|
+
} = options;
|
|
4116
|
+
const earliest = now.getTime() + minNoticeMinutes * 6e4;
|
|
4117
|
+
const busyRanges = busy.map((interval) => [
|
|
4118
|
+
new Date(interval.start_at).getTime(),
|
|
4119
|
+
new Date(interval.end_at).getTime()
|
|
4120
|
+
]);
|
|
4121
|
+
const slots = [];
|
|
4122
|
+
let cursor = startOfLocalDay(now, timeZone);
|
|
4123
|
+
for (let dayOffset = 0; dayOffset < windowDays; dayOffset += 1) {
|
|
4124
|
+
const dateKey = dateKeyOf(cursor, timeZone);
|
|
4125
|
+
const [year, month, day] = dateKey.split("-").map(Number);
|
|
4126
|
+
cursor = instantFromWallClock(timeZone, year, month, day + 1, 12, 0);
|
|
4127
|
+
if (openingHours.closedDates?.includes(dateKey)) continue;
|
|
4128
|
+
const intervals = openingHours.overrides?.[dateKey] ?? openingHours.weekly[weekdayFromDateKey(dateKey)] ?? [];
|
|
4129
|
+
for (const interval of intervals) {
|
|
4130
|
+
const [openHour, openMinute] = parseHhMm(interval.start);
|
|
4131
|
+
const [closeHour, closeMinute] = parseHhMm(interval.end);
|
|
4132
|
+
const opensAt = instantFromWallClock(timeZone, year, month, day, openHour, openMinute);
|
|
4133
|
+
const closesAt = instantFromWallClock(timeZone, year, month, day, closeHour, closeMinute);
|
|
4134
|
+
for (let start = opensAt.getTime(); start + durationMinutes2 * 6e4 <= closesAt.getTime(); start += granularityMinutes * 6e4) {
|
|
4135
|
+
const end = start + durationMinutes2 * 6e4;
|
|
4136
|
+
if (start < earliest) continue;
|
|
4137
|
+
const blockedStart = start - bufferBeforeMinutes * 6e4;
|
|
4138
|
+
const blockedEnd = end + bufferAfterMinutes * 6e4;
|
|
4139
|
+
const taken = busyRanges.some(
|
|
4140
|
+
([busyStart, busyEnd]) => overlaps(blockedStart, blockedEnd, busyStart, busyEnd)
|
|
4141
|
+
);
|
|
4142
|
+
if (taken) continue;
|
|
4143
|
+
slots.push({
|
|
4144
|
+
start_at: new Date(start).toISOString(),
|
|
4145
|
+
end_at: new Date(end).toISOString()
|
|
4146
|
+
});
|
|
4147
|
+
}
|
|
4148
|
+
}
|
|
4149
|
+
}
|
|
4150
|
+
slots.sort((a, b) => a.start_at.localeCompare(b.start_at));
|
|
4151
|
+
return { slots, nextAvailableAt: slots[0]?.start_at ?? null };
|
|
4152
|
+
}
|
|
4153
|
+
function groupSlotsByDay(slots, timeZone) {
|
|
4154
|
+
const byDay = /* @__PURE__ */ new Map();
|
|
4155
|
+
for (const slot of slots) {
|
|
4156
|
+
const key = dateKeyOf(new Date(slot.start_at), timeZone);
|
|
4157
|
+
const bucket = byDay.get(key);
|
|
4158
|
+
if (bucket) bucket.push(slot);
|
|
4159
|
+
else byDay.set(key, [slot]);
|
|
4160
|
+
}
|
|
4161
|
+
return [...byDay.entries()].map(([date, daySlots]) => ({ date, slots: daySlots })).sort((a, b) => a.date.localeCompare(b.date));
|
|
4162
|
+
}
|
|
4163
|
+
|
|
4164
|
+
// ../tracking-core/src/calendar-react.tsx
|
|
4165
|
+
var import_react6 = require("react");
|
|
4166
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
4167
|
+
var _calendarClientContext;
|
|
4168
|
+
function calendarClientContext() {
|
|
4169
|
+
return _calendarClientContext ?? (_calendarClientContext = (0, import_react6.createContext)(null));
|
|
4170
|
+
}
|
|
4171
|
+
function CalendarClientProvider({
|
|
4172
|
+
value,
|
|
4173
|
+
children
|
|
4174
|
+
}) {
|
|
4175
|
+
const Ctx = calendarClientContext();
|
|
4176
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Ctx.Provider, { value, children });
|
|
4177
|
+
}
|
|
4178
|
+
function useCalendarClient() {
|
|
4179
|
+
const client = (0, import_react6.useContext)(calendarClientContext());
|
|
4180
|
+
if (!client) {
|
|
4181
|
+
throw new Error(
|
|
4182
|
+
"useCalendarClient requires <CalendarClientProvider>. Wire it via createTracking({ calendar })."
|
|
4183
|
+
);
|
|
4184
|
+
}
|
|
4185
|
+
return client;
|
|
4186
|
+
}
|
|
4187
|
+
function useCalendarBusy(calendarKey, window2) {
|
|
4188
|
+
const client = useCalendarClient();
|
|
4189
|
+
const [busy, setBusy] = (0, import_react6.useState)([]);
|
|
4190
|
+
const [timeZone, setTimeZone] = (0, import_react6.useState)(resolveBrowserTimeZone());
|
|
4191
|
+
const [isLoading, setIsLoading] = (0, import_react6.useState)(true);
|
|
4192
|
+
const [error, setError] = (0, import_react6.useState)(null);
|
|
4193
|
+
const [nonce, setNonce] = (0, import_react6.useState)(0);
|
|
4194
|
+
(0, import_react6.useEffect)(() => {
|
|
4195
|
+
const controller = new AbortController();
|
|
4196
|
+
setIsLoading(true);
|
|
4197
|
+
client.busy(calendarKey, { since: window2.since, until: window2.until }).then((response) => {
|
|
4198
|
+
if (controller.signal.aborted) return;
|
|
4199
|
+
setBusy(response.busy);
|
|
4200
|
+
setTimeZone(response.time_zone);
|
|
4201
|
+
setError(null);
|
|
4202
|
+
}).catch((cause) => {
|
|
4203
|
+
if (controller.signal.aborted) return;
|
|
4204
|
+
setError(cause instanceof Error ? cause : new Error(String(cause)));
|
|
4205
|
+
}).finally(() => {
|
|
4206
|
+
if (!controller.signal.aborted) setIsLoading(false);
|
|
4207
|
+
});
|
|
4208
|
+
return () => controller.abort();
|
|
4209
|
+
}, [client, calendarKey, window2.since, window2.until, nonce]);
|
|
4210
|
+
const refetch = (0, import_react6.useCallback)(() => setNonce((value) => value + 1), []);
|
|
4211
|
+
return { busy, timeZone, isLoading, error, refetch };
|
|
4212
|
+
}
|
|
4213
|
+
function useSlots(busy, timeZone, options) {
|
|
4214
|
+
const zone = options.timeZone ?? timeZone;
|
|
4215
|
+
return (0, import_react6.useMemo)(() => {
|
|
4216
|
+
const { slots, nextAvailableAt } = computeSlots({ ...options, busy, timeZone: zone });
|
|
4217
|
+
return { slots, days: groupSlotsByDay(slots, zone), nextAvailableAt };
|
|
4218
|
+
}, [busy, zone, options]);
|
|
4219
|
+
}
|
|
4220
|
+
function useBookingForm(options = {}) {
|
|
4221
|
+
const endpoint = options.endpoint ?? "/api/aranova/calendar/bookings";
|
|
4222
|
+
const [status, setStatus] = (0, import_react6.useState)("idle");
|
|
4223
|
+
const [error, setError] = (0, import_react6.useState)(null);
|
|
4224
|
+
const [booking, setBooking] = (0, import_react6.useState)(null);
|
|
4225
|
+
const submit = (0, import_react6.useCallback)(
|
|
4226
|
+
async (input) => {
|
|
4227
|
+
setStatus("submitting");
|
|
4228
|
+
setError(null);
|
|
4229
|
+
try {
|
|
4230
|
+
const response = await fetch(endpoint, {
|
|
4231
|
+
method: "POST",
|
|
4232
|
+
headers: { "Content-Type": "application/json" },
|
|
4233
|
+
body: JSON.stringify(input)
|
|
4234
|
+
});
|
|
4235
|
+
const body = await response.json().catch(() => null);
|
|
4236
|
+
if (!response.ok) {
|
|
4237
|
+
const detail = body && typeof body === "object" && typeof body.detail === "string" ? body.detail : "Booking failed";
|
|
4238
|
+
throw new Error(detail);
|
|
4239
|
+
}
|
|
4240
|
+
setBooking(body);
|
|
4241
|
+
setStatus("confirmed");
|
|
4242
|
+
options.onConfirmed?.(body);
|
|
4243
|
+
} catch (cause) {
|
|
4244
|
+
setError(cause instanceof Error ? cause : new Error(String(cause)));
|
|
4245
|
+
setStatus("failed");
|
|
4246
|
+
}
|
|
4247
|
+
},
|
|
4248
|
+
[endpoint, options]
|
|
4249
|
+
);
|
|
4250
|
+
const reset = (0, import_react6.useCallback)(() => {
|
|
4251
|
+
setStatus("idle");
|
|
4252
|
+
setError(null);
|
|
4253
|
+
setBooking(null);
|
|
4254
|
+
}, []);
|
|
4255
|
+
return { status, error, booking, submit, reset };
|
|
4256
|
+
}
|
|
3749
4257
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3750
4258
|
0 && (module.exports = {
|
|
3751
4259
|
AdPlatformTracking,
|
|
3752
4260
|
AranovaApiError,
|
|
4261
|
+
BOOKING_SOURCES,
|
|
4262
|
+
BOOKING_STATUSES,
|
|
4263
|
+
CALENDAR_ERROR_CODES,
|
|
4264
|
+
CALENDAR_METADATA_SCHEMA_VERSION,
|
|
4265
|
+
CALENDAR_SYNC_STATUSES,
|
|
4266
|
+
CalendarClientProvider,
|
|
3753
4267
|
ConsentBanner,
|
|
3754
4268
|
DEFAULT_DECLINE_TTL_DAYS,
|
|
3755
4269
|
DEFAULT_PHONE_COUNTRY,
|
|
3756
4270
|
EVENT_SEMANTICS,
|
|
4271
|
+
GOOGLE_SYNC_STATES,
|
|
3757
4272
|
GoogleAdsTracking,
|
|
4273
|
+
MAX_ATTENDEES,
|
|
4274
|
+
MAX_BOOKING_MINUTES,
|
|
4275
|
+
MAX_REMINDER_MINUTES,
|
|
4276
|
+
MAX_REMINDER_OVERRIDES,
|
|
3758
4277
|
NAMED_RANGES,
|
|
3759
4278
|
PhoneField,
|
|
3760
4279
|
SUPPORTED_CURRENCIES,
|
|
3761
4280
|
TRACKING_PARAM_KEYS,
|
|
3762
4281
|
TRACKING_RANGES,
|
|
4282
|
+
bookingAttendeeSchema,
|
|
4283
|
+
bookingCancelSchema,
|
|
4284
|
+
bookingCreateSchema,
|
|
4285
|
+
bookingCustomerSchema,
|
|
4286
|
+
bookingLocationNullableSchema,
|
|
4287
|
+
bookingLocationSchema,
|
|
4288
|
+
bookingMetadataSchema,
|
|
4289
|
+
bookingReminderSchema,
|
|
4290
|
+
bookingRemindersSchema,
|
|
4291
|
+
bookingRescheduleSchema,
|
|
3763
4292
|
captureTrackingParamsFromLocation,
|
|
3764
4293
|
clearStashedUserData,
|
|
4294
|
+
computeSlots,
|
|
4295
|
+
createCalendarReadClient,
|
|
3765
4296
|
createSalesClient,
|
|
3766
4297
|
createTracking,
|
|
3767
4298
|
createTrackingClientContext,
|
|
3768
4299
|
createTrackingEventCreatePayload,
|
|
3769
4300
|
createTrackingSessionUpsertPayload,
|
|
4301
|
+
durationMinutes,
|
|
4302
|
+
endOfDayInTz,
|
|
3770
4303
|
fetchServices,
|
|
3771
4304
|
formatDateInTz,
|
|
3772
4305
|
formatMoney,
|
|
3773
4306
|
formatPhone,
|
|
3774
4307
|
formatPhoneAsTyped,
|
|
4308
|
+
formatSlotRange,
|
|
3775
4309
|
fromMinor,
|
|
3776
4310
|
getConsentChoice,
|
|
3777
4311
|
getConsentState,
|
|
3778
4312
|
getEventSemantics,
|
|
3779
4313
|
getTrackingConfigRuntime,
|
|
4314
|
+
groupSlotsByDay,
|
|
4315
|
+
instantFromWallClock,
|
|
4316
|
+
isCalendarError,
|
|
4317
|
+
localDateKey,
|
|
4318
|
+
offsetMinutesAt,
|
|
3780
4319
|
onConsentChange,
|
|
3781
4320
|
optIn,
|
|
3782
4321
|
optOut,
|
|
3783
4322
|
parsePhone,
|
|
3784
4323
|
phoneField,
|
|
3785
4324
|
resetConsent,
|
|
4325
|
+
resolveBrowserTimeZone,
|
|
3786
4326
|
resolveConversionConfig,
|
|
3787
4327
|
saleCreateSchema,
|
|
3788
4328
|
saleItemSchema,
|
|
@@ -3790,15 +4330,20 @@ function createTracking(options) {
|
|
|
3790
4330
|
saleUpdateSchema,
|
|
3791
4331
|
salesRequest,
|
|
3792
4332
|
setConsentState,
|
|
4333
|
+
startOfDayInTz,
|
|
3793
4334
|
stashUserData,
|
|
3794
4335
|
toE164,
|
|
3795
4336
|
toMinor,
|
|
4337
|
+
useBookingForm,
|
|
4338
|
+
useCalendarBusy,
|
|
4339
|
+
useCalendarClient,
|
|
3796
4340
|
useConsent,
|
|
3797
4341
|
useConsentState,
|
|
3798
4342
|
useCookiePreferences,
|
|
3799
4343
|
useGclid,
|
|
3800
4344
|
usePhoneConfig,
|
|
3801
4345
|
usePhoneField,
|
|
4346
|
+
useSlots,
|
|
3802
4347
|
useTrackingParams
|
|
3803
4348
|
});
|
|
3804
4349
|
//# sourceMappingURL=index.js.map
|