@aranova/tracking-react 0.13.0 → 0.14.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 +38 -0
- package/dist/index.d.mts +26 -14
- package/dist/index.d.ts +26 -14
- package/dist/index.js +398 -65
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +397 -65
- package/dist/index.mjs.map +1 -1
- package/dist/phone.js +73 -0
- package/dist/phone.js.map +1 -1
- package/dist/phone.mjs +73 -0
- package/dist/phone.mjs.map +1 -1
- package/dist/sales-BsJodmh0.d.mts +887 -0
- package/dist/sales-BsJodmh0.d.ts +887 -0
- package/dist/sales.d.mts +2 -784
- package/dist/sales.d.ts +2 -784
- package/dist/sales.js +172 -45
- package/dist/sales.js.map +1 -1
- package/dist/sales.mjs +172 -45
- package/dist/sales.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -7,6 +7,13 @@ import { useCallback, useEffect, useState } from "react";
|
|
|
7
7
|
// ../tracking-core/src/consent.ts
|
|
8
8
|
var CONSENT_STATE_KEY = "consent_state";
|
|
9
9
|
var CONSENT_TIMESTAMP_KEY = "consent_timestamp";
|
|
10
|
+
var grantedListeners = /* @__PURE__ */ new Set();
|
|
11
|
+
function onConsentGranted(listener) {
|
|
12
|
+
grantedListeners.add(listener);
|
|
13
|
+
return () => {
|
|
14
|
+
grantedListeners.delete(listener);
|
|
15
|
+
};
|
|
16
|
+
}
|
|
10
17
|
function buildConsentPayload(state) {
|
|
11
18
|
return {
|
|
12
19
|
ad_storage: state,
|
|
@@ -35,6 +42,14 @@ function setConsentState(state) {
|
|
|
35
42
|
window.gtag("consent", "update", buildConsentPayload(state));
|
|
36
43
|
if (typeof window.fbq === "function")
|
|
37
44
|
window.fbq("consent", state === "granted" ? "grant" : "revoke");
|
|
45
|
+
if (state === "granted") {
|
|
46
|
+
for (const listener of grantedListeners) {
|
|
47
|
+
try {
|
|
48
|
+
listener();
|
|
49
|
+
} catch {
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
38
53
|
}
|
|
39
54
|
function resetConsent() {
|
|
40
55
|
if (typeof window === "undefined") return;
|
|
@@ -170,6 +185,24 @@ function ensureGtagFunction() {
|
|
|
170
185
|
};
|
|
171
186
|
return window.gtag;
|
|
172
187
|
}
|
|
188
|
+
var SEND_TO_RE = /^AW-[A-Za-z0-9]+\/[A-Za-z0-9_-]+$/;
|
|
189
|
+
function isValidSendTo(sendTo) {
|
|
190
|
+
return SEND_TO_RE.test(sendTo);
|
|
191
|
+
}
|
|
192
|
+
function fireGtagConversion(input) {
|
|
193
|
+
if (typeof window === "undefined" || typeof window.gtag !== "function") return false;
|
|
194
|
+
if (!isValidSendTo(input.sendTo)) return false;
|
|
195
|
+
const params = { send_to: input.sendTo };
|
|
196
|
+
if (input.value != null) params.value = input.value;
|
|
197
|
+
if (input.currency) params.currency = input.currency;
|
|
198
|
+
if (input.transactionId) params.transaction_id = input.transactionId;
|
|
199
|
+
try {
|
|
200
|
+
window.gtag("event", "conversion", params);
|
|
201
|
+
return true;
|
|
202
|
+
} catch {
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
173
206
|
function applyDefaultConsentState() {
|
|
174
207
|
const gtag = ensureGtagFunction();
|
|
175
208
|
gtag("consent", "default", {
|
|
@@ -376,6 +409,289 @@ function createTrackingEventCreatePayload(trackingParams, input, context) {
|
|
|
376
409
|
};
|
|
377
410
|
}
|
|
378
411
|
|
|
412
|
+
// ../tracking-core/src/resources/conversion-firing.ts
|
|
413
|
+
var DEDUP_PREFIX = "_aranova_conv_";
|
|
414
|
+
var MAX_PENDING = 100;
|
|
415
|
+
var pendingQueue = [];
|
|
416
|
+
function dedupKey(input) {
|
|
417
|
+
return `${DEDUP_PREFIX}${input.transactionId ?? ""}:${input.sendTo}`;
|
|
418
|
+
}
|
|
419
|
+
function alreadyFired(input) {
|
|
420
|
+
if (!input.transactionId || typeof window === "undefined") return false;
|
|
421
|
+
try {
|
|
422
|
+
return window.sessionStorage.getItem(dedupKey(input)) !== null;
|
|
423
|
+
} catch {
|
|
424
|
+
return false;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
function markFired(input) {
|
|
428
|
+
if (!input.transactionId || typeof window === "undefined") return;
|
|
429
|
+
try {
|
|
430
|
+
window.sessionStorage.setItem(dedupKey(input), "1");
|
|
431
|
+
} catch {
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
function fireOnce(input) {
|
|
435
|
+
if (alreadyFired(input)) return;
|
|
436
|
+
if (fireGtagConversion(input)) markFired(input);
|
|
437
|
+
}
|
|
438
|
+
function fireConversionWithConsent(input) {
|
|
439
|
+
const state = getConsentState();
|
|
440
|
+
if (state === "denied") return;
|
|
441
|
+
if (state === "pending") {
|
|
442
|
+
if (pendingQueue.length >= MAX_PENDING) pendingQueue.shift();
|
|
443
|
+
pendingQueue.push(input);
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
fireOnce(input);
|
|
447
|
+
}
|
|
448
|
+
function flushPendingConversions() {
|
|
449
|
+
if (getConsentState() !== "granted") return;
|
|
450
|
+
while (pendingQueue.length > 0) {
|
|
451
|
+
const input = pendingQueue.shift();
|
|
452
|
+
if (input) fireOnce(input);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
if (typeof window !== "undefined") onConsentGranted(flushPendingConversions);
|
|
456
|
+
|
|
457
|
+
// ../tracking-core/src/resources/conversion-config.ts
|
|
458
|
+
function isStringMap(value) {
|
|
459
|
+
return typeof value === "object" && value !== null && Object.values(value).every((v) => typeof v === "string");
|
|
460
|
+
}
|
|
461
|
+
function parseFiring(value) {
|
|
462
|
+
if (!value || typeof value !== "object") return null;
|
|
463
|
+
const f = value;
|
|
464
|
+
if (typeof f.send_to !== "string") return null;
|
|
465
|
+
return {
|
|
466
|
+
send_to: f.send_to,
|
|
467
|
+
value_cents: typeof f.value_cents === "number" ? f.value_cents : null,
|
|
468
|
+
currency: typeof f.currency === "string" ? f.currency : null
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
function parseTrigger(value) {
|
|
472
|
+
if (!value || typeof value !== "object") return null;
|
|
473
|
+
const t = value;
|
|
474
|
+
if (typeof t.event_type !== "string") return null;
|
|
475
|
+
const spec = { event_type: t.event_type };
|
|
476
|
+
if (typeof t.threshold_percent === "number") spec.threshold_percent = t.threshold_percent;
|
|
477
|
+
if (typeof t.threshold_seconds === "number") spec.threshold_seconds = t.threshold_seconds;
|
|
478
|
+
if (typeof t.page_threshold === "number") spec.page_threshold = t.page_threshold;
|
|
479
|
+
if (typeof t.page_name === "string") spec.page_name = t.page_name;
|
|
480
|
+
return spec;
|
|
481
|
+
}
|
|
482
|
+
function parseConversionConfig(raw) {
|
|
483
|
+
if (!raw || typeof raw !== "object") return null;
|
|
484
|
+
const obj = raw;
|
|
485
|
+
const servicesRaw = Array.isArray(obj.services) ? obj.services : [];
|
|
486
|
+
const services = servicesRaw.flatMap((entry) => {
|
|
487
|
+
if (!entry || typeof entry !== "object") return [];
|
|
488
|
+
const s = entry;
|
|
489
|
+
if (typeof s.key !== "string") return [];
|
|
490
|
+
return [
|
|
491
|
+
{
|
|
492
|
+
key: s.key,
|
|
493
|
+
label: typeof s.label === "string" ? s.label : void 0,
|
|
494
|
+
firing: parseFiring(s.firing)
|
|
495
|
+
}
|
|
496
|
+
];
|
|
497
|
+
});
|
|
498
|
+
const goalsRaw = Array.isArray(obj.goals) ? obj.goals : null;
|
|
499
|
+
const goals = goalsRaw ? goalsRaw.flatMap((entry) => {
|
|
500
|
+
if (!entry || typeof entry !== "object") return [];
|
|
501
|
+
const g = entry;
|
|
502
|
+
if (typeof g.key !== "string") return [];
|
|
503
|
+
return [
|
|
504
|
+
{
|
|
505
|
+
key: g.key,
|
|
506
|
+
label: typeof g.label === "string" ? g.label : void 0,
|
|
507
|
+
kind: g.kind === "event" ? "event" : "sale",
|
|
508
|
+
trigger: parseTrigger(g.trigger),
|
|
509
|
+
firing: parseFiring(g.firing)
|
|
510
|
+
}
|
|
511
|
+
];
|
|
512
|
+
}) : services.map((s) => ({
|
|
513
|
+
key: s.key,
|
|
514
|
+
label: s.label,
|
|
515
|
+
kind: "sale",
|
|
516
|
+
trigger: null,
|
|
517
|
+
firing: s.firing
|
|
518
|
+
}));
|
|
519
|
+
return {
|
|
520
|
+
schema_version: typeof obj.schema_version === "number" ? obj.schema_version : 1,
|
|
521
|
+
config_version: typeof obj.config_version === "number" ? obj.config_version : 0,
|
|
522
|
+
business_id: typeof obj.business_id === "string" ? obj.business_id : void 0,
|
|
523
|
+
customer_id: typeof obj.customer_id === "string" ? obj.customer_id : null,
|
|
524
|
+
environment: typeof obj.environment === "string" ? obj.environment : void 0,
|
|
525
|
+
gtag_ids: isStringMap(obj.gtag_ids) ? obj.gtag_ids : {},
|
|
526
|
+
meta_pixel_ids: isStringMap(obj.meta_pixel_ids) ? obj.meta_pixel_ids : {},
|
|
527
|
+
services,
|
|
528
|
+
goals
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
var CACHE_PREFIX = "_aranova_cfg_";
|
|
532
|
+
function cacheKey(url) {
|
|
533
|
+
return `${CACHE_PREFIX}${url}`;
|
|
534
|
+
}
|
|
535
|
+
function readCache(url) {
|
|
536
|
+
if (typeof window === "undefined") return null;
|
|
537
|
+
try {
|
|
538
|
+
const raw = window.sessionStorage.getItem(cacheKey(url));
|
|
539
|
+
if (!raw) return null;
|
|
540
|
+
const parsed = JSON.parse(raw);
|
|
541
|
+
const config = parseConversionConfig(parsed.config);
|
|
542
|
+
if (!config) return null;
|
|
543
|
+
return {
|
|
544
|
+
etag: typeof parsed.etag === "string" ? parsed.etag : null,
|
|
545
|
+
config
|
|
546
|
+
};
|
|
547
|
+
} catch {
|
|
548
|
+
return null;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
function writeCache(url, entry) {
|
|
552
|
+
if (typeof window === "undefined") return;
|
|
553
|
+
try {
|
|
554
|
+
window.sessionStorage.setItem(cacheKey(url), JSON.stringify(entry));
|
|
555
|
+
} catch {
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
function resolveConversionConfig(options) {
|
|
559
|
+
const cached = readCache(options.cdnUrl);
|
|
560
|
+
let current = cached?.config ?? options.baked ?? null;
|
|
561
|
+
let etag = cached?.etag ?? null;
|
|
562
|
+
const goalsByKey = /* @__PURE__ */ new Map();
|
|
563
|
+
function rebuildIndex() {
|
|
564
|
+
goalsByKey.clear();
|
|
565
|
+
for (const goal of current?.goals ?? []) {
|
|
566
|
+
goalsByKey.set(goal.key, goal);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
function adopt(next, nextEtag) {
|
|
570
|
+
if (!next) return;
|
|
571
|
+
if (current && next.config_version <= current.config_version) return;
|
|
572
|
+
current = next;
|
|
573
|
+
etag = nextEtag;
|
|
574
|
+
rebuildIndex();
|
|
575
|
+
writeCache(options.cdnUrl, { etag, config: next });
|
|
576
|
+
}
|
|
577
|
+
async function revalidate() {
|
|
578
|
+
if (typeof window === "undefined") return;
|
|
579
|
+
try {
|
|
580
|
+
const doFetch = options.fetchImpl ?? globalThis.fetch;
|
|
581
|
+
if (!doFetch) return;
|
|
582
|
+
const headers = {};
|
|
583
|
+
if (etag) headers["If-None-Match"] = etag;
|
|
584
|
+
const response = await doFetch(options.cdnUrl, {
|
|
585
|
+
method: "GET",
|
|
586
|
+
headers
|
|
587
|
+
});
|
|
588
|
+
if (response.status === 304 || !response.ok) return;
|
|
589
|
+
adopt(parseConversionConfig(await response.json()), response.headers.get("ETag"));
|
|
590
|
+
} catch {
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
rebuildIndex();
|
|
594
|
+
void revalidate();
|
|
595
|
+
return {
|
|
596
|
+
getFiring: (key) => goalsByKey.get(key)?.firing ?? null,
|
|
597
|
+
getGoal: (key) => goalsByKey.get(key) ?? null,
|
|
598
|
+
listGoals: () => [...goalsByKey.values()],
|
|
599
|
+
current: () => current,
|
|
600
|
+
revalidate
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// ../tracking-core/src/resources/sales/money.ts
|
|
605
|
+
var MINOR_UNIT_EXPONENT = {
|
|
606
|
+
USD: 2,
|
|
607
|
+
CAD: 2
|
|
608
|
+
};
|
|
609
|
+
function exponentFor(currency) {
|
|
610
|
+
return MINOR_UNIT_EXPONENT[currency] ?? 2;
|
|
611
|
+
}
|
|
612
|
+
function toMinor(amount, currency) {
|
|
613
|
+
return Math.round(amount * 10 ** exponentFor(currency));
|
|
614
|
+
}
|
|
615
|
+
function fromMinor(cents, currency) {
|
|
616
|
+
return cents / 10 ** exponentFor(currency);
|
|
617
|
+
}
|
|
618
|
+
function formatMoney(cents, currency, locale) {
|
|
619
|
+
return new Intl.NumberFormat(locale, { style: "currency", currency }).format(
|
|
620
|
+
fromMinor(cents, currency)
|
|
621
|
+
);
|
|
622
|
+
}
|
|
623
|
+
function formatDateInTz(iso, timeZone, opts, locale) {
|
|
624
|
+
const date = new Date(iso);
|
|
625
|
+
if (Number.isNaN(date.getTime())) return iso;
|
|
626
|
+
return new Intl.DateTimeFormat(locale, {
|
|
627
|
+
year: "numeric",
|
|
628
|
+
month: "short",
|
|
629
|
+
day: "2-digit",
|
|
630
|
+
hour: "2-digit",
|
|
631
|
+
minute: "2-digit",
|
|
632
|
+
...opts,
|
|
633
|
+
timeZone
|
|
634
|
+
}).format(date);
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
// ../tracking-core/src/resources/conversion-autofire.ts
|
|
638
|
+
function thresholdMet(goal, eventType, metadata) {
|
|
639
|
+
const t = goal.trigger;
|
|
640
|
+
if (!t || t.event_type !== eventType) return false;
|
|
641
|
+
switch (eventType) {
|
|
642
|
+
case "scroll_depth":
|
|
643
|
+
return typeof metadata.depth_percent === "number" && t.threshold_percent != null && metadata.depth_percent >= t.threshold_percent;
|
|
644
|
+
case "time_on_site":
|
|
645
|
+
return typeof metadata.duration_ms === "number" && t.threshold_seconds != null && metadata.duration_ms >= t.threshold_seconds * 1e3;
|
|
646
|
+
case "multi_page_session":
|
|
647
|
+
return typeof metadata.page_count === "number" && t.page_threshold != null && metadata.page_count >= t.page_threshold;
|
|
648
|
+
case "specific_page_visit":
|
|
649
|
+
return typeof metadata.page_name === "string" && metadata.page_name === t.page_name;
|
|
650
|
+
case "page_view":
|
|
651
|
+
case "form_start":
|
|
652
|
+
return true;
|
|
653
|
+
// no threshold — fire whenever the detector emits
|
|
654
|
+
default:
|
|
655
|
+
return false;
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
function currentPath() {
|
|
659
|
+
return typeof window === "undefined" ? "" : window.location.pathname;
|
|
660
|
+
}
|
|
661
|
+
function createConversionAutoFire(store) {
|
|
662
|
+
return {
|
|
663
|
+
onAutomaticEvent(eventType, metadata) {
|
|
664
|
+
for (const goal of store.listGoals()) {
|
|
665
|
+
if (goal.kind !== "event" || !goal.firing) continue;
|
|
666
|
+
if (!thresholdMet(goal, eventType, metadata)) continue;
|
|
667
|
+
const firing = goal.firing;
|
|
668
|
+
const cents = firing.value_cents ?? null;
|
|
669
|
+
const currency = firing.currency ?? null;
|
|
670
|
+
fireConversionWithConsent({
|
|
671
|
+
sendTo: firing.send_to,
|
|
672
|
+
value: cents != null && currency ? fromMinor(cents, currency) : null,
|
|
673
|
+
currency,
|
|
674
|
+
// Page-scoped txn id → fire once per (goal, path) per session; engagement conversions
|
|
675
|
+
// shouldn't re-fire as the visitor scrolls back and forth or re-enters a page.
|
|
676
|
+
transactionId: `auto:${goal.key}:${currentPath()}`
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
function withConversionAutoFire(client, autoFire) {
|
|
683
|
+
return {
|
|
684
|
+
...client,
|
|
685
|
+
trackEvent: (input) => {
|
|
686
|
+
client.trackEvent(input);
|
|
687
|
+
try {
|
|
688
|
+
autoFire.onAutomaticEvent(input.eventType, input.metadata ?? {});
|
|
689
|
+
} catch {
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
|
|
379
695
|
// ../tracking-core/src/session.ts
|
|
380
696
|
var VISITOR_STORAGE_KEY = "aranova_tracking_visitor";
|
|
381
697
|
var SESSION_STORAGE_KEY = "aranova_tracking_session";
|
|
@@ -1195,7 +1511,7 @@ function attachScrollDepth(client, config) {
|
|
|
1195
1511
|
}
|
|
1196
1512
|
const thresholds = new Set(config.thresholds);
|
|
1197
1513
|
let firedForPath = /* @__PURE__ */ new Set();
|
|
1198
|
-
let
|
|
1514
|
+
let currentPath2 = window.location.pathname;
|
|
1199
1515
|
let rafId = null;
|
|
1200
1516
|
function getScrollPercent() {
|
|
1201
1517
|
const doc = document.documentElement;
|
|
@@ -1214,7 +1530,7 @@ function attachScrollDepth(client, config) {
|
|
|
1214
1530
|
eventType: "scroll_depth",
|
|
1215
1531
|
metadata: {
|
|
1216
1532
|
depth_percent: threshold,
|
|
1217
|
-
page: { path:
|
|
1533
|
+
page: { path: currentPath2 }
|
|
1218
1534
|
},
|
|
1219
1535
|
pageUrl: window.location.href,
|
|
1220
1536
|
occurredAt: null
|
|
@@ -1231,8 +1547,8 @@ function attachScrollDepth(client, config) {
|
|
|
1231
1547
|
}
|
|
1232
1548
|
function resetIfPathChanged() {
|
|
1233
1549
|
const newPath = window.location.pathname;
|
|
1234
|
-
if (newPath ===
|
|
1235
|
-
|
|
1550
|
+
if (newPath === currentPath2) return;
|
|
1551
|
+
currentPath2 = newPath;
|
|
1236
1552
|
firedForPath = /* @__PURE__ */ new Set();
|
|
1237
1553
|
setTimeout(checkThresholds, 0);
|
|
1238
1554
|
}
|
|
@@ -1308,13 +1624,13 @@ function attachMultiPageSession(client, config) {
|
|
|
1308
1624
|
return storage.getItem(FIRED_KEY) === "1";
|
|
1309
1625
|
}
|
|
1310
1626
|
function check() {
|
|
1311
|
-
const
|
|
1312
|
-
if (
|
|
1313
|
-
lastCheckedPath =
|
|
1627
|
+
const currentPath2 = window.location.pathname;
|
|
1628
|
+
if (currentPath2 === lastCheckedPath) return;
|
|
1629
|
+
lastCheckedPath = currentPath2;
|
|
1314
1630
|
resetIfSessionChanged();
|
|
1315
1631
|
if (hasFired()) return;
|
|
1316
1632
|
const paths = getDistinctPaths();
|
|
1317
|
-
paths.add(
|
|
1633
|
+
paths.add(currentPath2);
|
|
1318
1634
|
saveDistinctPaths(paths);
|
|
1319
1635
|
if (paths.size >= pageThreshold) {
|
|
1320
1636
|
storage.setItem(FIRED_KEY, "1");
|
|
@@ -1358,7 +1674,7 @@ function attachFormStart(client, config) {
|
|
|
1358
1674
|
}
|
|
1359
1675
|
const selector = config.selector ?? "form";
|
|
1360
1676
|
let firedForms = /* @__PURE__ */ new Set();
|
|
1361
|
-
let
|
|
1677
|
+
let currentPath2 = window.location.pathname;
|
|
1362
1678
|
function getFormKey(form) {
|
|
1363
1679
|
if (form.id) return `id:${form.id}`;
|
|
1364
1680
|
const explicitAction = form.getAttribute("action");
|
|
@@ -1389,8 +1705,8 @@ function attachFormStart(client, config) {
|
|
|
1389
1705
|
}
|
|
1390
1706
|
function resetIfPathChanged() {
|
|
1391
1707
|
const newPath = window.location.pathname;
|
|
1392
|
-
if (newPath ===
|
|
1393
|
-
|
|
1708
|
+
if (newPath === currentPath2) return;
|
|
1709
|
+
currentPath2 = newPath;
|
|
1394
1710
|
firedForms = /* @__PURE__ */ new Set();
|
|
1395
1711
|
}
|
|
1396
1712
|
const originalPushState = history.pushState.bind(history);
|
|
@@ -1469,21 +1785,64 @@ async function salesRequest(config, method, path, body) {
|
|
|
1469
1785
|
}
|
|
1470
1786
|
|
|
1471
1787
|
// ../tracking-core/src/resources/sales/client.ts
|
|
1788
|
+
function fireRecordedConversions(firing, input, recorded, sale, currency) {
|
|
1789
|
+
if (!firing) return;
|
|
1790
|
+
const txnBase = input.external_id ?? sale.id;
|
|
1791
|
+
for (const item of recorded) {
|
|
1792
|
+
if (!item.service) continue;
|
|
1793
|
+
const config = firing.getFiring(item.service);
|
|
1794
|
+
if (!config) continue;
|
|
1795
|
+
const cents = item.amount_cents ?? config.value_cents ?? null;
|
|
1796
|
+
fireConversionWithConsent({
|
|
1797
|
+
sendTo: config.send_to,
|
|
1798
|
+
value: cents != null ? fromMinor(cents, currency) : null,
|
|
1799
|
+
currency: config.currency ?? currency,
|
|
1800
|
+
transactionId: `${txnBase}:${item.service}`
|
|
1801
|
+
});
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1472
1804
|
function createSalesClient(config) {
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1805
|
+
async function record(input) {
|
|
1806
|
+
const currency = input.currency ?? config.defaultCurrency;
|
|
1807
|
+
if (!currency) {
|
|
1808
|
+
throw new Error(
|
|
1809
|
+
"record: `currency` is required (pass it on the sale or set config.defaultCurrency)"
|
|
1810
|
+
);
|
|
1811
|
+
}
|
|
1812
|
+
const body = {
|
|
1813
|
+
...input,
|
|
1814
|
+
currency,
|
|
1815
|
+
occurred_at: input.occurred_at ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
1816
|
+
};
|
|
1817
|
+
const sale = await salesRequest(config, "POST", "/sales", body);
|
|
1818
|
+
const recorded = input.services?.length ? input.services.map((s) => ({
|
|
1819
|
+
service: s.service,
|
|
1820
|
+
amount_cents: s.amount_cents
|
|
1821
|
+
})) : [
|
|
1822
|
+
{
|
|
1823
|
+
service: input.service,
|
|
1824
|
+
amount_cents: input.amount_total_cents ?? null
|
|
1480
1825
|
}
|
|
1481
|
-
|
|
1482
|
-
|
|
1826
|
+
];
|
|
1827
|
+
fireRecordedConversions(config.firing, input, recorded, sale, currency);
|
|
1828
|
+
return sale;
|
|
1829
|
+
}
|
|
1830
|
+
return {
|
|
1831
|
+
record,
|
|
1832
|
+
// recordSale is the intent-revealing alias — same behavior, clearer call site.
|
|
1833
|
+
recordSale: record,
|
|
1834
|
+
trackConversion(key, options) {
|
|
1835
|
+
const firing = config.firing?.getFiring(key);
|
|
1836
|
+
if (!firing) return;
|
|
1837
|
+
const currency = firing.currency ?? options?.currency ?? config.defaultCurrency ?? null;
|
|
1838
|
+
const cents = firing.value_cents ?? null;
|
|
1839
|
+
const value = options?.value ?? (cents != null && currency ? fromMinor(cents, currency) : null);
|
|
1840
|
+
fireConversionWithConsent({
|
|
1841
|
+
sendTo: firing.send_to,
|
|
1842
|
+
value,
|
|
1483
1843
|
currency,
|
|
1484
|
-
|
|
1485
|
-
};
|
|
1486
|
-
return salesRequest(config, "POST", "/sales", body);
|
|
1844
|
+
transactionId: options?.transactionId ?? null
|
|
1845
|
+
});
|
|
1487
1846
|
},
|
|
1488
1847
|
async list(query) {
|
|
1489
1848
|
const { cursor, limit, sort, order, want_total, ...filters } = query ?? {};
|
|
@@ -1577,39 +1936,6 @@ function createSalesClient(config) {
|
|
|
1577
1936
|
};
|
|
1578
1937
|
}
|
|
1579
1938
|
|
|
1580
|
-
// ../tracking-core/src/resources/sales/money.ts
|
|
1581
|
-
var MINOR_UNIT_EXPONENT = {
|
|
1582
|
-
USD: 2,
|
|
1583
|
-
CAD: 2
|
|
1584
|
-
};
|
|
1585
|
-
function exponentFor(currency) {
|
|
1586
|
-
return MINOR_UNIT_EXPONENT[currency] ?? 2;
|
|
1587
|
-
}
|
|
1588
|
-
function toMinor(amount, currency) {
|
|
1589
|
-
return Math.round(amount * 10 ** exponentFor(currency));
|
|
1590
|
-
}
|
|
1591
|
-
function fromMinor(cents, currency) {
|
|
1592
|
-
return cents / 10 ** exponentFor(currency);
|
|
1593
|
-
}
|
|
1594
|
-
function formatMoney(cents, currency, locale) {
|
|
1595
|
-
return new Intl.NumberFormat(locale, { style: "currency", currency }).format(
|
|
1596
|
-
fromMinor(cents, currency)
|
|
1597
|
-
);
|
|
1598
|
-
}
|
|
1599
|
-
function formatDateInTz(iso, timeZone, opts, locale) {
|
|
1600
|
-
const date = new Date(iso);
|
|
1601
|
-
if (Number.isNaN(date.getTime())) return iso;
|
|
1602
|
-
return new Intl.DateTimeFormat(locale, {
|
|
1603
|
-
year: "numeric",
|
|
1604
|
-
month: "short",
|
|
1605
|
-
day: "2-digit",
|
|
1606
|
-
hour: "2-digit",
|
|
1607
|
-
minute: "2-digit",
|
|
1608
|
-
...opts,
|
|
1609
|
-
timeZone
|
|
1610
|
-
}).format(date);
|
|
1611
|
-
}
|
|
1612
|
-
|
|
1613
1939
|
// ../tracking-core/src/resources/sales/schema.ts
|
|
1614
1940
|
import { z as z11 } from "zod";
|
|
1615
1941
|
var SUPPORTED_CURRENCIES = ["USD", "CAD"];
|
|
@@ -2057,7 +2383,7 @@ function GoogleAdsTracking(props) {
|
|
|
2057
2383
|
import { createContext as createContext2, useContext as useContext2, useEffect as useEffect5, useMemo as useMemo4 } from "react";
|
|
2058
2384
|
|
|
2059
2385
|
// package.json
|
|
2060
|
-
var version = "0.
|
|
2386
|
+
var version = "0.14.0";
|
|
2061
2387
|
|
|
2062
2388
|
// ../tracking-core/src/phone-react.tsx
|
|
2063
2389
|
import {
|
|
@@ -2163,7 +2489,7 @@ var NOOP_CLIENT = {
|
|
|
2163
2489
|
getVisitorId: () => ""
|
|
2164
2490
|
};
|
|
2165
2491
|
function createTracking(options) {
|
|
2166
|
-
const { apiKey, endpoint, triggers, environment, debug, phone } = options;
|
|
2492
|
+
const { apiKey, endpoint, triggers, environment, debug, phone, conversionConfig } = options;
|
|
2167
2493
|
if (!apiKey || !endpoint) {
|
|
2168
2494
|
if (apiKey || endpoint) {
|
|
2169
2495
|
console.warn(
|
|
@@ -2238,27 +2564,32 @@ function createTracking(options) {
|
|
|
2238
2564
|
activeGtagIds: resolvedGtagIds,
|
|
2239
2565
|
debug
|
|
2240
2566
|
});
|
|
2241
|
-
|
|
2242
|
-
|
|
2567
|
+
const conversionStore = conversionConfig ? resolveConversionConfig({
|
|
2568
|
+
cdnUrl: conversionConfig.cdnUrl,
|
|
2569
|
+
baked: conversionConfig.baked
|
|
2570
|
+
}) : null;
|
|
2571
|
+
const detectorClient = conversionStore ? withConversionAutoFire(rawClient, createConversionAutoFire(conversionStore)) : rawClient;
|
|
2572
|
+
detachers.push(attachAutoPageView(detectorClient));
|
|
2573
|
+
detachers.push(attachBfcacheRestore(detectorClient));
|
|
2243
2574
|
const timeOnSite = triggers.automatic.time_on_site;
|
|
2244
2575
|
if (timeOnSite) {
|
|
2245
|
-
detachers.push(attachTimeOnSite(
|
|
2576
|
+
detachers.push(attachTimeOnSite(detectorClient, timeOnSite));
|
|
2246
2577
|
}
|
|
2247
2578
|
const specificPageVisit = triggers.automatic.specific_page_visit;
|
|
2248
2579
|
if (specificPageVisit) {
|
|
2249
|
-
detachers.push(attachSpecificPageVisit(
|
|
2580
|
+
detachers.push(attachSpecificPageVisit(detectorClient, specificPageVisit));
|
|
2250
2581
|
}
|
|
2251
2582
|
const scrollDepth = triggers.automatic.scroll_depth;
|
|
2252
2583
|
if (scrollDepth) {
|
|
2253
|
-
detachers.push(attachScrollDepth(
|
|
2584
|
+
detachers.push(attachScrollDepth(detectorClient, scrollDepth));
|
|
2254
2585
|
}
|
|
2255
2586
|
const multiPageSession = triggers.automatic.multi_page_session;
|
|
2256
2587
|
if (multiPageSession) {
|
|
2257
|
-
detachers.push(attachMultiPageSession(
|
|
2588
|
+
detachers.push(attachMultiPageSession(detectorClient, multiPageSession));
|
|
2258
2589
|
}
|
|
2259
2590
|
const formStart = triggers.automatic.form_start;
|
|
2260
2591
|
if (formStart) {
|
|
2261
|
-
detachers.push(attachFormStart(
|
|
2592
|
+
detachers.push(attachFormStart(detectorClient, formStart));
|
|
2262
2593
|
}
|
|
2263
2594
|
return () => {
|
|
2264
2595
|
for (let i = detachers.length - 1; i >= 0; i--) {
|
|
@@ -2306,6 +2637,7 @@ export {
|
|
|
2306
2637
|
parsePhone,
|
|
2307
2638
|
phoneField,
|
|
2308
2639
|
resetConsent,
|
|
2640
|
+
resolveConversionConfig,
|
|
2309
2641
|
saleCreateSchema,
|
|
2310
2642
|
saleItemSchema,
|
|
2311
2643
|
saleServiceSchema,
|