@aranova/tracking-react 0.11.0 → 0.12.1
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 +83 -61
- package/dist/index.d.mts +137 -880
- package/dist/index.d.ts +137 -880
- package/dist/index.js +420 -89
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +405 -90
- package/dist/index.mjs.map +1 -1
- package/dist/phone-utils-DXAki8pO.d.mts +344 -0
- package/dist/phone-utils-DXAki8pO.d.ts +344 -0
- package/dist/phone.d.mts +3 -0
- package/dist/phone.d.ts +3 -0
- package/dist/phone.js +416 -0
- package/dist/phone.js.map +1 -0
- package/dist/phone.mjs +384 -0
- package/dist/phone.mjs.map +1 -0
- package/dist/sales.d.mts +784 -0
- package/dist/sales.d.ts +784 -0
- package/dist/sales.js +400 -0
- package/dist/sales.js.map +1 -0
- package/dist/sales.mjs +359 -0
- package/dist/sales.mjs.map +1 -0
- package/package.json +33 -4
package/dist/index.mjs
CHANGED
|
@@ -16,31 +16,26 @@ function buildConsentPayload(state) {
|
|
|
16
16
|
};
|
|
17
17
|
}
|
|
18
18
|
function getConsentState() {
|
|
19
|
-
if (typeof window === "undefined")
|
|
20
|
-
return "pending";
|
|
19
|
+
if (typeof window === "undefined") return "pending";
|
|
21
20
|
const storedState = window.localStorage.getItem(CONSENT_STATE_KEY);
|
|
22
|
-
if (storedState === "granted" || storedState === "denied")
|
|
23
|
-
return storedState;
|
|
21
|
+
if (storedState === "granted" || storedState === "denied") return storedState;
|
|
24
22
|
return "pending";
|
|
25
23
|
}
|
|
26
24
|
function setConsentState(state) {
|
|
27
|
-
if (typeof window === "undefined")
|
|
28
|
-
return;
|
|
25
|
+
if (typeof window === "undefined") return;
|
|
29
26
|
window.localStorage.setItem(CONSENT_STATE_KEY, state);
|
|
30
27
|
window.localStorage.setItem(CONSENT_TIMESTAMP_KEY, (/* @__PURE__ */ new Date()).toISOString());
|
|
31
28
|
if (typeof window.gtag === "function")
|
|
32
29
|
window.gtag("consent", "update", buildConsentPayload(state));
|
|
33
30
|
}
|
|
34
31
|
function resetConsent() {
|
|
35
|
-
if (typeof window === "undefined")
|
|
36
|
-
return;
|
|
32
|
+
if (typeof window === "undefined") return;
|
|
37
33
|
window.localStorage.removeItem(CONSENT_STATE_KEY);
|
|
38
34
|
window.localStorage.removeItem(CONSENT_TIMESTAMP_KEY);
|
|
39
35
|
}
|
|
40
36
|
function restoreStoredConsent() {
|
|
41
37
|
const consentState = getConsentState();
|
|
42
|
-
if (consentState === "granted" || consentState === "denied")
|
|
43
|
-
setConsentState(consentState);
|
|
38
|
+
if (consentState === "granted" || consentState === "denied") setConsentState(consentState);
|
|
44
39
|
return consentState;
|
|
45
40
|
}
|
|
46
41
|
|
|
@@ -97,8 +92,7 @@ function isValidGtagId(id) {
|
|
|
97
92
|
}
|
|
98
93
|
function ensureGtagFunction() {
|
|
99
94
|
window.dataLayer = window.dataLayer || [];
|
|
100
|
-
if (typeof window.gtag === "function")
|
|
101
|
-
return window.gtag;
|
|
95
|
+
if (typeof window.gtag === "function") return window.gtag;
|
|
102
96
|
window.gtag = (...args) => {
|
|
103
97
|
window.dataLayer?.push(args);
|
|
104
98
|
};
|
|
@@ -115,17 +109,17 @@ function applyDefaultConsentState() {
|
|
|
115
109
|
});
|
|
116
110
|
}
|
|
117
111
|
function loadGtagScript(gtagId) {
|
|
118
|
-
if (typeof document === "undefined")
|
|
119
|
-
return;
|
|
112
|
+
if (typeof document === "undefined") return;
|
|
120
113
|
const marker = getScriptMarker("gtag-loader");
|
|
121
|
-
const existingScript = document.querySelector(
|
|
122
|
-
|
|
123
|
-
|
|
114
|
+
const existingScript = document.querySelector(
|
|
115
|
+
`script[${TRACKING_SCRIPT_ATTRIBUTE}="${marker}"]`
|
|
116
|
+
);
|
|
117
|
+
if (existingScript) return;
|
|
124
118
|
const script = document.createElement("script");
|
|
125
119
|
script.async = true;
|
|
126
120
|
script.src = `${GTAG_SCRIPT_HOST}?id=${encodeURIComponent(gtagId)}`;
|
|
127
121
|
script.setAttribute(TRACKING_SCRIPT_ATTRIBUTE, marker);
|
|
128
|
-
document.head.
|
|
122
|
+
document.head.append(script);
|
|
129
123
|
}
|
|
130
124
|
function initializeGtag(gtagId) {
|
|
131
125
|
const gtag = ensureGtagFunction();
|
|
@@ -133,21 +127,17 @@ function initializeGtag(gtagId) {
|
|
|
133
127
|
gtag("config", gtagId);
|
|
134
128
|
}
|
|
135
129
|
function bootstrapGoogleAdsTracking(gtagId) {
|
|
136
|
-
if (typeof window === "undefined" || typeof document === "undefined")
|
|
137
|
-
|
|
138
|
-
if (!isValidGtagId(gtagId))
|
|
139
|
-
return;
|
|
130
|
+
if (typeof window === "undefined" || typeof document === "undefined") return;
|
|
131
|
+
if (!isValidGtagId(gtagId)) return;
|
|
140
132
|
applyDefaultConsentState();
|
|
141
133
|
loadGtagScript(gtagId);
|
|
142
134
|
initializeGtag(gtagId);
|
|
143
135
|
restoreStoredConsent();
|
|
144
136
|
}
|
|
145
137
|
function bootstrapMultipleGtags(gtagIds) {
|
|
146
|
-
if (typeof window === "undefined" || typeof document === "undefined")
|
|
147
|
-
return;
|
|
138
|
+
if (typeof window === "undefined" || typeof document === "undefined") return;
|
|
148
139
|
const ids = Object.values(gtagIds).filter(isValidGtagId);
|
|
149
|
-
if (ids.length === 0)
|
|
150
|
-
return;
|
|
140
|
+
if (ids.length === 0) return;
|
|
151
141
|
applyDefaultConsentState();
|
|
152
142
|
loadGtagScript(ids[0]);
|
|
153
143
|
const gtag = ensureGtagFunction();
|
|
@@ -199,18 +189,15 @@ function getTrackingQueryValues(searchParams) {
|
|
|
199
189
|
}, {});
|
|
200
190
|
}
|
|
201
191
|
function getCookieValueFromDocument(key) {
|
|
202
|
-
if (typeof document === "undefined")
|
|
203
|
-
return null;
|
|
192
|
+
if (typeof document === "undefined") return null;
|
|
204
193
|
const cookies = document.cookie ? document.cookie.split("; ") : [];
|
|
205
194
|
const match = cookies.find((cookie) => cookie.startsWith(`${key}=`));
|
|
206
|
-
if (!match)
|
|
207
|
-
return null;
|
|
195
|
+
if (!match) return null;
|
|
208
196
|
const [, rawValue = ""] = match.split("=");
|
|
209
197
|
return normalizeTrackingCookieValue(decodeURIComponent(rawValue));
|
|
210
198
|
}
|
|
211
199
|
function setTrackingCookie(key, value, maxAgeSeconds = TRACKING_COOKIE_MAX_AGE_SECONDS) {
|
|
212
|
-
if (typeof document === "undefined")
|
|
213
|
-
return;
|
|
200
|
+
if (typeof document === "undefined") return;
|
|
214
201
|
const encodedValue = encodeURIComponent(value);
|
|
215
202
|
document.cookie = `${key}=${encodedValue}; Max-Age=${maxAgeSeconds}; Path=/; SameSite=Lax`;
|
|
216
203
|
}
|
|
@@ -250,18 +237,15 @@ function writeLocalStorage(key, value) {
|
|
|
250
237
|
}
|
|
251
238
|
}
|
|
252
239
|
function getVisitorId() {
|
|
253
|
-
if (typeof window === "undefined")
|
|
254
|
-
return safeUuid();
|
|
240
|
+
if (typeof window === "undefined") return safeUuid();
|
|
255
241
|
const existing = readLocalStorage(VISITOR_STORAGE_KEY);
|
|
256
|
-
if (existing && existing.length > 0)
|
|
257
|
-
return existing;
|
|
242
|
+
if (existing && existing.length > 0) return existing;
|
|
258
243
|
const fresh = safeUuid();
|
|
259
244
|
writeLocalStorage(VISITOR_STORAGE_KEY, fresh);
|
|
260
245
|
return fresh;
|
|
261
246
|
}
|
|
262
247
|
function getOrRotateSessionId(now = Date.now()) {
|
|
263
|
-
if (typeof window === "undefined")
|
|
264
|
-
return { id: safeUuid(), isNew: true };
|
|
248
|
+
if (typeof window === "undefined") return { id: safeUuid(), isNew: true };
|
|
265
249
|
const raw = readLocalStorage(SESSION_STORAGE_KEY);
|
|
266
250
|
if (raw) {
|
|
267
251
|
try {
|
|
@@ -334,8 +318,7 @@ function setLastFiredUrl(url) {
|
|
|
334
318
|
writeSessionStorage(LAST_FIRED_URL_STORAGE_KEY, url);
|
|
335
319
|
}
|
|
336
320
|
function buildPageViewMetadata(referrerOverride) {
|
|
337
|
-
if (typeof window === "undefined" || typeof document === "undefined")
|
|
338
|
-
return null;
|
|
321
|
+
if (typeof window === "undefined" || typeof document === "undefined") return null;
|
|
339
322
|
return pageViewMetadataSchema.parse({
|
|
340
323
|
page: {
|
|
341
324
|
title: document.title || null,
|
|
@@ -348,8 +331,7 @@ function buildPageViewMetadata(referrerOverride) {
|
|
|
348
331
|
});
|
|
349
332
|
}
|
|
350
333
|
function fireManualPageView(client) {
|
|
351
|
-
if (typeof window === "undefined")
|
|
352
|
-
return;
|
|
334
|
+
if (typeof window === "undefined") return;
|
|
353
335
|
const currentHref = window.location.href;
|
|
354
336
|
const previousFiredUrl = getLastFiredUrl();
|
|
355
337
|
const internalReferrer = previousFiredUrl !== null && previousFiredUrl !== currentHref ? previousFiredUrl : null;
|
|
@@ -385,8 +367,7 @@ function attachAutoPageView(client, options = {}) {
|
|
|
385
367
|
let lastPath = window.location.pathname + window.location.search;
|
|
386
368
|
function maybeFire() {
|
|
387
369
|
const current = window.location.pathname + window.location.search;
|
|
388
|
-
if (current === lastPath)
|
|
389
|
-
return;
|
|
370
|
+
if (current === lastPath) return;
|
|
390
371
|
lastPath = current;
|
|
391
372
|
fireManualPageView(client);
|
|
392
373
|
}
|
|
@@ -408,8 +389,7 @@ function attachAutoPageView(client, options = {}) {
|
|
|
408
389
|
history.replaceState = patchedReplaceState;
|
|
409
390
|
window.addEventListener("popstate", maybeFire);
|
|
410
391
|
window.addEventListener("pageshow", handlePageShow);
|
|
411
|
-
if (!options.skipInitial)
|
|
412
|
-
fireManualPageView(client);
|
|
392
|
+
if (!options.skipInitial) fireManualPageView(client);
|
|
413
393
|
return () => {
|
|
414
394
|
history.pushState = originalPushState;
|
|
415
395
|
history.replaceState = originalReplaceState;
|
|
@@ -491,8 +471,7 @@ function buildContext(surface, sdkVersion, packageName, environment, activeGtagI
|
|
|
491
471
|
};
|
|
492
472
|
}
|
|
493
473
|
function readTrackingParams() {
|
|
494
|
-
if (typeof window === "undefined")
|
|
495
|
-
return createEmptyTrackingParams();
|
|
474
|
+
if (typeof window === "undefined") return createEmptyTrackingParams();
|
|
496
475
|
try {
|
|
497
476
|
captureTrackingParamsFromLocation();
|
|
498
477
|
} catch {
|
|
@@ -507,8 +486,7 @@ function consentSnapshot() {
|
|
|
507
486
|
}
|
|
508
487
|
}
|
|
509
488
|
async function postWithFetch(url, body, apiKey, identity, keepalive) {
|
|
510
|
-
if (typeof fetch !== "function")
|
|
511
|
-
return;
|
|
489
|
+
if (typeof fetch !== "function") return;
|
|
512
490
|
try {
|
|
513
491
|
await fetch(url, {
|
|
514
492
|
method: "POST",
|
|
@@ -568,8 +546,7 @@ function createTrackingClient(config) {
|
|
|
568
546
|
const visitorId = getVisitorId();
|
|
569
547
|
const initialSession = getOrRotateSessionId();
|
|
570
548
|
let sessionId = initialSession.id;
|
|
571
|
-
if (typeof window !== "undefined")
|
|
572
|
-
firstPage = window.location.href;
|
|
549
|
+
if (typeof window !== "undefined") firstPage = window.location.href;
|
|
573
550
|
function enqueueHeartbeat() {
|
|
574
551
|
const metadata = buildHeartbeatMetadata(
|
|
575
552
|
config.surface,
|
|
@@ -595,7 +572,13 @@ function createTrackingClient(config) {
|
|
|
595
572
|
}
|
|
596
573
|
sessionId = rotated.id;
|
|
597
574
|
const params = readTrackingParams();
|
|
598
|
-
const context = buildContext(
|
|
575
|
+
const context = buildContext(
|
|
576
|
+
config.surface,
|
|
577
|
+
sdkVersion,
|
|
578
|
+
packageName,
|
|
579
|
+
environment,
|
|
580
|
+
activeGtagIds
|
|
581
|
+
);
|
|
599
582
|
return {
|
|
600
583
|
session_id: sessionId,
|
|
601
584
|
visitor_id: visitorId,
|
|
@@ -612,8 +595,7 @@ function createTrackingClient(config) {
|
|
|
612
595
|
};
|
|
613
596
|
}
|
|
614
597
|
function scheduleFlush() {
|
|
615
|
-
if (flushTimer !== null || destroyed)
|
|
616
|
-
return;
|
|
598
|
+
if (flushTimer !== null || destroyed) return;
|
|
617
599
|
flushTimer = setTimeout(() => {
|
|
618
600
|
flushTimer = null;
|
|
619
601
|
void flush();
|
|
@@ -626,8 +608,7 @@ function createTrackingClient(config) {
|
|
|
626
608
|
}
|
|
627
609
|
}
|
|
628
610
|
async function flush() {
|
|
629
|
-
if (queue.length === 0)
|
|
630
|
-
return;
|
|
611
|
+
if (queue.length === 0) return;
|
|
631
612
|
const events = queue.slice(0, HARD_MAX_BATCH);
|
|
632
613
|
queue = queue.slice(events.length);
|
|
633
614
|
clearScheduledFlush();
|
|
@@ -639,10 +620,8 @@ function createTrackingClient(config) {
|
|
|
639
620
|
await postWithFetch(eventsUrl, serialized, config.apiKey, identityHeaders2, false);
|
|
640
621
|
}
|
|
641
622
|
function trackEvent(input) {
|
|
642
|
-
if (destroyed)
|
|
643
|
-
|
|
644
|
-
if (!input || typeof input.eventType !== "string" || input.eventType.length === 0)
|
|
645
|
-
return;
|
|
623
|
+
if (destroyed) return;
|
|
624
|
+
if (!input || typeof input.eventType !== "string" || input.eventType.length === 0) return;
|
|
646
625
|
const occurredAt = input.occurredAt instanceof Date ? input.occurredAt.toISOString() : typeof input.occurredAt === "string" ? input.occurredAt : (/* @__PURE__ */ new Date()).toISOString();
|
|
647
626
|
queue.push({
|
|
648
627
|
event_type: input.eventType,
|
|
@@ -657,8 +636,7 @@ function createTrackingClient(config) {
|
|
|
657
636
|
}
|
|
658
637
|
}
|
|
659
638
|
function flushOnUnload() {
|
|
660
|
-
if (queue.length === 0)
|
|
661
|
-
return;
|
|
639
|
+
if (queue.length === 0) return;
|
|
662
640
|
const events = queue.slice(0, HARD_MAX_BATCH);
|
|
663
641
|
queue = queue.slice(events.length);
|
|
664
642
|
clearScheduledFlush();
|
|
@@ -1333,21 +1311,40 @@ function createSalesClient(config) {
|
|
|
1333
1311
|
return salesRequest(config, "POST", "/sales", body);
|
|
1334
1312
|
},
|
|
1335
1313
|
async list(query) {
|
|
1336
|
-
const { cursor, limit, ...filters } = query ?? {};
|
|
1314
|
+
const { cursor, limit, sort, order, want_total, ...filters } = query ?? {};
|
|
1337
1315
|
return salesRequest(config, "POST", "/sales/query", {
|
|
1338
1316
|
filters,
|
|
1339
1317
|
...limit !== void 0 ? { limit } : {},
|
|
1340
|
-
...cursor !== void 0 ? { cursor } : {}
|
|
1318
|
+
...cursor !== void 0 ? { cursor } : {},
|
|
1319
|
+
...sort !== void 0 ? { sort } : {},
|
|
1320
|
+
...order !== void 0 ? { order } : {},
|
|
1321
|
+
...want_total !== void 0 ? { want_total } : {}
|
|
1341
1322
|
});
|
|
1342
1323
|
},
|
|
1343
1324
|
async summary(query) {
|
|
1344
|
-
const {
|
|
1325
|
+
const {
|
|
1326
|
+
range,
|
|
1327
|
+
include_categories,
|
|
1328
|
+
include_deleted_services,
|
|
1329
|
+
top_n,
|
|
1330
|
+
since,
|
|
1331
|
+
until,
|
|
1332
|
+
timezone,
|
|
1333
|
+
granularity,
|
|
1334
|
+
compare_to,
|
|
1335
|
+
...filters
|
|
1336
|
+
} = query;
|
|
1345
1337
|
return salesRequest(config, "POST", "/sales/summary", {
|
|
1346
1338
|
filters,
|
|
1347
|
-
range,
|
|
1339
|
+
...range !== void 0 ? { range } : {},
|
|
1348
1340
|
...include_categories !== void 0 ? { include_categories } : {},
|
|
1349
1341
|
...include_deleted_services !== void 0 ? { include_deleted_services } : {},
|
|
1350
|
-
...top_n !== void 0 ? { top_n } : {}
|
|
1342
|
+
...top_n !== void 0 ? { top_n } : {},
|
|
1343
|
+
...since !== void 0 ? { since } : {},
|
|
1344
|
+
...until !== void 0 ? { until } : {},
|
|
1345
|
+
...timezone !== void 0 ? { timezone } : {},
|
|
1346
|
+
...granularity !== void 0 ? { granularity } : {},
|
|
1347
|
+
...compare_to !== void 0 ? { compare_to } : {}
|
|
1351
1348
|
});
|
|
1352
1349
|
},
|
|
1353
1350
|
async get(id) {
|
|
@@ -1358,15 +1355,53 @@ function createSalesClient(config) {
|
|
|
1358
1355
|
},
|
|
1359
1356
|
async delete(id) {
|
|
1360
1357
|
await salesRequest(config, "DELETE", `/sales/${id}`);
|
|
1358
|
+
},
|
|
1359
|
+
customers: {
|
|
1360
|
+
async list(query) {
|
|
1361
|
+
const { segment, sort, order, cursor, limit, want_total, ...filters } = query ?? {};
|
|
1362
|
+
return salesRequest(config, "POST", "/customers/query", {
|
|
1363
|
+
filters,
|
|
1364
|
+
...segment !== void 0 ? { segment } : {},
|
|
1365
|
+
...sort !== void 0 ? { sort } : {},
|
|
1366
|
+
...order !== void 0 ? { order } : {},
|
|
1367
|
+
...cursor !== void 0 ? { cursor } : {},
|
|
1368
|
+
...limit !== void 0 ? { limit } : {},
|
|
1369
|
+
...want_total !== void 0 ? { want_total } : {}
|
|
1370
|
+
});
|
|
1371
|
+
},
|
|
1372
|
+
async get(id, options) {
|
|
1373
|
+
const params = new URLSearchParams();
|
|
1374
|
+
if (options?.include_sales !== void 0)
|
|
1375
|
+
params.set("include_sales", String(options.include_sales));
|
|
1376
|
+
if (options?.limit !== void 0) params.set("limit", String(options.limit));
|
|
1377
|
+
if (options?.cursor != null) params.set("cursor", options.cursor);
|
|
1378
|
+
const qs = params.toString();
|
|
1379
|
+
return salesRequest(
|
|
1380
|
+
config,
|
|
1381
|
+
"GET",
|
|
1382
|
+
`/customers/${encodeURIComponent(id)}${qs ? `?${qs}` : ""}`
|
|
1383
|
+
);
|
|
1384
|
+
},
|
|
1385
|
+
async summary(query) {
|
|
1386
|
+
const { range, since, until, timezone, compare_to, ...filters } = query ?? {};
|
|
1387
|
+
return salesRequest(config, "POST", "/customers/summary", {
|
|
1388
|
+
filters,
|
|
1389
|
+
...range !== void 0 ? { range } : {},
|
|
1390
|
+
...since !== void 0 ? { since } : {},
|
|
1391
|
+
...until !== void 0 ? { until } : {},
|
|
1392
|
+
...timezone !== void 0 ? { timezone } : {},
|
|
1393
|
+
...compare_to !== void 0 ? { compare_to } : {}
|
|
1394
|
+
});
|
|
1395
|
+
}
|
|
1396
|
+
},
|
|
1397
|
+
business: {
|
|
1398
|
+
async config() {
|
|
1399
|
+
return salesRequest(config, "GET", "/business/config");
|
|
1400
|
+
}
|
|
1361
1401
|
}
|
|
1362
1402
|
};
|
|
1363
1403
|
}
|
|
1364
1404
|
|
|
1365
|
-
// ../tracking-core/src/resources/services.ts
|
|
1366
|
-
async function fetchServices(config) {
|
|
1367
|
-
return salesRequest(config, "GET", "/services");
|
|
1368
|
-
}
|
|
1369
|
-
|
|
1370
1405
|
// ../tracking-core/src/resources/sales/money.ts
|
|
1371
1406
|
var MINOR_UNIT_EXPONENT = {
|
|
1372
1407
|
USD: 2,
|
|
@@ -1386,6 +1421,181 @@ function formatMoney(cents, currency, locale) {
|
|
|
1386
1421
|
fromMinor(cents, currency)
|
|
1387
1422
|
);
|
|
1388
1423
|
}
|
|
1424
|
+
function formatDateInTz(iso, timeZone, opts, locale) {
|
|
1425
|
+
const date = new Date(iso);
|
|
1426
|
+
if (Number.isNaN(date.getTime())) return iso;
|
|
1427
|
+
return new Intl.DateTimeFormat(locale, {
|
|
1428
|
+
year: "numeric",
|
|
1429
|
+
month: "short",
|
|
1430
|
+
day: "2-digit",
|
|
1431
|
+
hour: "2-digit",
|
|
1432
|
+
minute: "2-digit",
|
|
1433
|
+
...opts,
|
|
1434
|
+
timeZone
|
|
1435
|
+
}).format(date);
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
// ../tracking-core/src/resources/sales/schema.ts
|
|
1439
|
+
import { z as z11 } from "zod";
|
|
1440
|
+
var SUPPORTED_CURRENCIES = ["USD", "CAD"];
|
|
1441
|
+
var TRACKING_ENVIRONMENTS = ["production", "development"];
|
|
1442
|
+
var currencySchema = z11.enum(SUPPORTED_CURRENCIES);
|
|
1443
|
+
var centsSchema = z11.number().int().nonnegative();
|
|
1444
|
+
var quantitySchema = z11.string().regex(/^\d+(\.\d{1,3})?$/);
|
|
1445
|
+
var metadataSchema = z11.record(z11.unknown());
|
|
1446
|
+
var saleItemSchema = z11.object({
|
|
1447
|
+
external_item_id: z11.string().nullable().optional(),
|
|
1448
|
+
name: z11.string().nullable().optional(),
|
|
1449
|
+
category: z11.string().nullable().optional(),
|
|
1450
|
+
quantity: quantitySchema,
|
|
1451
|
+
unit_price_cents: centsSchema,
|
|
1452
|
+
// Non-negativity validated on the wire — same contract as the other cents
|
|
1453
|
+
// fields — and backstopped by the DB CHECK.
|
|
1454
|
+
unit_cost_cents: centsSchema.nullable().optional()
|
|
1455
|
+
}).strict();
|
|
1456
|
+
var saleServiceSchema = z11.object({
|
|
1457
|
+
service: z11.string(),
|
|
1458
|
+
amount_cents: centsSchema
|
|
1459
|
+
}).strict();
|
|
1460
|
+
var customerNameSchema = z11.string().max(200);
|
|
1461
|
+
var customerPhoneSchema = z11.string().max(64);
|
|
1462
|
+
var customerEmailSchema = z11.string().max(320).email();
|
|
1463
|
+
function refineServiceXor(val, ctx, { requireAmount }) {
|
|
1464
|
+
if (val.services != null) {
|
|
1465
|
+
if (val.service != null) {
|
|
1466
|
+
ctx.addIssue({
|
|
1467
|
+
code: z11.ZodIssueCode.custom,
|
|
1468
|
+
message: "pass either `service` or `services`, not both",
|
|
1469
|
+
path: ["services"]
|
|
1470
|
+
});
|
|
1471
|
+
}
|
|
1472
|
+
if (val.services.length === 0) {
|
|
1473
|
+
ctx.addIssue({
|
|
1474
|
+
code: z11.ZodIssueCode.custom,
|
|
1475
|
+
message: "`services` must not be empty",
|
|
1476
|
+
path: ["services"]
|
|
1477
|
+
});
|
|
1478
|
+
}
|
|
1479
|
+
const keys = val.services.map((s) => s.service);
|
|
1480
|
+
if (new Set(keys).size !== keys.length) {
|
|
1481
|
+
ctx.addIssue({
|
|
1482
|
+
code: z11.ZodIssueCode.custom,
|
|
1483
|
+
message: "`services` must not list the same service more than once",
|
|
1484
|
+
path: ["services"]
|
|
1485
|
+
});
|
|
1486
|
+
}
|
|
1487
|
+
if (val.amount_total_cents != null) {
|
|
1488
|
+
const sum = val.services.reduce((acc, s) => acc + s.amount_cents, 0);
|
|
1489
|
+
if (val.amount_total_cents !== sum) {
|
|
1490
|
+
ctx.addIssue({
|
|
1491
|
+
code: z11.ZodIssueCode.custom,
|
|
1492
|
+
message: "amount_total_cents must equal the sum of the services amounts (omit it to derive it automatically)",
|
|
1493
|
+
path: ["amount_total_cents"]
|
|
1494
|
+
});
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
} else if (requireAmount && val.amount_total_cents == null) {
|
|
1498
|
+
ctx.addIssue({
|
|
1499
|
+
code: z11.ZodIssueCode.custom,
|
|
1500
|
+
message: "amount_total_cents is required unless `services` is provided",
|
|
1501
|
+
path: ["amount_total_cents"]
|
|
1502
|
+
});
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
var saleCreateSchema = z11.object({
|
|
1506
|
+
external_id: z11.string().nullable().optional(),
|
|
1507
|
+
description: z11.string().nullable().optional(),
|
|
1508
|
+
service: z11.string().nullable().optional(),
|
|
1509
|
+
services: z11.array(saleServiceSchema).nullable().optional(),
|
|
1510
|
+
currency: currencySchema,
|
|
1511
|
+
// Optional only because the plural `services` form derives it from the sum
|
|
1512
|
+
// (see refineServiceXor); the singular/serviceless path still requires it.
|
|
1513
|
+
amount_total_cents: centsSchema.nullable().optional(),
|
|
1514
|
+
occurred_at: z11.string().datetime(),
|
|
1515
|
+
environment: z11.enum(TRACKING_ENVIRONMENTS).default("production"),
|
|
1516
|
+
items: z11.array(saleItemSchema).default([]),
|
|
1517
|
+
metadata: metadataSchema.nullable().optional(),
|
|
1518
|
+
customer_name: customerNameSchema.nullable().optional(),
|
|
1519
|
+
customer_phone: customerPhoneSchema.nullable().optional(),
|
|
1520
|
+
customer_email: customerEmailSchema.nullable().optional()
|
|
1521
|
+
}).strict().superRefine((val, ctx) => refineServiceXor(val, ctx, { requireAmount: true }));
|
|
1522
|
+
var saleUpdateSchema = z11.object({
|
|
1523
|
+
description: z11.string().nullable().optional(),
|
|
1524
|
+
service: z11.string().nullable().optional(),
|
|
1525
|
+
services: z11.array(saleServiceSchema).nullable().optional(),
|
|
1526
|
+
currency: currencySchema.optional(),
|
|
1527
|
+
amount_total_cents: centsSchema.optional(),
|
|
1528
|
+
occurred_at: z11.string().datetime().optional(),
|
|
1529
|
+
items: z11.array(saleItemSchema).optional(),
|
|
1530
|
+
metadata: metadataSchema.nullable().optional(),
|
|
1531
|
+
customer_name: customerNameSchema.nullable().optional(),
|
|
1532
|
+
customer_phone: customerPhoneSchema.nullable().optional(),
|
|
1533
|
+
customer_email: customerEmailSchema.nullable().optional()
|
|
1534
|
+
}).strict().superRefine((val, ctx) => refineServiceXor(val, ctx, { requireAmount: false }));
|
|
1535
|
+
var TRACKING_RANGES = ["24h", "7d", "30d"];
|
|
1536
|
+
var NAMED_RANGES = [
|
|
1537
|
+
"today",
|
|
1538
|
+
"yesterday",
|
|
1539
|
+
"wtd",
|
|
1540
|
+
"mtd",
|
|
1541
|
+
"qtd",
|
|
1542
|
+
"ytd",
|
|
1543
|
+
"24h",
|
|
1544
|
+
"7d",
|
|
1545
|
+
"30d",
|
|
1546
|
+
"90d",
|
|
1547
|
+
"custom"
|
|
1548
|
+
];
|
|
1549
|
+
|
|
1550
|
+
// ../tracking-core/src/resources/services.ts
|
|
1551
|
+
async function fetchServices(config) {
|
|
1552
|
+
return salesRequest(config, "GET", "/services");
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
// ../tracking-core/src/phone.ts
|
|
1556
|
+
import { AsYouType, parsePhoneNumberFromString } from "libphonenumber-js";
|
|
1557
|
+
var DEFAULT_PHONE_COUNTRY = "CA";
|
|
1558
|
+
function parsePhone(raw, country) {
|
|
1559
|
+
const region = country ?? DEFAULT_PHONE_COUNTRY;
|
|
1560
|
+
const parsed = parsePhoneNumberFromString(raw ?? "", region);
|
|
1561
|
+
if (!parsed) {
|
|
1562
|
+
return { e164: null, national: "", international: "", country: region, isValid: false };
|
|
1563
|
+
}
|
|
1564
|
+
const isValid = parsed.isValid();
|
|
1565
|
+
return {
|
|
1566
|
+
// E.164 is only surfaced for a *valid* number — a possible-but-invalid input
|
|
1567
|
+
// (e.g. too few digits) still parses but must not be transmitted.
|
|
1568
|
+
e164: isValid ? parsed.number : null,
|
|
1569
|
+
national: parsed.formatNational(),
|
|
1570
|
+
international: parsed.formatInternational(),
|
|
1571
|
+
country: parsed.country ?? region,
|
|
1572
|
+
isValid
|
|
1573
|
+
};
|
|
1574
|
+
}
|
|
1575
|
+
function toE164(raw, country) {
|
|
1576
|
+
return parsePhone(raw, country).e164;
|
|
1577
|
+
}
|
|
1578
|
+
function formatPhone(value, format = "national", country) {
|
|
1579
|
+
const parsed = parsePhone(value, country);
|
|
1580
|
+
if (typeof format === "function") return format(parsed);
|
|
1581
|
+
switch (format) {
|
|
1582
|
+
case "international":
|
|
1583
|
+
return parsed.international || value;
|
|
1584
|
+
case "e164":
|
|
1585
|
+
return parsed.e164 ?? value;
|
|
1586
|
+
case "national":
|
|
1587
|
+
default:
|
|
1588
|
+
return parsed.national || value;
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
function formatPhoneAsTyped(raw, country) {
|
|
1592
|
+
return new AsYouType(country ?? DEFAULT_PHONE_COUNTRY).input(raw ?? "");
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
// ../tracking-core/src/phone-field.ts
|
|
1596
|
+
function phoneField(name, raw, country) {
|
|
1597
|
+
return { name, type: "phone", value: toE164(raw, country) };
|
|
1598
|
+
}
|
|
1389
1599
|
|
|
1390
1600
|
// src/hooks.ts
|
|
1391
1601
|
function useGclid() {
|
|
@@ -1627,10 +1837,7 @@ var ANIMATION_KEYFRAMES = `
|
|
|
1627
1837
|
import { useEffect as useEffect3, useMemo } from "react";
|
|
1628
1838
|
function GoogleAdsTracking(props) {
|
|
1629
1839
|
const { gtagId, gtagIds } = props;
|
|
1630
|
-
const gtagIdsKey = useMemo(
|
|
1631
|
-
() => gtagIds ? JSON.stringify(gtagIds) : "",
|
|
1632
|
-
[gtagIds]
|
|
1633
|
-
);
|
|
1840
|
+
const gtagIdsKey = useMemo(() => gtagIds ? JSON.stringify(gtagIds) : "", [gtagIds]);
|
|
1634
1841
|
useEffect3(() => {
|
|
1635
1842
|
if (gtagIds && Object.keys(gtagIds).length > 0) {
|
|
1636
1843
|
bootstrapMultipleGtags(gtagIds);
|
|
@@ -1642,18 +1849,106 @@ function GoogleAdsTracking(props) {
|
|
|
1642
1849
|
}
|
|
1643
1850
|
|
|
1644
1851
|
// src/factory.tsx
|
|
1852
|
+
import { createContext as createContext2, useContext as useContext2, useEffect as useEffect4, useMemo as useMemo3 } from "react";
|
|
1853
|
+
|
|
1854
|
+
// package.json
|
|
1855
|
+
var version = "0.12.1";
|
|
1856
|
+
|
|
1857
|
+
// ../tracking-core/src/phone-react.tsx
|
|
1645
1858
|
import {
|
|
1646
1859
|
createContext,
|
|
1860
|
+
forwardRef,
|
|
1861
|
+
useCallback as useCallback2,
|
|
1647
1862
|
useContext,
|
|
1648
|
-
|
|
1649
|
-
|
|
1863
|
+
useMemo as useMemo2,
|
|
1864
|
+
useState as useState3
|
|
1650
1865
|
} from "react";
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1866
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
1867
|
+
var _phoneConfigContext;
|
|
1868
|
+
function phoneConfigContext() {
|
|
1869
|
+
return _phoneConfigContext ?? (_phoneConfigContext = createContext(null));
|
|
1870
|
+
}
|
|
1871
|
+
function PhoneConfigProvider({
|
|
1872
|
+
value,
|
|
1873
|
+
children
|
|
1874
|
+
}) {
|
|
1875
|
+
const Ctx = phoneConfigContext();
|
|
1876
|
+
return /* @__PURE__ */ jsx2(Ctx.Provider, { value, children });
|
|
1877
|
+
}
|
|
1878
|
+
function usePhoneConfig() {
|
|
1879
|
+
const ctx = useContext(phoneConfigContext());
|
|
1880
|
+
return {
|
|
1881
|
+
defaultCountry: ctx?.defaultCountry ?? DEFAULT_PHONE_COUNTRY,
|
|
1882
|
+
display: ctx?.display ?? "national"
|
|
1883
|
+
};
|
|
1884
|
+
}
|
|
1885
|
+
function usePhoneField(opts = {}) {
|
|
1886
|
+
const cfg = usePhoneConfig();
|
|
1887
|
+
const country = opts.country ?? cfg.defaultCountry;
|
|
1888
|
+
const display = opts.display ?? cfg.display;
|
|
1889
|
+
const { onValueChange } = opts;
|
|
1890
|
+
const [value, setValue] = useState3(() => formatPhoneAsTyped(opts.defaultValue ?? "", country));
|
|
1891
|
+
const [touched, setTouched] = useState3(false);
|
|
1892
|
+
const parsed = useMemo2(() => parsePhone(value, country), [value, country]);
|
|
1893
|
+
const onChange = useCallback2(
|
|
1894
|
+
(event) => {
|
|
1895
|
+
const next = formatPhoneAsTyped(event.target.value, country);
|
|
1896
|
+
setValue(next);
|
|
1897
|
+
onValueChange?.(parsePhone(next, country).e164);
|
|
1898
|
+
},
|
|
1899
|
+
[country, onValueChange]
|
|
1900
|
+
);
|
|
1901
|
+
const onBlur = useCallback2(
|
|
1902
|
+
(_event) => {
|
|
1903
|
+
setTouched(true);
|
|
1904
|
+
setValue((current) => {
|
|
1905
|
+
const p = parsePhone(current, country);
|
|
1906
|
+
return p.isValid ? formatPhone(current, display, country) : current;
|
|
1907
|
+
});
|
|
1908
|
+
},
|
|
1909
|
+
[country, display]
|
|
1910
|
+
);
|
|
1911
|
+
const error = touched && value.length > 0 && !parsed.isValid ? "Enter a valid phone number" : null;
|
|
1912
|
+
return {
|
|
1913
|
+
value,
|
|
1914
|
+
e164: parsed.e164,
|
|
1915
|
+
isValid: parsed.isValid,
|
|
1916
|
+
error,
|
|
1917
|
+
parsed,
|
|
1918
|
+
inputProps: { value, onChange, onBlur, type: "tel", inputMode: "tel", autoComplete: "tel" }
|
|
1919
|
+
};
|
|
1920
|
+
}
|
|
1921
|
+
var PhoneField = forwardRef(function PhoneField2({ country, value, defaultValue, onChange, onE164Change, ...rest }, ref) {
|
|
1922
|
+
const cfg = usePhoneConfig();
|
|
1923
|
+
const resolvedCountry = country ?? cfg.defaultCountry;
|
|
1924
|
+
const isControlled = value !== void 0;
|
|
1925
|
+
const [internal, setInternal] = useState3(
|
|
1926
|
+
() => formatPhoneAsTyped(defaultValue ?? "", resolvedCountry)
|
|
1927
|
+
);
|
|
1928
|
+
const handleChange = (event) => {
|
|
1929
|
+
const formatted = formatPhoneAsTyped(event.target.value, resolvedCountry);
|
|
1930
|
+
event.target.value = formatted;
|
|
1931
|
+
onE164Change?.(parsePhone(formatted, resolvedCountry).e164);
|
|
1932
|
+
if (!isControlled) setInternal(formatted);
|
|
1933
|
+
onChange?.(event);
|
|
1934
|
+
};
|
|
1935
|
+
const shown = isControlled ? formatPhoneAsTyped(value, resolvedCountry) : internal;
|
|
1936
|
+
return /* @__PURE__ */ jsx2(
|
|
1937
|
+
"input",
|
|
1938
|
+
{
|
|
1939
|
+
...rest,
|
|
1940
|
+
ref,
|
|
1941
|
+
type: "tel",
|
|
1942
|
+
inputMode: "tel",
|
|
1943
|
+
autoComplete: "tel",
|
|
1944
|
+
value: shown,
|
|
1945
|
+
onChange: handleChange
|
|
1946
|
+
}
|
|
1947
|
+
);
|
|
1948
|
+
});
|
|
1654
1949
|
|
|
1655
1950
|
// src/factory.tsx
|
|
1656
|
-
import { jsx as
|
|
1951
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
1657
1952
|
var NOOP_CLIENT = {
|
|
1658
1953
|
trackEvent: () => {
|
|
1659
1954
|
},
|
|
@@ -1663,7 +1958,7 @@ var NOOP_CLIENT = {
|
|
|
1663
1958
|
getVisitorId: () => ""
|
|
1664
1959
|
};
|
|
1665
1960
|
function createTracking(options) {
|
|
1666
|
-
const { apiKey, endpoint, triggers, environment, debug } = options;
|
|
1961
|
+
const { apiKey, endpoint, triggers, environment, debug, phone } = options;
|
|
1667
1962
|
if (!apiKey || !endpoint) {
|
|
1668
1963
|
if (apiKey || endpoint) {
|
|
1669
1964
|
console.warn(
|
|
@@ -1672,14 +1967,16 @@ function createTracking(options) {
|
|
|
1672
1967
|
}
|
|
1673
1968
|
const noopTyped = NOOP_CLIENT;
|
|
1674
1969
|
return {
|
|
1675
|
-
|
|
1970
|
+
// Still publish phone config so usePhoneField/<PhoneField> work even when
|
|
1971
|
+
// tracking is disabled (missing apiKey/endpoint).
|
|
1972
|
+
TrackingProvider: ({ children }) => /* @__PURE__ */ jsx3(PhoneConfigProvider, { value: phone ?? null, children }),
|
|
1676
1973
|
useTracking: () => noopTyped
|
|
1677
1974
|
};
|
|
1678
1975
|
}
|
|
1679
|
-
const TrackingContext =
|
|
1976
|
+
const TrackingContext = createContext2(null);
|
|
1680
1977
|
function TrackingProvider({ gtagId, gtagIds, children }) {
|
|
1681
1978
|
const resolvedGtagIds = gtagIds ?? (gtagId ? { default: gtagId } : void 0);
|
|
1682
|
-
const client =
|
|
1979
|
+
const client = useMemo3(
|
|
1683
1980
|
() => createTypedClient(
|
|
1684
1981
|
getOrCreateTrackingClient({
|
|
1685
1982
|
apiKey,
|
|
@@ -1697,7 +1994,7 @@ function createTracking(options) {
|
|
|
1697
1994
|
),
|
|
1698
1995
|
[]
|
|
1699
1996
|
);
|
|
1700
|
-
const gtagIdsKey =
|
|
1997
|
+
const gtagIdsKey = useMemo3(() => gtagIds ? JSON.stringify(gtagIds) : "", [gtagIds]);
|
|
1701
1998
|
useEffect4(() => {
|
|
1702
1999
|
if (gtagIds && Object.keys(gtagIds).length > 0) {
|
|
1703
2000
|
bootstrapMultipleGtags(gtagIds);
|
|
@@ -1745,10 +2042,10 @@ function createTracking(options) {
|
|
|
1745
2042
|
}
|
|
1746
2043
|
};
|
|
1747
2044
|
}, []);
|
|
1748
|
-
return /* @__PURE__ */
|
|
2045
|
+
return /* @__PURE__ */ jsx3(TrackingContext.Provider, { value: client, children: /* @__PURE__ */ jsx3(PhoneConfigProvider, { value: phone ?? null, children }) });
|
|
1749
2046
|
}
|
|
1750
2047
|
function useTracking() {
|
|
1751
|
-
const client =
|
|
2048
|
+
const client = useContext2(TrackingContext);
|
|
1752
2049
|
if (client === null) {
|
|
1753
2050
|
throw new Error(
|
|
1754
2051
|
"useTracking must be called inside a <TrackingProvider> returned by createTracking()"
|
|
@@ -1761,8 +2058,13 @@ function createTracking(options) {
|
|
|
1761
2058
|
export {
|
|
1762
2059
|
AranovaApiError,
|
|
1763
2060
|
ConsentBanner,
|
|
2061
|
+
DEFAULT_PHONE_COUNTRY,
|
|
1764
2062
|
GoogleAdsTracking,
|
|
2063
|
+
NAMED_RANGES,
|
|
2064
|
+
PhoneField,
|
|
2065
|
+
SUPPORTED_CURRENCIES,
|
|
1765
2066
|
TRACKING_PARAM_KEYS,
|
|
2067
|
+
TRACKING_RANGES,
|
|
1766
2068
|
captureTrackingParamsFromLocation,
|
|
1767
2069
|
createSalesClient,
|
|
1768
2070
|
createTracking,
|
|
@@ -1770,15 +2072,28 @@ export {
|
|
|
1770
2072
|
createTrackingEventCreatePayload,
|
|
1771
2073
|
createTrackingSessionUpsertPayload,
|
|
1772
2074
|
fetchServices,
|
|
2075
|
+
formatDateInTz,
|
|
1773
2076
|
formatMoney,
|
|
2077
|
+
formatPhone,
|
|
2078
|
+
formatPhoneAsTyped,
|
|
1774
2079
|
fromMinor,
|
|
1775
2080
|
getConsentState,
|
|
2081
|
+
parsePhone,
|
|
2082
|
+
phoneField,
|
|
1776
2083
|
resetConsent,
|
|
2084
|
+
saleCreateSchema,
|
|
2085
|
+
saleItemSchema,
|
|
2086
|
+
saleServiceSchema,
|
|
2087
|
+
saleUpdateSchema,
|
|
2088
|
+
salesRequest,
|
|
1777
2089
|
setConsentState,
|
|
2090
|
+
toE164,
|
|
1778
2091
|
toMinor,
|
|
1779
2092
|
useConsent,
|
|
1780
2093
|
useConsentState,
|
|
1781
2094
|
useGclid,
|
|
2095
|
+
usePhoneConfig,
|
|
2096
|
+
usePhoneField,
|
|
1782
2097
|
useTrackingParams
|
|
1783
2098
|
};
|
|
1784
2099
|
//# sourceMappingURL=index.mjs.map
|