@aranova/tracking-next 0.20.2 → 0.21.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/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 +517 -0
- package/dist/calendar.js.map +1 -0
- package/dist/calendar.mjs +457 -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 +60 -3
- package/dist/index.d.ts +60 -3
- package/dist/index.js +511 -18
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +474 -18
- package/dist/index.mjs.map +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-B3BnYncU.d.mts} +5 -44
- package/dist/{sales-DrH6dY5F.d.ts → sales-CDjXRdmd.d.ts} +5 -44
- package/dist/sales.d.mts +3 -1
- package/dist/sales.d.ts +3 -1
- package/dist/sales.js +22 -17
- package/dist/sales.js.map +1 -1
- package/dist/sales.mjs +22 -17
- package/dist/sales.mjs.map +1 -1
- package/dist/transport-Bku8zftU.d.mts +721 -0
- package/dist/transport-DsOY6kcW.d.ts +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);
|
|
@@ -1033,6 +1070,21 @@ function automaticThresholdMet(goal, eventType, metadata) {
|
|
|
1033
1070
|
}
|
|
1034
1071
|
}
|
|
1035
1072
|
|
|
1073
|
+
// ../tracking-core/src/resources/intl/date.ts
|
|
1074
|
+
function formatDateInTz(iso, timeZone, opts, locale) {
|
|
1075
|
+
const date = new Date(iso);
|
|
1076
|
+
if (Number.isNaN(date.getTime())) return iso;
|
|
1077
|
+
return new Intl.DateTimeFormat(locale, {
|
|
1078
|
+
year: "numeric",
|
|
1079
|
+
month: "short",
|
|
1080
|
+
day: "2-digit",
|
|
1081
|
+
hour: "2-digit",
|
|
1082
|
+
minute: "2-digit",
|
|
1083
|
+
...opts,
|
|
1084
|
+
timeZone
|
|
1085
|
+
}).format(date);
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1036
1088
|
// ../tracking-core/src/resources/sales/money.ts
|
|
1037
1089
|
var MINOR_UNIT_EXPONENT = {
|
|
1038
1090
|
USD: 2,
|
|
@@ -1052,19 +1104,6 @@ function formatMoney(cents, currency, locale) {
|
|
|
1052
1104
|
fromMinor(cents, currency)
|
|
1053
1105
|
);
|
|
1054
1106
|
}
|
|
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
1107
|
|
|
1069
1108
|
// ../tracking-core/src/resources/tracking-config-runtime.ts
|
|
1070
1109
|
var CACHE_PREFIX2 = "_aranova_cfg_runtime_";
|
|
@@ -2767,7 +2806,7 @@ function attachPhoneClickCapture(client, config) {
|
|
|
2767
2806
|
};
|
|
2768
2807
|
}
|
|
2769
2808
|
|
|
2770
|
-
// ../tracking-core/src/resources/
|
|
2809
|
+
// ../tracking-core/src/resources/http/errors.ts
|
|
2771
2810
|
var AranovaApiError = class extends Error {
|
|
2772
2811
|
constructor(message, options) {
|
|
2773
2812
|
super(message);
|
|
@@ -2778,7 +2817,7 @@ var AranovaApiError = class extends Error {
|
|
|
2778
2817
|
}
|
|
2779
2818
|
};
|
|
2780
2819
|
|
|
2781
|
-
// ../tracking-core/src/resources/
|
|
2820
|
+
// ../tracking-core/src/resources/http/request.ts
|
|
2782
2821
|
function identityHeaders(config) {
|
|
2783
2822
|
const headers = { [API_KEY_HEADER]: config.apiKey };
|
|
2784
2823
|
if (config.sdkVersion) headers[SDK_VERSION_HEADER] = config.sdkVersion;
|
|
@@ -2790,8 +2829,8 @@ function identityHeaders(config) {
|
|
|
2790
2829
|
function joinUrl(endpoint, path) {
|
|
2791
2830
|
return `${endpoint.replace(/\/$/, "")}${path}`;
|
|
2792
2831
|
}
|
|
2793
|
-
async function
|
|
2794
|
-
const headers = identityHeaders(config);
|
|
2832
|
+
async function apiRequest(config, method, path, body, extraHeaders) {
|
|
2833
|
+
const headers = { ...identityHeaders(config), ...extraHeaders };
|
|
2795
2834
|
if (body !== void 0) headers["Content-Type"] = "application/json";
|
|
2796
2835
|
const response = await fetch(joinUrl(config.endpoint, path), {
|
|
2797
2836
|
method,
|
|
@@ -2820,6 +2859,9 @@ async function salesRequest(config, method, path, body) {
|
|
|
2820
2859
|
return await response.json();
|
|
2821
2860
|
}
|
|
2822
2861
|
|
|
2862
|
+
// ../tracking-core/src/resources/sales/transport.ts
|
|
2863
|
+
var salesRequest = apiRequest;
|
|
2864
|
+
|
|
2823
2865
|
// ../tracking-core/src/resources/sales/client.ts
|
|
2824
2866
|
function fireRecordedConversions(firing, input, recorded, sale, currency) {
|
|
2825
2867
|
if (!firing) return;
|
|
@@ -3465,7 +3507,7 @@ function GoogleAdsTracking(props) {
|
|
|
3465
3507
|
var import_navigation3 = require("next/navigation");
|
|
3466
3508
|
|
|
3467
3509
|
// package.json
|
|
3468
|
-
var version = "0.
|
|
3510
|
+
var version = "0.21.0";
|
|
3469
3511
|
|
|
3470
3512
|
// src/factory.tsx
|
|
3471
3513
|
var import_react5 = require("react");
|
|
@@ -3746,43 +3788,489 @@ function createTracking(options) {
|
|
|
3746
3788
|
}
|
|
3747
3789
|
return { TrackingProvider, useTracking };
|
|
3748
3790
|
}
|
|
3791
|
+
|
|
3792
|
+
// ../tracking-core/src/resources/calendar/transport.ts
|
|
3793
|
+
async function calendarRequest(config, method, path, body) {
|
|
3794
|
+
return apiRequest(config, method, `/calendar${path}`, body);
|
|
3795
|
+
}
|
|
3796
|
+
|
|
3797
|
+
// ../tracking-core/src/resources/calendar/time.ts
|
|
3798
|
+
function resolveBrowserTimeZone() {
|
|
3799
|
+
try {
|
|
3800
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
|
|
3801
|
+
} catch {
|
|
3802
|
+
return "UTC";
|
|
3803
|
+
}
|
|
3804
|
+
}
|
|
3805
|
+
function partsInTz(date, timeZone) {
|
|
3806
|
+
const formatter = new Intl.DateTimeFormat("en-US", {
|
|
3807
|
+
timeZone,
|
|
3808
|
+
hour12: false,
|
|
3809
|
+
year: "numeric",
|
|
3810
|
+
month: "2-digit",
|
|
3811
|
+
day: "2-digit",
|
|
3812
|
+
hour: "2-digit",
|
|
3813
|
+
minute: "2-digit",
|
|
3814
|
+
second: "2-digit"
|
|
3815
|
+
});
|
|
3816
|
+
const out = {};
|
|
3817
|
+
for (const part of formatter.formatToParts(date)) {
|
|
3818
|
+
if (part.type !== "literal") out[part.type] = Number(part.value);
|
|
3819
|
+
}
|
|
3820
|
+
if (out.hour === 24) out.hour = 0;
|
|
3821
|
+
return out;
|
|
3822
|
+
}
|
|
3823
|
+
function offsetMinutesAt(date, timeZone) {
|
|
3824
|
+
const p = partsInTz(date, timeZone);
|
|
3825
|
+
const asUtc = Date.UTC(p.year, p.month - 1, p.day, p.hour, p.minute, p.second);
|
|
3826
|
+
return (asUtc - Math.floor(date.getTime() / 1e3) * 1e3) / 6e4;
|
|
3827
|
+
}
|
|
3828
|
+
function instantFromWallClock(timeZone, year, month, day, hour = 0, minute = 0) {
|
|
3829
|
+
const naive = Date.UTC(year, month - 1, day, hour, minute);
|
|
3830
|
+
const firstGuess = new Date(naive - offsetMinutesAt(new Date(naive), timeZone) * 6e4);
|
|
3831
|
+
const corrected = naive - offsetMinutesAt(firstGuess, timeZone) * 6e4;
|
|
3832
|
+
return new Date(corrected);
|
|
3833
|
+
}
|
|
3834
|
+
function localDateKey(iso, timeZone) {
|
|
3835
|
+
const p = partsInTz(new Date(iso), timeZone);
|
|
3836
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
3837
|
+
return `${p.year}-${pad(p.month)}-${pad(p.day)}`;
|
|
3838
|
+
}
|
|
3839
|
+
function startOfDayInTz(dateKey, timeZone) {
|
|
3840
|
+
const [year, month, day] = dateKey.split("-").map(Number);
|
|
3841
|
+
return instantFromWallClock(timeZone, year, month, day, 0, 0);
|
|
3842
|
+
}
|
|
3843
|
+
function endOfDayInTz(dateKey, timeZone) {
|
|
3844
|
+
const start = startOfDayInTz(dateKey, timeZone);
|
|
3845
|
+
const p = partsInTz(start, timeZone);
|
|
3846
|
+
return instantFromWallClock(timeZone, p.year, p.month, p.day + 1, 0, 0);
|
|
3847
|
+
}
|
|
3848
|
+
function durationMinutes(startIso, endIso) {
|
|
3849
|
+
return Math.round((new Date(endIso).getTime() - new Date(startIso).getTime()) / 6e4);
|
|
3850
|
+
}
|
|
3851
|
+
function formatSlotRange(startIso, endIso, timeZone, locale) {
|
|
3852
|
+
const opts = { hour: "2-digit", minute: "2-digit", timeZone };
|
|
3853
|
+
const fmt = new Intl.DateTimeFormat(locale, opts);
|
|
3854
|
+
return `${fmt.format(new Date(startIso))} \u2013 ${fmt.format(new Date(endIso))}`;
|
|
3855
|
+
}
|
|
3856
|
+
|
|
3857
|
+
// ../tracking-core/src/resources/calendar/read-client.ts
|
|
3858
|
+
function withBusiness(config, path) {
|
|
3859
|
+
if (!config.businessId) return path;
|
|
3860
|
+
const separator = path.includes("?") ? "&" : "?";
|
|
3861
|
+
return `${path}${separator}business_id=${encodeURIComponent(config.businessId)}`;
|
|
3862
|
+
}
|
|
3863
|
+
function createCalendarReadClient(config) {
|
|
3864
|
+
return {
|
|
3865
|
+
async listCalendars() {
|
|
3866
|
+
return calendarRequest(config, "GET", withBusiness(config, "/calendars"));
|
|
3867
|
+
},
|
|
3868
|
+
async busy(calendarKey, query) {
|
|
3869
|
+
const params = new URLSearchParams({
|
|
3870
|
+
since: query.since,
|
|
3871
|
+
until: query.until
|
|
3872
|
+
});
|
|
3873
|
+
const timeZone = query.timeZone ?? config.defaultTimeZone ?? resolveBrowserTimeZone();
|
|
3874
|
+
params.set("time_zone", timeZone);
|
|
3875
|
+
return calendarRequest(
|
|
3876
|
+
config,
|
|
3877
|
+
"GET",
|
|
3878
|
+
withBusiness(config, `/${encodeURIComponent(calendarKey)}/busy?${params.toString()}`)
|
|
3879
|
+
);
|
|
3880
|
+
}
|
|
3881
|
+
};
|
|
3882
|
+
}
|
|
3883
|
+
function isCalendarError(error, code) {
|
|
3884
|
+
if (!(error instanceof AranovaApiError)) return false;
|
|
3885
|
+
return code === void 0 || error.code === code;
|
|
3886
|
+
}
|
|
3887
|
+
|
|
3888
|
+
// ../tracking-core/src/resources/calendar/schema.ts
|
|
3889
|
+
var import_zod13 = require("zod");
|
|
3890
|
+
var CALENDAR_METADATA_SCHEMA_VERSION = 1;
|
|
3891
|
+
var MAX_ATTENDEES = 20;
|
|
3892
|
+
var MAX_REMINDER_OVERRIDES = 5;
|
|
3893
|
+
var MAX_REMINDER_MINUTES = 40320;
|
|
3894
|
+
var MAX_BOOKING_MINUTES = 1440;
|
|
3895
|
+
var BOOKING_SOURCES = ["website", "phone", "walk_in", "import", "operator"];
|
|
3896
|
+
var BOOKING_STATUSES = ["pending", "confirmed", "cancelled", "no_show"];
|
|
3897
|
+
var GOOGLE_SYNC_STATES = ["queued", "synced", "uncertain", "failed", "drifted"];
|
|
3898
|
+
var CALENDAR_SYNC_STATUSES = [
|
|
3899
|
+
"pending_invite",
|
|
3900
|
+
"awaiting_calendar_selection",
|
|
3901
|
+
"connected",
|
|
3902
|
+
"needs_reconnect",
|
|
3903
|
+
"revoked",
|
|
3904
|
+
"disabled"
|
|
3905
|
+
];
|
|
3906
|
+
var CALENDAR_ERROR_CODES = [
|
|
3907
|
+
"slot_unavailable",
|
|
3908
|
+
"calendar_not_connected",
|
|
3909
|
+
"calendar_disconnected",
|
|
3910
|
+
"booking_not_found",
|
|
3911
|
+
"outside_booking_window",
|
|
3912
|
+
"rate_limited",
|
|
3913
|
+
"google_error"
|
|
3914
|
+
];
|
|
3915
|
+
var isoInstant = import_zod13.z.string().datetime({ offset: true });
|
|
3916
|
+
function isKnownTimeZone(timeZone) {
|
|
3917
|
+
try {
|
|
3918
|
+
new Intl.DateTimeFormat(void 0, { timeZone });
|
|
3919
|
+
return true;
|
|
3920
|
+
} catch {
|
|
3921
|
+
return false;
|
|
3922
|
+
}
|
|
3923
|
+
}
|
|
3924
|
+
var ianaTz = import_zod13.z.string().min(1).max(64).regex(/^[A-Za-z0-9_+\-/]+$/).refine(isKnownTimeZone, { message: "unknown IANA time zone" });
|
|
3925
|
+
var bookingAttendeeSchema = import_zod13.z.object({
|
|
3926
|
+
email: import_zod13.z.string().max(320).email(),
|
|
3927
|
+
display_name: import_zod13.z.string().max(200).nullable().optional(),
|
|
3928
|
+
optional: import_zod13.z.boolean().default(false)
|
|
3929
|
+
}).strict();
|
|
3930
|
+
var bookingReminderSchema = import_zod13.z.object({
|
|
3931
|
+
method: import_zod13.z.enum(["email", "popup"]),
|
|
3932
|
+
minutes_before: import_zod13.z.number().int().min(0).max(MAX_REMINDER_MINUTES)
|
|
3933
|
+
}).strict();
|
|
3934
|
+
var bookingRemindersSchema = import_zod13.z.object({
|
|
3935
|
+
use_calendar_defaults: import_zod13.z.boolean().default(true),
|
|
3936
|
+
overrides: import_zod13.z.array(bookingReminderSchema).max(MAX_REMINDER_OVERRIDES).default([])
|
|
3937
|
+
}).strict();
|
|
3938
|
+
var bookingLocationSchema = import_zod13.z.union([
|
|
3939
|
+
import_zod13.z.object({ kind: import_zod13.z.literal("google_meet") }).strict(),
|
|
3940
|
+
import_zod13.z.object({ kind: import_zod13.z.literal("physical"), address: import_zod13.z.string().max(1024) }).strict(),
|
|
3941
|
+
import_zod13.z.object({ kind: import_zod13.z.literal("phone"), phone: import_zod13.z.string().max(64) }).strict(),
|
|
3942
|
+
import_zod13.z.object({ kind: import_zod13.z.literal("custom"), text: import_zod13.z.string().max(1024) }).strict()
|
|
3943
|
+
]);
|
|
3944
|
+
var bookingLocationNullableSchema = import_zod13.z.union([...bookingLocationSchema.options, import_zod13.z.null()]);
|
|
3945
|
+
var bookingCustomerSchema = import_zod13.z.object({
|
|
3946
|
+
// Required: Google needs an address to send the invite that confirms the
|
|
3947
|
+
// booking, and that invite is the whole confirmation mechanism.
|
|
3948
|
+
email: import_zod13.z.string().max(320).email(),
|
|
3949
|
+
name: import_zod13.z.string().max(200).nullable().optional(),
|
|
3950
|
+
phone: import_zod13.z.string().max(64).nullable().optional(),
|
|
3951
|
+
sms_consent: import_zod13.z.boolean().default(false)
|
|
3952
|
+
}).strict();
|
|
3953
|
+
var jsonScalar = import_zod13.z.union([import_zod13.z.string(), import_zod13.z.number(), import_zod13.z.boolean(), import_zod13.z.null()]);
|
|
3954
|
+
var bookingMetadataSchema = import_zod13.z.object({
|
|
3955
|
+
schema_version: import_zod13.z.number().int().default(CALENDAR_METADATA_SCHEMA_VERSION),
|
|
3956
|
+
source: import_zod13.z.enum(BOOKING_SOURCES).nullable().optional(),
|
|
3957
|
+
service: import_zod13.z.string().max(64).nullable().optional(),
|
|
3958
|
+
visitor_id: import_zod13.z.string().max(64).nullable().optional(),
|
|
3959
|
+
session_id: import_zod13.z.string().max(64).nullable().optional(),
|
|
3960
|
+
gclid: import_zod13.z.string().max(256).nullable().optional(),
|
|
3961
|
+
fbclid: import_zod13.z.string().max(256).nullable().optional(),
|
|
3962
|
+
utm_source: import_zod13.z.string().max(128).nullable().optional(),
|
|
3963
|
+
utm_medium: import_zod13.z.string().max(128).nullable().optional(),
|
|
3964
|
+
utm_campaign: import_zod13.z.string().max(128).nullable().optional(),
|
|
3965
|
+
utm_term: import_zod13.z.string().max(128).nullable().optional(),
|
|
3966
|
+
utm_content: import_zod13.z.string().max(128).nullable().optional(),
|
|
3967
|
+
landing_page: import_zod13.z.string().max(2048).nullable().optional(),
|
|
3968
|
+
referrer: import_zod13.z.string().max(2048).nullable().optional(),
|
|
3969
|
+
notes: import_zod13.z.string().max(2e3).nullable().optional(),
|
|
3970
|
+
custom: import_zod13.z.record(jsonScalar).nullable().optional()
|
|
3971
|
+
}).strict();
|
|
3972
|
+
function refineEndXor(value, ctx) {
|
|
3973
|
+
const hasEnd = value.end_at !== void 0 && value.end_at !== null;
|
|
3974
|
+
const hasDuration = value.duration_minutes !== void 0 && value.duration_minutes !== null;
|
|
3975
|
+
if (hasEnd === hasDuration) {
|
|
3976
|
+
ctx.addIssue({
|
|
3977
|
+
code: import_zod13.z.ZodIssueCode.custom,
|
|
3978
|
+
message: "provide exactly one of end_at or duration_minutes",
|
|
3979
|
+
path: ["end_at"]
|
|
3980
|
+
});
|
|
3981
|
+
return;
|
|
3982
|
+
}
|
|
3983
|
+
if (hasEnd && new Date(value.end_at) <= new Date(value.start_at)) {
|
|
3984
|
+
ctx.addIssue({
|
|
3985
|
+
code: import_zod13.z.ZodIssueCode.custom,
|
|
3986
|
+
message: "end_at must be after start_at",
|
|
3987
|
+
path: ["end_at"]
|
|
3988
|
+
});
|
|
3989
|
+
}
|
|
3990
|
+
}
|
|
3991
|
+
var bookingCreateSchema = import_zod13.z.object({
|
|
3992
|
+
calendar_key: import_zod13.z.string().min(1).max(64),
|
|
3993
|
+
// Free-form: appointment types are the client site's own vocabulary, not
|
|
3994
|
+
// configuration the dashboard holds.
|
|
3995
|
+
appointment_type: import_zod13.z.string().max(64).nullable().optional(),
|
|
3996
|
+
start_at: isoInstant,
|
|
3997
|
+
end_at: isoInstant.nullable().optional(),
|
|
3998
|
+
duration_minutes: import_zod13.z.number().int().positive().max(MAX_BOOKING_MINUTES).nullable().optional(),
|
|
3999
|
+
/** The booker's zone — distinct from the business's and the calendar's. */
|
|
4000
|
+
time_zone: ianaTz,
|
|
4001
|
+
title: import_zod13.z.string().max(300).nullable().optional(),
|
|
4002
|
+
description: import_zod13.z.string().max(8e3).nullable().optional(),
|
|
4003
|
+
location: bookingLocationNullableSchema.optional(),
|
|
4004
|
+
customer: bookingCustomerSchema,
|
|
4005
|
+
attendees: import_zod13.z.array(bookingAttendeeSchema).max(MAX_ATTENDEES).default([]),
|
|
4006
|
+
send_invites: import_zod13.z.boolean().default(true),
|
|
4007
|
+
reminders: bookingRemindersSchema.nullable().optional(),
|
|
4008
|
+
metadata: bookingMetadataSchema.nullable().optional(),
|
|
4009
|
+
idempotency_key: import_zod13.z.string().max(128).nullable().optional(),
|
|
4010
|
+
buffer_before_minutes: import_zod13.z.number().int().min(0).max(MAX_BOOKING_MINUTES).default(0),
|
|
4011
|
+
buffer_after_minutes: import_zod13.z.number().int().min(0).max(MAX_BOOKING_MINUTES).default(0)
|
|
4012
|
+
}).strict().superRefine(refineEndXor);
|
|
4013
|
+
var bookingRescheduleSchema = import_zod13.z.object({
|
|
4014
|
+
start_at: isoInstant,
|
|
4015
|
+
end_at: isoInstant.nullable().optional(),
|
|
4016
|
+
duration_minutes: import_zod13.z.number().int().positive().max(MAX_BOOKING_MINUTES).nullable().optional(),
|
|
4017
|
+
time_zone: ianaTz,
|
|
4018
|
+
notify_attendees: import_zod13.z.boolean().default(true),
|
|
4019
|
+
reason: import_zod13.z.string().max(500).nullable().optional()
|
|
4020
|
+
}).strict().superRefine(refineEndXor);
|
|
4021
|
+
var bookingCancelSchema = import_zod13.z.object({
|
|
4022
|
+
reason: import_zod13.z.string().max(500).nullable().optional(),
|
|
4023
|
+
notify_attendees: import_zod13.z.boolean().default(true)
|
|
4024
|
+
}).strict();
|
|
4025
|
+
|
|
4026
|
+
// ../tracking-core/src/resources/calendar/slots.ts
|
|
4027
|
+
function parseHhMm(value) {
|
|
4028
|
+
const [hour, minute] = value.split(":").map(Number);
|
|
4029
|
+
return [hour || 0, minute || 0];
|
|
4030
|
+
}
|
|
4031
|
+
function dateKeyOf(date, timeZone) {
|
|
4032
|
+
const fmt = new Intl.DateTimeFormat("en-CA", {
|
|
4033
|
+
timeZone,
|
|
4034
|
+
year: "numeric",
|
|
4035
|
+
month: "2-digit",
|
|
4036
|
+
day: "2-digit"
|
|
4037
|
+
});
|
|
4038
|
+
return fmt.format(date);
|
|
4039
|
+
}
|
|
4040
|
+
function weekdayFromDateKey(dateKey) {
|
|
4041
|
+
const [year, month, day] = dateKey.split("-").map(Number);
|
|
4042
|
+
return new Date(Date.UTC(year, month - 1, day, 12)).getUTCDay();
|
|
4043
|
+
}
|
|
4044
|
+
function startOfLocalDay(at, timeZone) {
|
|
4045
|
+
const [year, month, day] = dateKeyOf(at, timeZone).split("-").map(Number);
|
|
4046
|
+
return instantFromWallClock(timeZone, year, month, day, 12, 0);
|
|
4047
|
+
}
|
|
4048
|
+
function overlaps(aStart, aEnd, bStart, bEnd) {
|
|
4049
|
+
return aStart < bEnd && aEnd > bStart;
|
|
4050
|
+
}
|
|
4051
|
+
function computeSlots(options) {
|
|
4052
|
+
const {
|
|
4053
|
+
busy,
|
|
4054
|
+
openingHours,
|
|
4055
|
+
timeZone,
|
|
4056
|
+
durationMinutes: durationMinutes2,
|
|
4057
|
+
granularityMinutes = 15,
|
|
4058
|
+
minNoticeMinutes = 0,
|
|
4059
|
+
bufferBeforeMinutes = 0,
|
|
4060
|
+
bufferAfterMinutes = 0,
|
|
4061
|
+
windowDays = 30,
|
|
4062
|
+
now = /* @__PURE__ */ new Date()
|
|
4063
|
+
} = options;
|
|
4064
|
+
const earliest = now.getTime() + minNoticeMinutes * 6e4;
|
|
4065
|
+
const busyRanges = busy.map((interval) => [
|
|
4066
|
+
new Date(interval.start_at).getTime(),
|
|
4067
|
+
new Date(interval.end_at).getTime()
|
|
4068
|
+
]);
|
|
4069
|
+
const slots = [];
|
|
4070
|
+
let cursor = startOfLocalDay(now, timeZone);
|
|
4071
|
+
for (let dayOffset = 0; dayOffset < windowDays; dayOffset += 1) {
|
|
4072
|
+
const dateKey = dateKeyOf(cursor, timeZone);
|
|
4073
|
+
const [year, month, day] = dateKey.split("-").map(Number);
|
|
4074
|
+
cursor = instantFromWallClock(timeZone, year, month, day + 1, 12, 0);
|
|
4075
|
+
if (openingHours.closedDates?.includes(dateKey)) continue;
|
|
4076
|
+
const intervals = openingHours.overrides?.[dateKey] ?? openingHours.weekly[weekdayFromDateKey(dateKey)] ?? [];
|
|
4077
|
+
for (const interval of intervals) {
|
|
4078
|
+
const [openHour, openMinute] = parseHhMm(interval.start);
|
|
4079
|
+
const [closeHour, closeMinute] = parseHhMm(interval.end);
|
|
4080
|
+
const opensAt = instantFromWallClock(timeZone, year, month, day, openHour, openMinute);
|
|
4081
|
+
const closesAt = instantFromWallClock(timeZone, year, month, day, closeHour, closeMinute);
|
|
4082
|
+
for (let start = opensAt.getTime(); start + durationMinutes2 * 6e4 <= closesAt.getTime(); start += granularityMinutes * 6e4) {
|
|
4083
|
+
const end = start + durationMinutes2 * 6e4;
|
|
4084
|
+
if (start < earliest) continue;
|
|
4085
|
+
const blockedStart = start - bufferBeforeMinutes * 6e4;
|
|
4086
|
+
const blockedEnd = end + bufferAfterMinutes * 6e4;
|
|
4087
|
+
const taken = busyRanges.some(
|
|
4088
|
+
([busyStart, busyEnd]) => overlaps(blockedStart, blockedEnd, busyStart, busyEnd)
|
|
4089
|
+
);
|
|
4090
|
+
if (taken) continue;
|
|
4091
|
+
slots.push({
|
|
4092
|
+
start_at: new Date(start).toISOString(),
|
|
4093
|
+
end_at: new Date(end).toISOString()
|
|
4094
|
+
});
|
|
4095
|
+
}
|
|
4096
|
+
}
|
|
4097
|
+
}
|
|
4098
|
+
slots.sort((a, b) => a.start_at.localeCompare(b.start_at));
|
|
4099
|
+
return { slots, nextAvailableAt: slots[0]?.start_at ?? null };
|
|
4100
|
+
}
|
|
4101
|
+
function groupSlotsByDay(slots, timeZone) {
|
|
4102
|
+
const byDay = /* @__PURE__ */ new Map();
|
|
4103
|
+
for (const slot of slots) {
|
|
4104
|
+
const key = dateKeyOf(new Date(slot.start_at), timeZone);
|
|
4105
|
+
const bucket = byDay.get(key);
|
|
4106
|
+
if (bucket) bucket.push(slot);
|
|
4107
|
+
else byDay.set(key, [slot]);
|
|
4108
|
+
}
|
|
4109
|
+
return [...byDay.entries()].map(([date, daySlots]) => ({ date, slots: daySlots })).sort((a, b) => a.date.localeCompare(b.date));
|
|
4110
|
+
}
|
|
4111
|
+
|
|
4112
|
+
// ../tracking-core/src/calendar-react.tsx
|
|
4113
|
+
var import_react6 = require("react");
|
|
4114
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
4115
|
+
var _calendarClientContext;
|
|
4116
|
+
function calendarClientContext() {
|
|
4117
|
+
return _calendarClientContext ?? (_calendarClientContext = (0, import_react6.createContext)(null));
|
|
4118
|
+
}
|
|
4119
|
+
function CalendarClientProvider({
|
|
4120
|
+
value,
|
|
4121
|
+
children
|
|
4122
|
+
}) {
|
|
4123
|
+
const Ctx = calendarClientContext();
|
|
4124
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Ctx.Provider, { value, children });
|
|
4125
|
+
}
|
|
4126
|
+
function useCalendarClient() {
|
|
4127
|
+
const client = (0, import_react6.useContext)(calendarClientContext());
|
|
4128
|
+
if (!client) {
|
|
4129
|
+
throw new Error(
|
|
4130
|
+
"useCalendarClient requires <CalendarClientProvider>. Wire it via createTracking({ calendar })."
|
|
4131
|
+
);
|
|
4132
|
+
}
|
|
4133
|
+
return client;
|
|
4134
|
+
}
|
|
4135
|
+
function useCalendarBusy(calendarKey, window2) {
|
|
4136
|
+
const client = useCalendarClient();
|
|
4137
|
+
const [busy, setBusy] = (0, import_react6.useState)([]);
|
|
4138
|
+
const [timeZone, setTimeZone] = (0, import_react6.useState)(resolveBrowserTimeZone());
|
|
4139
|
+
const [isLoading, setIsLoading] = (0, import_react6.useState)(true);
|
|
4140
|
+
const [error, setError] = (0, import_react6.useState)(null);
|
|
4141
|
+
const [nonce, setNonce] = (0, import_react6.useState)(0);
|
|
4142
|
+
(0, import_react6.useEffect)(() => {
|
|
4143
|
+
const controller = new AbortController();
|
|
4144
|
+
setIsLoading(true);
|
|
4145
|
+
client.busy(calendarKey, { since: window2.since, until: window2.until }).then((response) => {
|
|
4146
|
+
if (controller.signal.aborted) return;
|
|
4147
|
+
setBusy(response.busy);
|
|
4148
|
+
setTimeZone(response.time_zone);
|
|
4149
|
+
setError(null);
|
|
4150
|
+
}).catch((cause) => {
|
|
4151
|
+
if (controller.signal.aborted) return;
|
|
4152
|
+
setError(cause instanceof Error ? cause : new Error(String(cause)));
|
|
4153
|
+
}).finally(() => {
|
|
4154
|
+
if (!controller.signal.aborted) setIsLoading(false);
|
|
4155
|
+
});
|
|
4156
|
+
return () => controller.abort();
|
|
4157
|
+
}, [client, calendarKey, window2.since, window2.until, nonce]);
|
|
4158
|
+
const refetch = (0, import_react6.useCallback)(() => setNonce((value) => value + 1), []);
|
|
4159
|
+
return { busy, timeZone, isLoading, error, refetch };
|
|
4160
|
+
}
|
|
4161
|
+
function useSlots(busy, timeZone, options) {
|
|
4162
|
+
const zone = options.timeZone ?? timeZone;
|
|
4163
|
+
return (0, import_react6.useMemo)(() => {
|
|
4164
|
+
const { slots, nextAvailableAt } = computeSlots({ ...options, busy, timeZone: zone });
|
|
4165
|
+
return { slots, days: groupSlotsByDay(slots, zone), nextAvailableAt };
|
|
4166
|
+
}, [busy, zone, options]);
|
|
4167
|
+
}
|
|
4168
|
+
function useBookingForm(options = {}) {
|
|
4169
|
+
const endpoint = options.endpoint ?? "/api/aranova/calendar/bookings";
|
|
4170
|
+
const [status, setStatus] = (0, import_react6.useState)("idle");
|
|
4171
|
+
const [error, setError] = (0, import_react6.useState)(null);
|
|
4172
|
+
const [booking, setBooking] = (0, import_react6.useState)(null);
|
|
4173
|
+
const submit = (0, import_react6.useCallback)(
|
|
4174
|
+
async (input) => {
|
|
4175
|
+
setStatus("submitting");
|
|
4176
|
+
setError(null);
|
|
4177
|
+
try {
|
|
4178
|
+
const response = await fetch(endpoint, {
|
|
4179
|
+
method: "POST",
|
|
4180
|
+
headers: { "Content-Type": "application/json" },
|
|
4181
|
+
body: JSON.stringify(input)
|
|
4182
|
+
});
|
|
4183
|
+
const body = await response.json().catch(() => null);
|
|
4184
|
+
if (!response.ok) {
|
|
4185
|
+
const detail = body && typeof body === "object" && typeof body.detail === "string" ? body.detail : "Booking failed";
|
|
4186
|
+
throw new Error(detail);
|
|
4187
|
+
}
|
|
4188
|
+
setBooking(body);
|
|
4189
|
+
setStatus("confirmed");
|
|
4190
|
+
options.onConfirmed?.(body);
|
|
4191
|
+
} catch (cause) {
|
|
4192
|
+
setError(cause instanceof Error ? cause : new Error(String(cause)));
|
|
4193
|
+
setStatus("failed");
|
|
4194
|
+
}
|
|
4195
|
+
},
|
|
4196
|
+
[endpoint, options]
|
|
4197
|
+
);
|
|
4198
|
+
const reset = (0, import_react6.useCallback)(() => {
|
|
4199
|
+
setStatus("idle");
|
|
4200
|
+
setError(null);
|
|
4201
|
+
setBooking(null);
|
|
4202
|
+
}, []);
|
|
4203
|
+
return { status, error, booking, submit, reset };
|
|
4204
|
+
}
|
|
3749
4205
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3750
4206
|
0 && (module.exports = {
|
|
3751
4207
|
AdPlatformTracking,
|
|
3752
4208
|
AranovaApiError,
|
|
4209
|
+
BOOKING_SOURCES,
|
|
4210
|
+
BOOKING_STATUSES,
|
|
4211
|
+
CALENDAR_ERROR_CODES,
|
|
4212
|
+
CALENDAR_METADATA_SCHEMA_VERSION,
|
|
4213
|
+
CALENDAR_SYNC_STATUSES,
|
|
4214
|
+
CalendarClientProvider,
|
|
3753
4215
|
ConsentBanner,
|
|
3754
4216
|
DEFAULT_DECLINE_TTL_DAYS,
|
|
3755
4217
|
DEFAULT_PHONE_COUNTRY,
|
|
3756
4218
|
EVENT_SEMANTICS,
|
|
4219
|
+
GOOGLE_SYNC_STATES,
|
|
3757
4220
|
GoogleAdsTracking,
|
|
4221
|
+
MAX_ATTENDEES,
|
|
4222
|
+
MAX_BOOKING_MINUTES,
|
|
4223
|
+
MAX_REMINDER_MINUTES,
|
|
4224
|
+
MAX_REMINDER_OVERRIDES,
|
|
3758
4225
|
NAMED_RANGES,
|
|
3759
4226
|
PhoneField,
|
|
3760
4227
|
SUPPORTED_CURRENCIES,
|
|
3761
4228
|
TRACKING_PARAM_KEYS,
|
|
3762
4229
|
TRACKING_RANGES,
|
|
4230
|
+
bookingAttendeeSchema,
|
|
4231
|
+
bookingCancelSchema,
|
|
4232
|
+
bookingCreateSchema,
|
|
4233
|
+
bookingCustomerSchema,
|
|
4234
|
+
bookingLocationNullableSchema,
|
|
4235
|
+
bookingLocationSchema,
|
|
4236
|
+
bookingMetadataSchema,
|
|
4237
|
+
bookingReminderSchema,
|
|
4238
|
+
bookingRemindersSchema,
|
|
4239
|
+
bookingRescheduleSchema,
|
|
3763
4240
|
captureTrackingParamsFromLocation,
|
|
3764
4241
|
clearStashedUserData,
|
|
4242
|
+
computeSlots,
|
|
4243
|
+
createCalendarReadClient,
|
|
3765
4244
|
createSalesClient,
|
|
3766
4245
|
createTracking,
|
|
3767
4246
|
createTrackingClientContext,
|
|
3768
4247
|
createTrackingEventCreatePayload,
|
|
3769
4248
|
createTrackingSessionUpsertPayload,
|
|
4249
|
+
durationMinutes,
|
|
4250
|
+
endOfDayInTz,
|
|
3770
4251
|
fetchServices,
|
|
3771
4252
|
formatDateInTz,
|
|
3772
4253
|
formatMoney,
|
|
3773
4254
|
formatPhone,
|
|
3774
4255
|
formatPhoneAsTyped,
|
|
4256
|
+
formatSlotRange,
|
|
3775
4257
|
fromMinor,
|
|
3776
4258
|
getConsentChoice,
|
|
3777
4259
|
getConsentState,
|
|
3778
4260
|
getEventSemantics,
|
|
3779
4261
|
getTrackingConfigRuntime,
|
|
4262
|
+
groupSlotsByDay,
|
|
4263
|
+
instantFromWallClock,
|
|
4264
|
+
isCalendarError,
|
|
4265
|
+
localDateKey,
|
|
4266
|
+
offsetMinutesAt,
|
|
3780
4267
|
onConsentChange,
|
|
3781
4268
|
optIn,
|
|
3782
4269
|
optOut,
|
|
3783
4270
|
parsePhone,
|
|
3784
4271
|
phoneField,
|
|
3785
4272
|
resetConsent,
|
|
4273
|
+
resolveBrowserTimeZone,
|
|
3786
4274
|
resolveConversionConfig,
|
|
3787
4275
|
saleCreateSchema,
|
|
3788
4276
|
saleItemSchema,
|
|
@@ -3790,15 +4278,20 @@ function createTracking(options) {
|
|
|
3790
4278
|
saleUpdateSchema,
|
|
3791
4279
|
salesRequest,
|
|
3792
4280
|
setConsentState,
|
|
4281
|
+
startOfDayInTz,
|
|
3793
4282
|
stashUserData,
|
|
3794
4283
|
toE164,
|
|
3795
4284
|
toMinor,
|
|
4285
|
+
useBookingForm,
|
|
4286
|
+
useCalendarBusy,
|
|
4287
|
+
useCalendarClient,
|
|
3796
4288
|
useConsent,
|
|
3797
4289
|
useConsentState,
|
|
3798
4290
|
useCookiePreferences,
|
|
3799
4291
|
useGclid,
|
|
3800
4292
|
usePhoneConfig,
|
|
3801
4293
|
usePhoneField,
|
|
4294
|
+
useSlots,
|
|
3802
4295
|
useTrackingParams
|
|
3803
4296
|
});
|
|
3804
4297
|
//# sourceMappingURL=index.js.map
|