@aranova/tracking-react 1.2.5 → 1.3.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 +70 -0
- package/dist/{tracking-config-runtime-C6H7ofmo.d.mts → bookings-CqdjLMkv.d.ts} +144 -1
- package/dist/{tracking-config-runtime-C6H7ofmo.d.ts → bookings-VsQdopTt.d.mts} +144 -1
- package/dist/client.d.mts +56 -5
- package/dist/client.d.ts +56 -5
- package/dist/client.js +281 -11
- package/dist/client.js.map +1 -1
- package/dist/client.mjs +276 -11
- package/dist/client.mjs.map +1 -1
- package/dist/form-submit-BLb28aCk.d.mts +75 -0
- package/dist/form-submit-BLb28aCk.d.ts +75 -0
- package/dist/index.d.mts +7 -6
- package/dist/index.d.ts +7 -6
- package/dist/index.js +429 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +424 -4
- package/dist/index.mjs.map +1 -1
- package/dist/{ingest-typed-oAwnKqH2.d.mts → ingest-typed-BCUv93ax.d.mts} +78 -2
- package/dist/{ingest-typed-CUpdCtmM.d.ts → ingest-typed-DGqzbteM.d.ts} +78 -2
- package/dist/{phone-utils-qLfVpQI7.d.mts → phone-utils-CM8eUPz8.d.mts} +2 -74
- package/dist/{phone-utils-qLfVpQI7.d.ts → phone-utils-l8ey3Zdm.d.ts} +2 -74
- package/dist/phone.d.mts +2 -1
- package/dist/phone.d.ts +2 -1
- package/dist/{sales-C3O_xxZ_.d.ts → sales-DSL6vMuY.d.mts} +23 -2
- package/dist/{sales-BuKD_bdo.d.mts → sales-_F3nnI2r.d.ts} +23 -2
- package/dist/sales.d.mts +3 -2
- package/dist/sales.d.ts +3 -2
- package/dist/sales.js +307 -9
- package/dist/sales.js.map +1 -1
- package/dist/sales.mjs +305 -9
- package/dist/sales.mjs.map +1 -1
- package/package.json +1 -1
package/dist/client.mjs
CHANGED
|
@@ -243,6 +243,8 @@ var TRACKING_CAPABILITIES = [
|
|
|
243
243
|
"ad_tags_meta",
|
|
244
244
|
"base_tracking",
|
|
245
245
|
"blog_rendering",
|
|
246
|
+
"booking_handoff",
|
|
247
|
+
"booking_integration",
|
|
246
248
|
"calendar_read",
|
|
247
249
|
"calendar_write",
|
|
248
250
|
"consent_controls",
|
|
@@ -645,15 +647,23 @@ function buildLandingPayloadFields(sessionId, override) {
|
|
|
645
647
|
};
|
|
646
648
|
}
|
|
647
649
|
|
|
650
|
+
// ../tracking-core/src/uuid.ts
|
|
651
|
+
function uuidV4() {
|
|
652
|
+
const cryptoApi = globalThis.crypto;
|
|
653
|
+
if (typeof cryptoApi?.randomUUID === "function") return cryptoApi.randomUUID();
|
|
654
|
+
const bytes = new Uint8Array(16);
|
|
655
|
+
if (typeof cryptoApi?.getRandomValues === "function") cryptoApi.getRandomValues(bytes);
|
|
656
|
+
else for (let i = 0; i < 16; i += 1) bytes[i] = Math.floor(Math.random() * 256);
|
|
657
|
+
bytes[6] = bytes[6] & 15 | 64;
|
|
658
|
+
bytes[8] = bytes[8] & 63 | 128;
|
|
659
|
+
const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
660
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
661
|
+
}
|
|
662
|
+
|
|
648
663
|
// ../tracking-core/src/session.ts
|
|
649
664
|
var VISITOR_STORAGE_KEY = "aranova_tracking_visitor";
|
|
650
665
|
var SESSION_STORAGE_KEY = "aranova_tracking_session";
|
|
651
666
|
var SESSION_IDLE_MS = 30 * 60 * 1e3;
|
|
652
|
-
function safeUuid() {
|
|
653
|
-
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function")
|
|
654
|
-
return crypto.randomUUID();
|
|
655
|
-
return `${Date.now().toString(16)}-${Math.random().toString(16).slice(2)}-${Math.random().toString(16).slice(2)}`;
|
|
656
|
-
}
|
|
657
667
|
function readLocalStorage(key) {
|
|
658
668
|
try {
|
|
659
669
|
return window.localStorage.getItem(key);
|
|
@@ -668,10 +678,10 @@ function writeLocalStorage(key, value) {
|
|
|
668
678
|
}
|
|
669
679
|
}
|
|
670
680
|
function getVisitorId() {
|
|
671
|
-
if (typeof window === "undefined") return
|
|
681
|
+
if (typeof window === "undefined") return uuidV4();
|
|
672
682
|
const existing = readLocalStorage(VISITOR_STORAGE_KEY);
|
|
673
683
|
if (existing && existing.length > 0) return existing;
|
|
674
|
-
const fresh =
|
|
684
|
+
const fresh = uuidV4();
|
|
675
685
|
writeLocalStorage(VISITOR_STORAGE_KEY, fresh);
|
|
676
686
|
return fresh;
|
|
677
687
|
}
|
|
@@ -683,7 +693,7 @@ function adoptVisitorId(visitorId) {
|
|
|
683
693
|
return readLocalStorage(VISITOR_STORAGE_KEY) === visitorId;
|
|
684
694
|
}
|
|
685
695
|
function getOrRotateSessionId(now = Date.now()) {
|
|
686
|
-
if (typeof window === "undefined") return { id:
|
|
696
|
+
if (typeof window === "undefined") return { id: uuidV4(), isNew: true };
|
|
687
697
|
const raw = readLocalStorage(SESSION_STORAGE_KEY);
|
|
688
698
|
if (raw) {
|
|
689
699
|
try {
|
|
@@ -698,7 +708,7 @@ function getOrRotateSessionId(now = Date.now()) {
|
|
|
698
708
|
} catch {
|
|
699
709
|
}
|
|
700
710
|
}
|
|
701
|
-
const fresh = { id:
|
|
711
|
+
const fresh = { id: uuidV4(), last_event_at: now };
|
|
702
712
|
writeLocalStorage(SESSION_STORAGE_KEY, JSON.stringify(fresh));
|
|
703
713
|
return { id: fresh.id, isNew: true };
|
|
704
714
|
}
|
|
@@ -931,6 +941,69 @@ function parseFiring(value) {
|
|
|
931
941
|
currency: typeof f.currency === "string" ? f.currency : null
|
|
932
942
|
};
|
|
933
943
|
}
|
|
944
|
+
function isNumberList(value) {
|
|
945
|
+
return Array.isArray(value) && value.every((v) => typeof v === "number");
|
|
946
|
+
}
|
|
947
|
+
function isStringList(value) {
|
|
948
|
+
return Array.isArray(value) && value.every((v) => typeof v === "string");
|
|
949
|
+
}
|
|
950
|
+
function parseWindowsMap(value) {
|
|
951
|
+
const windowsByKey = {};
|
|
952
|
+
if (!value || typeof value !== "object") return windowsByKey;
|
|
953
|
+
for (const [key, windows] of Object.entries(value)) {
|
|
954
|
+
if (!windows || typeof windows !== "object") continue;
|
|
955
|
+
const w = windows;
|
|
956
|
+
windowsByKey[key] = {
|
|
957
|
+
morning: isNumberList(w.morning) ? w.morning : [],
|
|
958
|
+
afternoon: isNumberList(w.afternoon) ? w.afternoon : []
|
|
959
|
+
};
|
|
960
|
+
}
|
|
961
|
+
return windowsByKey;
|
|
962
|
+
}
|
|
963
|
+
function parseBookingRules(value) {
|
|
964
|
+
if (!value || typeof value !== "object") return null;
|
|
965
|
+
const r = value;
|
|
966
|
+
if (typeof r.min_days_ahead !== "number" || typeof r.max_days_ahead !== "number") return null;
|
|
967
|
+
if (!r.hours || typeof r.hours !== "object") return null;
|
|
968
|
+
const hours = parseWindowsMap(r.hours);
|
|
969
|
+
return {
|
|
970
|
+
min_days_ahead: r.min_days_ahead,
|
|
971
|
+
max_days_ahead: r.max_days_ahead,
|
|
972
|
+
hours,
|
|
973
|
+
closed_dates: isStringList(r.closed_dates) ? r.closed_dates : [],
|
|
974
|
+
special_hours: parseWindowsMap(r.special_hours),
|
|
975
|
+
vehicle_required: r.vehicle_required === true,
|
|
976
|
+
drop_off_options: isStringList(r.drop_off_options) ? r.drop_off_options : []
|
|
977
|
+
};
|
|
978
|
+
}
|
|
979
|
+
function parseBookingOption(value) {
|
|
980
|
+
if (!value || typeof value !== "object") return [];
|
|
981
|
+
const o = value;
|
|
982
|
+
if (typeof o.key !== "string" || !o.key || typeof o.label !== "string") return [];
|
|
983
|
+
return [{ key: o.key, label: o.label }];
|
|
984
|
+
}
|
|
985
|
+
function parseIntegrations(value) {
|
|
986
|
+
if (!value || typeof value !== "object") return {};
|
|
987
|
+
const autoleap = value.autoleap;
|
|
988
|
+
if (!autoleap || typeof autoleap !== "object") return {};
|
|
989
|
+
const booking = autoleap.booking;
|
|
990
|
+
if (!booking || typeof booking !== "object") return {};
|
|
991
|
+
const b = booking;
|
|
992
|
+
if (typeof b.fallback_url !== "string" || !b.fallback_url) return {};
|
|
993
|
+
return {
|
|
994
|
+
autoleap: {
|
|
995
|
+
booking: {
|
|
996
|
+
enabled: b.enabled === true,
|
|
997
|
+
fallback_url: b.fallback_url,
|
|
998
|
+
timezone: typeof b.timezone === "string" ? b.timezone : "UTC",
|
|
999
|
+
config_version: typeof b.config_version === "number" ? b.config_version : null,
|
|
1000
|
+
accepts_bookings: b.accepts_bookings === true,
|
|
1001
|
+
rules: parseBookingRules(b.rules),
|
|
1002
|
+
options: Array.isArray(b.options) ? b.options.flatMap(parseBookingOption) : []
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
};
|
|
1006
|
+
}
|
|
934
1007
|
function parseTrigger(value) {
|
|
935
1008
|
if (!value || typeof value !== "object") return null;
|
|
936
1009
|
const t = value;
|
|
@@ -990,7 +1063,8 @@ function parseConversionConfig(raw) {
|
|
|
990
1063
|
meta_pixel_ids: isStringMap(obj.meta_pixel_ids) ? obj.meta_pixel_ids : {},
|
|
991
1064
|
services,
|
|
992
1065
|
goals,
|
|
993
|
-
linked_hostnames: Array.isArray(obj.linked_hostnames) ? obj.linked_hostnames.filter((h) => typeof h === "string" && h.length > 0) : []
|
|
1066
|
+
linked_hostnames: Array.isArray(obj.linked_hostnames) ? obj.linked_hostnames.filter((h) => typeof h === "string" && h.length > 0) : [],
|
|
1067
|
+
integrations: parseIntegrations(obj.integrations)
|
|
994
1068
|
};
|
|
995
1069
|
}
|
|
996
1070
|
var CACHE_PREFIX = "_aranova_cfg_";
|
|
@@ -1414,6 +1488,13 @@ var TrackingConfigRuntime = class {
|
|
|
1414
1488
|
linkedHostnames() {
|
|
1415
1489
|
return this.current?.linked_hostnames ?? [];
|
|
1416
1490
|
}
|
|
1491
|
+
/**
|
|
1492
|
+
* Integration blocks, from the cached object even while unconfirmed: the booking fallback
|
|
1493
|
+
* link is safe to show stale. Same reference until the next adopt, for `useSyncExternalStore`.
|
|
1494
|
+
*/
|
|
1495
|
+
integrations() {
|
|
1496
|
+
return this.current?.integrations ?? null;
|
|
1497
|
+
}
|
|
1417
1498
|
async revalidateNow() {
|
|
1418
1499
|
try {
|
|
1419
1500
|
const headers = {};
|
|
@@ -1583,6 +1664,105 @@ function getTrackingConfigRuntime(ref, fetchImpl) {
|
|
|
1583
1664
|
return runtime;
|
|
1584
1665
|
}
|
|
1585
1666
|
|
|
1667
|
+
// ../../contracts/autoleap-booking-links.json
|
|
1668
|
+
var autoleap_booking_links_default = {
|
|
1669
|
+
hosts: ["myalp.io"]
|
|
1670
|
+
};
|
|
1671
|
+
|
|
1672
|
+
// ../tracking-core/src/integrations-public.ts
|
|
1673
|
+
var HANDOFF_HOSTS = new Set(autoleap_booking_links_default.hosts);
|
|
1674
|
+
function getBookingIntegration(integrations) {
|
|
1675
|
+
const booking = integrations?.autoleap?.booking;
|
|
1676
|
+
if (!booking) return null;
|
|
1677
|
+
const rules = booking.rules ? camelRules(booking.rules) : null;
|
|
1678
|
+
return {
|
|
1679
|
+
provider: "autoleap",
|
|
1680
|
+
enabled: booking.enabled,
|
|
1681
|
+
fallbackUrl: booking.fallback_url,
|
|
1682
|
+
acceptsBookings: booking.accepts_bookings && rules !== null && booking.config_version !== null,
|
|
1683
|
+
timezone: booking.timezone,
|
|
1684
|
+
configVersion: booking.config_version,
|
|
1685
|
+
rules,
|
|
1686
|
+
options: booking.options.map((option) => ({ key: option.key, label: option.label }))
|
|
1687
|
+
};
|
|
1688
|
+
}
|
|
1689
|
+
function camelRules(rules) {
|
|
1690
|
+
return {
|
|
1691
|
+
minDaysAhead: rules.min_days_ahead,
|
|
1692
|
+
maxDaysAhead: rules.max_days_ahead,
|
|
1693
|
+
hours: rules.hours,
|
|
1694
|
+
closedDates: rules.closed_dates,
|
|
1695
|
+
specialHours: rules.special_hours,
|
|
1696
|
+
vehicleRequired: rules.vehicle_required,
|
|
1697
|
+
dropOffOptions: rules.drop_off_options
|
|
1698
|
+
};
|
|
1699
|
+
}
|
|
1700
|
+
var WEEKDAYS = ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"];
|
|
1701
|
+
function shopToday(timeZone, now = /* @__PURE__ */ new Date()) {
|
|
1702
|
+
const parts = new Intl.DateTimeFormat("en-CA", {
|
|
1703
|
+
timeZone,
|
|
1704
|
+
year: "numeric",
|
|
1705
|
+
month: "2-digit",
|
|
1706
|
+
day: "2-digit"
|
|
1707
|
+
}).formatToParts(now);
|
|
1708
|
+
const part = (type) => parts.find((p) => p.type === type)?.value ?? "";
|
|
1709
|
+
return `${part("year")}-${part("month")}-${part("day")}`;
|
|
1710
|
+
}
|
|
1711
|
+
function addDays(isoDate, days) {
|
|
1712
|
+
const [year, month, day] = isoDate.split("-").map(Number);
|
|
1713
|
+
const date = new Date(Date.UTC(year, month - 1, day + days));
|
|
1714
|
+
return date.toISOString().slice(0, 10);
|
|
1715
|
+
}
|
|
1716
|
+
function bookableSlots(rules, { timeZone, now = /* @__PURE__ */ new Date() }) {
|
|
1717
|
+
const today = shopToday(timeZone, now);
|
|
1718
|
+
const days = [];
|
|
1719
|
+
const closed = new Set(rules.closedDates);
|
|
1720
|
+
for (let offset = rules.minDaysAhead; offset <= rules.maxDaysAhead; offset += 1) {
|
|
1721
|
+
const date = addDays(today, offset);
|
|
1722
|
+
if (closed.has(date)) continue;
|
|
1723
|
+
const weekday = WEEKDAYS[(/* @__PURE__ */ new Date(`${date}T00:00:00Z`)).getUTCDay()];
|
|
1724
|
+
const windows = rules.specialHours[date] ?? rules.hours[weekday];
|
|
1725
|
+
if (!windows || windows.morning.length === 0 && windows.afternoon.length === 0) continue;
|
|
1726
|
+
days.push({
|
|
1727
|
+
date,
|
|
1728
|
+
weekday,
|
|
1729
|
+
morning: [...windows.morning],
|
|
1730
|
+
afternoon: [...windows.afternoon]
|
|
1731
|
+
});
|
|
1732
|
+
}
|
|
1733
|
+
return days;
|
|
1734
|
+
}
|
|
1735
|
+
function buildBookingHandoffUrl(fallbackUrl, prefill = {}) {
|
|
1736
|
+
let url;
|
|
1737
|
+
try {
|
|
1738
|
+
url = new URL(fallbackUrl);
|
|
1739
|
+
} catch {
|
|
1740
|
+
return null;
|
|
1741
|
+
}
|
|
1742
|
+
if (url.protocol !== "https:" || !HANDOFF_HOSTS.has(url.hostname) || url.username || url.password || url.port) {
|
|
1743
|
+
return null;
|
|
1744
|
+
}
|
|
1745
|
+
const [firstName, lastName] = prefill.firstName?.trim() ? [prefill.firstName, prefill.lastName] : splitFullName(prefill.name);
|
|
1746
|
+
const values = [
|
|
1747
|
+
["firstName", firstName?.trim()],
|
|
1748
|
+
["lastName", lastName?.trim()],
|
|
1749
|
+
["phone", prefill.phone ? nationalDigits(prefill.phone) : ""],
|
|
1750
|
+
["email", prefill.email?.trim()]
|
|
1751
|
+
];
|
|
1752
|
+
for (const [key, value] of values) {
|
|
1753
|
+
if (value) url.searchParams.set(key, value);
|
|
1754
|
+
}
|
|
1755
|
+
return url.toString();
|
|
1756
|
+
}
|
|
1757
|
+
function splitFullName(name) {
|
|
1758
|
+
const [first = "", ...rest] = (name ?? "").trim().split(/\s+/);
|
|
1759
|
+
return [first, rest.join(" ")];
|
|
1760
|
+
}
|
|
1761
|
+
function nationalDigits(phone) {
|
|
1762
|
+
const parsed = parsePhone(phone);
|
|
1763
|
+
return (parsed.isValid ? parsed.national : phone).replace(/\D/g, "");
|
|
1764
|
+
}
|
|
1765
|
+
|
|
1586
1766
|
// ../tracking-core/src/resources/conversion-autofire.ts
|
|
1587
1767
|
function currentPath() {
|
|
1588
1768
|
return typeof window === "undefined" ? "" : window.location.pathname;
|
|
@@ -3402,6 +3582,9 @@ function attachPhoneClickCapture(client, config) {
|
|
|
3402
3582
|
};
|
|
3403
3583
|
}
|
|
3404
3584
|
|
|
3585
|
+
// ../tracking-core/src/resources/sales/bookings.ts
|
|
3586
|
+
var newBookingAttemptKey = uuidV4;
|
|
3587
|
+
|
|
3405
3588
|
// src/hooks.ts
|
|
3406
3589
|
function useGclid() {
|
|
3407
3590
|
const [gclid, setGclid] = useState(null);
|
|
@@ -3733,7 +3916,7 @@ function GoogleAdsTracking(props) {
|
|
|
3733
3916
|
import { createContext as createContext2, useContext as useContext2, useEffect as useEffect5, useMemo as useMemo4 } from "react";
|
|
3734
3917
|
|
|
3735
3918
|
// package.json
|
|
3736
|
-
var version = "1.
|
|
3919
|
+
var version = "1.3.0";
|
|
3737
3920
|
|
|
3738
3921
|
// ../tracking-core/src/phone-react.tsx
|
|
3739
3922
|
import {
|
|
@@ -4007,12 +4190,94 @@ function createTracking(options) {
|
|
|
4007
4190
|
)
|
|
4008
4191
|
};
|
|
4009
4192
|
}
|
|
4193
|
+
|
|
4194
|
+
// ../tracking-core/src/booking-react.tsx
|
|
4195
|
+
import { useCallback as useCallback3, useMemo as useMemo5, useRef, useState as useState4, useSyncExternalStore } from "react";
|
|
4196
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
4197
|
+
function serverSnapshot() {
|
|
4198
|
+
return null;
|
|
4199
|
+
}
|
|
4200
|
+
function useBookingIntegration(trackingConfig) {
|
|
4201
|
+
registerCapability("booking_handoff");
|
|
4202
|
+
const subscribe = useCallback3(
|
|
4203
|
+
(listener) => trackingConfig ? getTrackingConfigRuntime(trackingConfig).subscribe(listener) : () => {
|
|
4204
|
+
},
|
|
4205
|
+
[trackingConfig]
|
|
4206
|
+
);
|
|
4207
|
+
const integrations = useSyncExternalStore(
|
|
4208
|
+
subscribe,
|
|
4209
|
+
() => trackingConfig ? getTrackingConfigRuntime(trackingConfig).integrations() : null,
|
|
4210
|
+
serverSnapshot
|
|
4211
|
+
);
|
|
4212
|
+
return useMemo5(() => getBookingIntegration(integrations), [integrations]);
|
|
4213
|
+
}
|
|
4214
|
+
function useBookingHandoffUrl(trackingConfig, { fallbackUrl, prefill } = {}) {
|
|
4215
|
+
const booking = useBookingIntegration(trackingConfig);
|
|
4216
|
+
const base = booking?.fallbackUrl ?? fallbackUrl;
|
|
4217
|
+
return base ? buildBookingHandoffUrl(base, prefill) : null;
|
|
4218
|
+
}
|
|
4219
|
+
function BookingHandoffLink({
|
|
4220
|
+
trackingConfig,
|
|
4221
|
+
fallbackUrl,
|
|
4222
|
+
prefill,
|
|
4223
|
+
children,
|
|
4224
|
+
target = "_blank",
|
|
4225
|
+
rel = "noopener noreferrer",
|
|
4226
|
+
...anchorProps
|
|
4227
|
+
}) {
|
|
4228
|
+
const href = useBookingHandoffUrl(trackingConfig, { fallbackUrl, prefill });
|
|
4229
|
+
if (!href) return null;
|
|
4230
|
+
return /* @__PURE__ */ jsx4("a", { ...anchorProps, href, target, rel, children });
|
|
4231
|
+
}
|
|
4232
|
+
function useBookingSlots(trackingConfig) {
|
|
4233
|
+
const booking = useBookingIntegration(trackingConfig);
|
|
4234
|
+
if (!booking?.acceptsBookings || !booking.rules) return [];
|
|
4235
|
+
return bookableSlots(booking.rules, { timeZone: booking.timezone });
|
|
4236
|
+
}
|
|
4237
|
+
function useBookingSubmit(bookings, options = {}) {
|
|
4238
|
+
registerCapability("booking_integration");
|
|
4239
|
+
const [outcome, setOutcome] = useState4(null);
|
|
4240
|
+
const [submitting, setSubmitting] = useState4(false);
|
|
4241
|
+
const attemptKey = useRef(null);
|
|
4242
|
+
const inFlight = useRef(null);
|
|
4243
|
+
const { formSubmit } = options;
|
|
4244
|
+
const submit = useCallback3(
|
|
4245
|
+
(input) => {
|
|
4246
|
+
if (inFlight.current) return inFlight.current;
|
|
4247
|
+
attemptKey.current ?? (attemptKey.current = newBookingAttemptKey());
|
|
4248
|
+
setSubmitting(true);
|
|
4249
|
+
const run = bookings.submit(input, { attemptKey: attemptKey.current, formSubmit }).then((result) => {
|
|
4250
|
+
const unrecorded = result.status === "invalid" || result.status === "stale" || result.status === "failed" && result.id === null;
|
|
4251
|
+
if (!unrecorded) attemptKey.current = null;
|
|
4252
|
+
setOutcome(result);
|
|
4253
|
+
return result;
|
|
4254
|
+
}).finally(() => {
|
|
4255
|
+
inFlight.current = null;
|
|
4256
|
+
setSubmitting(false);
|
|
4257
|
+
});
|
|
4258
|
+
inFlight.current = run;
|
|
4259
|
+
return run;
|
|
4260
|
+
},
|
|
4261
|
+
[bookings, formSubmit]
|
|
4262
|
+
);
|
|
4263
|
+
const reset = useCallback3(() => {
|
|
4264
|
+
attemptKey.current = null;
|
|
4265
|
+
setOutcome(null);
|
|
4266
|
+
}, []);
|
|
4267
|
+
const status = submitting ? "submitting" : outcome?.status ?? "idle";
|
|
4268
|
+
return { status, outcome, submit, reset };
|
|
4269
|
+
}
|
|
4010
4270
|
export {
|
|
4011
4271
|
AdPlatformTracking,
|
|
4272
|
+
BookingHandoffLink,
|
|
4012
4273
|
ConsentBanner,
|
|
4013
4274
|
GoogleAdsTracking,
|
|
4014
4275
|
PhoneField,
|
|
4015
4276
|
createTracking,
|
|
4277
|
+
useBookingHandoffUrl,
|
|
4278
|
+
useBookingIntegration,
|
|
4279
|
+
useBookingSlots,
|
|
4280
|
+
useBookingSubmit,
|
|
4016
4281
|
useConsent,
|
|
4017
4282
|
useConsentState,
|
|
4018
4283
|
useCookiePreferences,
|