@aranova/tracking-next 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/dist/index.js CHANGED
@@ -32,8 +32,13 @@ var src_exports = {};
32
32
  __export(src_exports, {
33
33
  AranovaApiError: () => AranovaApiError,
34
34
  ConsentBanner: () => ConsentBanner,
35
+ DEFAULT_PHONE_COUNTRY: () => DEFAULT_PHONE_COUNTRY,
35
36
  GoogleAdsTracking: () => GoogleAdsTracking,
37
+ NAMED_RANGES: () => NAMED_RANGES,
38
+ PhoneField: () => PhoneField,
39
+ SUPPORTED_CURRENCIES: () => SUPPORTED_CURRENCIES,
36
40
  TRACKING_PARAM_KEYS: () => TRACKING_PARAM_KEYS,
41
+ TRACKING_RANGES: () => TRACKING_RANGES,
37
42
  captureTrackingParamsFromLocation: () => captureTrackingParamsFromLocation,
38
43
  createSalesClient: () => createSalesClient,
39
44
  createTracking: () => createTracking,
@@ -41,15 +46,28 @@ __export(src_exports, {
41
46
  createTrackingEventCreatePayload: () => createTrackingEventCreatePayload,
42
47
  createTrackingSessionUpsertPayload: () => createTrackingSessionUpsertPayload,
43
48
  fetchServices: () => fetchServices,
49
+ formatDateInTz: () => formatDateInTz,
44
50
  formatMoney: () => formatMoney,
51
+ formatPhone: () => formatPhone,
52
+ formatPhoneAsTyped: () => formatPhoneAsTyped,
45
53
  fromMinor: () => fromMinor,
46
54
  getConsentState: () => getConsentState,
55
+ parsePhone: () => parsePhone,
56
+ phoneField: () => phoneField,
47
57
  resetConsent: () => resetConsent,
58
+ saleCreateSchema: () => saleCreateSchema,
59
+ saleItemSchema: () => saleItemSchema,
60
+ saleServiceSchema: () => saleServiceSchema,
61
+ saleUpdateSchema: () => saleUpdateSchema,
62
+ salesRequest: () => salesRequest,
48
63
  setConsentState: () => setConsentState,
64
+ toE164: () => toE164,
49
65
  toMinor: () => toMinor,
50
66
  useConsent: () => useConsent,
51
67
  useConsentState: () => useConsentState,
52
68
  useGclid: () => useGclid,
69
+ usePhoneConfig: () => usePhoneConfig,
70
+ usePhoneField: () => usePhoneField,
53
71
  useTrackingParams: () => useTrackingParams
54
72
  });
55
73
  module.exports = __toCommonJS(src_exports);
@@ -66,24 +84,20 @@ function buildConsentPayload(state) {
66
84
  };
67
85
  }
68
86
  function getConsentState() {
69
- if (typeof window === "undefined")
70
- return "pending";
87
+ if (typeof window === "undefined") return "pending";
71
88
  const storedState = window.localStorage.getItem(CONSENT_STATE_KEY);
72
- if (storedState === "granted" || storedState === "denied")
73
- return storedState;
89
+ if (storedState === "granted" || storedState === "denied") return storedState;
74
90
  return "pending";
75
91
  }
76
92
  function setConsentState(state) {
77
- if (typeof window === "undefined")
78
- return;
93
+ if (typeof window === "undefined") return;
79
94
  window.localStorage.setItem(CONSENT_STATE_KEY, state);
80
95
  window.localStorage.setItem(CONSENT_TIMESTAMP_KEY, (/* @__PURE__ */ new Date()).toISOString());
81
96
  if (typeof window.gtag === "function")
82
97
  window.gtag("consent", "update", buildConsentPayload(state));
83
98
  }
84
99
  function resetConsent() {
85
- if (typeof window === "undefined")
86
- return;
100
+ if (typeof window === "undefined") return;
87
101
  window.localStorage.removeItem(CONSENT_STATE_KEY);
88
102
  window.localStorage.removeItem(CONSENT_TIMESTAMP_KEY);
89
103
  }
@@ -224,18 +238,15 @@ function getTrackingQueryValues(searchParams) {
224
238
  }, {});
225
239
  }
226
240
  function getCookieValueFromDocument(key) {
227
- if (typeof document === "undefined")
228
- return null;
241
+ if (typeof document === "undefined") return null;
229
242
  const cookies = document.cookie ? document.cookie.split("; ") : [];
230
243
  const match = cookies.find((cookie) => cookie.startsWith(`${key}=`));
231
- if (!match)
232
- return null;
244
+ if (!match) return null;
233
245
  const [, rawValue = ""] = match.split("=");
234
246
  return normalizeTrackingCookieValue(decodeURIComponent(rawValue));
235
247
  }
236
248
  function setTrackingCookie(key, value, maxAgeSeconds = TRACKING_COOKIE_MAX_AGE_SECONDS) {
237
- if (typeof document === "undefined")
238
- return;
249
+ if (typeof document === "undefined") return;
239
250
  const encodedValue = encodeURIComponent(value);
240
251
  document.cookie = `${key}=${encodedValue}; Max-Age=${maxAgeSeconds}; Path=/; SameSite=Lax`;
241
252
  }
@@ -275,18 +286,15 @@ function writeLocalStorage(key, value) {
275
286
  }
276
287
  }
277
288
  function getVisitorId() {
278
- if (typeof window === "undefined")
279
- return safeUuid();
289
+ if (typeof window === "undefined") return safeUuid();
280
290
  const existing = readLocalStorage(VISITOR_STORAGE_KEY);
281
- if (existing && existing.length > 0)
282
- return existing;
291
+ if (existing && existing.length > 0) return existing;
283
292
  const fresh = safeUuid();
284
293
  writeLocalStorage(VISITOR_STORAGE_KEY, fresh);
285
294
  return fresh;
286
295
  }
287
296
  function getOrRotateSessionId(now = Date.now()) {
288
- if (typeof window === "undefined")
289
- return { id: safeUuid(), isNew: true };
297
+ if (typeof window === "undefined") return { id: safeUuid(), isNew: true };
290
298
  const raw = readLocalStorage(SESSION_STORAGE_KEY);
291
299
  if (raw) {
292
300
  try {
@@ -359,8 +367,7 @@ function setLastFiredUrl(url) {
359
367
  writeSessionStorage(LAST_FIRED_URL_STORAGE_KEY, url);
360
368
  }
361
369
  function buildPageViewMetadata(referrerOverride) {
362
- if (typeof window === "undefined" || typeof document === "undefined")
363
- return null;
370
+ if (typeof window === "undefined" || typeof document === "undefined") return null;
364
371
  return pageViewMetadataSchema.parse({
365
372
  page: {
366
373
  title: document.title || null,
@@ -373,8 +380,7 @@ function buildPageViewMetadata(referrerOverride) {
373
380
  });
374
381
  }
375
382
  function fireManualPageView(client) {
376
- if (typeof window === "undefined")
377
- return;
383
+ if (typeof window === "undefined") return;
378
384
  const currentHref = window.location.href;
379
385
  const previousFiredUrl = getLastFiredUrl();
380
386
  const internalReferrer = previousFiredUrl !== null && previousFiredUrl !== currentHref ? previousFiredUrl : null;
@@ -476,8 +482,7 @@ function buildContext(surface, sdkVersion, packageName, environment, activeGtagI
476
482
  };
477
483
  }
478
484
  function readTrackingParams() {
479
- if (typeof window === "undefined")
480
- return createEmptyTrackingParams();
485
+ if (typeof window === "undefined") return createEmptyTrackingParams();
481
486
  try {
482
487
  captureTrackingParamsFromLocation();
483
488
  } catch {
@@ -492,8 +497,7 @@ function consentSnapshot() {
492
497
  }
493
498
  }
494
499
  async function postWithFetch(url, body, apiKey, identity, keepalive) {
495
- if (typeof fetch !== "function")
496
- return;
500
+ if (typeof fetch !== "function") return;
497
501
  try {
498
502
  await fetch(url, {
499
503
  method: "POST",
@@ -553,8 +557,7 @@ function createTrackingClient(config) {
553
557
  const visitorId = getVisitorId();
554
558
  const initialSession = getOrRotateSessionId();
555
559
  let sessionId = initialSession.id;
556
- if (typeof window !== "undefined")
557
- firstPage = window.location.href;
560
+ if (typeof window !== "undefined") firstPage = window.location.href;
558
561
  function enqueueHeartbeat() {
559
562
  const metadata = buildHeartbeatMetadata(
560
563
  config.surface,
@@ -580,7 +583,13 @@ function createTrackingClient(config) {
580
583
  }
581
584
  sessionId = rotated.id;
582
585
  const params = readTrackingParams();
583
- const context = buildContext(config.surface, sdkVersion, packageName, environment, activeGtagIds);
586
+ const context = buildContext(
587
+ config.surface,
588
+ sdkVersion,
589
+ packageName,
590
+ environment,
591
+ activeGtagIds
592
+ );
584
593
  return {
585
594
  session_id: sessionId,
586
595
  visitor_id: visitorId,
@@ -597,8 +606,7 @@ function createTrackingClient(config) {
597
606
  };
598
607
  }
599
608
  function scheduleFlush() {
600
- if (flushTimer !== null || destroyed)
601
- return;
609
+ if (flushTimer !== null || destroyed) return;
602
610
  flushTimer = setTimeout(() => {
603
611
  flushTimer = null;
604
612
  void flush();
@@ -611,8 +619,7 @@ function createTrackingClient(config) {
611
619
  }
612
620
  }
613
621
  async function flush() {
614
- if (queue.length === 0)
615
- return;
622
+ if (queue.length === 0) return;
616
623
  const events = queue.slice(0, HARD_MAX_BATCH);
617
624
  queue = queue.slice(events.length);
618
625
  clearScheduledFlush();
@@ -624,10 +631,8 @@ function createTrackingClient(config) {
624
631
  await postWithFetch(eventsUrl, serialized, config.apiKey, identityHeaders2, false);
625
632
  }
626
633
  function trackEvent(input) {
627
- if (destroyed)
628
- return;
629
- if (!input || typeof input.eventType !== "string" || input.eventType.length === 0)
630
- return;
634
+ if (destroyed) return;
635
+ if (!input || typeof input.eventType !== "string" || input.eventType.length === 0) return;
631
636
  const occurredAt = input.occurredAt instanceof Date ? input.occurredAt.toISOString() : typeof input.occurredAt === "string" ? input.occurredAt : (/* @__PURE__ */ new Date()).toISOString();
632
637
  queue.push({
633
638
  event_type: input.eventType,
@@ -642,8 +647,7 @@ function createTrackingClient(config) {
642
647
  }
643
648
  }
644
649
  function flushOnUnload() {
645
- if (queue.length === 0)
646
- return;
650
+ if (queue.length === 0) return;
647
651
  const events = queue.slice(0, HARD_MAX_BATCH);
648
652
  queue = queue.slice(events.length);
649
653
  clearScheduledFlush();
@@ -1183,21 +1187,40 @@ function createSalesClient(config) {
1183
1187
  return salesRequest(config, "POST", "/sales", body);
1184
1188
  },
1185
1189
  async list(query) {
1186
- const { cursor, limit, ...filters } = query ?? {};
1190
+ const { cursor, limit, sort, order, want_total, ...filters } = query ?? {};
1187
1191
  return salesRequest(config, "POST", "/sales/query", {
1188
1192
  filters,
1189
1193
  ...limit !== void 0 ? { limit } : {},
1190
- ...cursor !== void 0 ? { cursor } : {}
1194
+ ...cursor !== void 0 ? { cursor } : {},
1195
+ ...sort !== void 0 ? { sort } : {},
1196
+ ...order !== void 0 ? { order } : {},
1197
+ ...want_total !== void 0 ? { want_total } : {}
1191
1198
  });
1192
1199
  },
1193
1200
  async summary(query) {
1194
- const { range, include_categories, include_deleted_services, top_n, ...filters } = query;
1201
+ const {
1202
+ range,
1203
+ include_categories,
1204
+ include_deleted_services,
1205
+ top_n,
1206
+ since,
1207
+ until,
1208
+ timezone,
1209
+ granularity,
1210
+ compare_to,
1211
+ ...filters
1212
+ } = query;
1195
1213
  return salesRequest(config, "POST", "/sales/summary", {
1196
1214
  filters,
1197
- range,
1215
+ ...range !== void 0 ? { range } : {},
1198
1216
  ...include_categories !== void 0 ? { include_categories } : {},
1199
1217
  ...include_deleted_services !== void 0 ? { include_deleted_services } : {},
1200
- ...top_n !== void 0 ? { top_n } : {}
1218
+ ...top_n !== void 0 ? { top_n } : {},
1219
+ ...since !== void 0 ? { since } : {},
1220
+ ...until !== void 0 ? { until } : {},
1221
+ ...timezone !== void 0 ? { timezone } : {},
1222
+ ...granularity !== void 0 ? { granularity } : {},
1223
+ ...compare_to !== void 0 ? { compare_to } : {}
1201
1224
  });
1202
1225
  },
1203
1226
  async get(id) {
@@ -1208,15 +1231,53 @@ function createSalesClient(config) {
1208
1231
  },
1209
1232
  async delete(id) {
1210
1233
  await salesRequest(config, "DELETE", `/sales/${id}`);
1234
+ },
1235
+ customers: {
1236
+ async list(query) {
1237
+ const { segment, sort, order, cursor, limit, want_total, ...filters } = query ?? {};
1238
+ return salesRequest(config, "POST", "/customers/query", {
1239
+ filters,
1240
+ ...segment !== void 0 ? { segment } : {},
1241
+ ...sort !== void 0 ? { sort } : {},
1242
+ ...order !== void 0 ? { order } : {},
1243
+ ...cursor !== void 0 ? { cursor } : {},
1244
+ ...limit !== void 0 ? { limit } : {},
1245
+ ...want_total !== void 0 ? { want_total } : {}
1246
+ });
1247
+ },
1248
+ async get(id, options) {
1249
+ const params = new URLSearchParams();
1250
+ if (options?.include_sales !== void 0)
1251
+ params.set("include_sales", String(options.include_sales));
1252
+ if (options?.limit !== void 0) params.set("limit", String(options.limit));
1253
+ if (options?.cursor != null) params.set("cursor", options.cursor);
1254
+ const qs = params.toString();
1255
+ return salesRequest(
1256
+ config,
1257
+ "GET",
1258
+ `/customers/${encodeURIComponent(id)}${qs ? `?${qs}` : ""}`
1259
+ );
1260
+ },
1261
+ async summary(query) {
1262
+ const { range, since, until, timezone, compare_to, ...filters } = query ?? {};
1263
+ return salesRequest(config, "POST", "/customers/summary", {
1264
+ filters,
1265
+ ...range !== void 0 ? { range } : {},
1266
+ ...since !== void 0 ? { since } : {},
1267
+ ...until !== void 0 ? { until } : {},
1268
+ ...timezone !== void 0 ? { timezone } : {},
1269
+ ...compare_to !== void 0 ? { compare_to } : {}
1270
+ });
1271
+ }
1272
+ },
1273
+ business: {
1274
+ async config() {
1275
+ return salesRequest(config, "GET", "/business/config");
1276
+ }
1211
1277
  }
1212
1278
  };
1213
1279
  }
1214
1280
 
1215
- // ../tracking-core/src/resources/services.ts
1216
- async function fetchServices(config) {
1217
- return salesRequest(config, "GET", "/services");
1218
- }
1219
-
1220
1281
  // ../tracking-core/src/resources/sales/money.ts
1221
1282
  var MINOR_UNIT_EXPONENT = {
1222
1283
  USD: 2,
@@ -1236,6 +1297,181 @@ function formatMoney(cents, currency, locale) {
1236
1297
  fromMinor(cents, currency)
1237
1298
  );
1238
1299
  }
1300
+ function formatDateInTz(iso, timeZone, opts, locale) {
1301
+ const date = new Date(iso);
1302
+ if (Number.isNaN(date.getTime())) return iso;
1303
+ return new Intl.DateTimeFormat(locale, {
1304
+ year: "numeric",
1305
+ month: "short",
1306
+ day: "2-digit",
1307
+ hour: "2-digit",
1308
+ minute: "2-digit",
1309
+ ...opts,
1310
+ timeZone
1311
+ }).format(date);
1312
+ }
1313
+
1314
+ // ../tracking-core/src/resources/sales/schema.ts
1315
+ var import_zod11 = require("zod");
1316
+ var SUPPORTED_CURRENCIES = ["USD", "CAD"];
1317
+ var TRACKING_ENVIRONMENTS = ["production", "development"];
1318
+ var currencySchema = import_zod11.z.enum(SUPPORTED_CURRENCIES);
1319
+ var centsSchema = import_zod11.z.number().int().nonnegative();
1320
+ var quantitySchema = import_zod11.z.string().regex(/^\d+(\.\d{1,3})?$/);
1321
+ var metadataSchema = import_zod11.z.record(import_zod11.z.unknown());
1322
+ var saleItemSchema = import_zod11.z.object({
1323
+ external_item_id: import_zod11.z.string().nullable().optional(),
1324
+ name: import_zod11.z.string().nullable().optional(),
1325
+ category: import_zod11.z.string().nullable().optional(),
1326
+ quantity: quantitySchema,
1327
+ unit_price_cents: centsSchema,
1328
+ // Non-negativity validated on the wire — same contract as the other cents
1329
+ // fields — and backstopped by the DB CHECK.
1330
+ unit_cost_cents: centsSchema.nullable().optional()
1331
+ }).strict();
1332
+ var saleServiceSchema = import_zod11.z.object({
1333
+ service: import_zod11.z.string(),
1334
+ amount_cents: centsSchema
1335
+ }).strict();
1336
+ var customerNameSchema = import_zod11.z.string().max(200);
1337
+ var customerPhoneSchema = import_zod11.z.string().max(64);
1338
+ var customerEmailSchema = import_zod11.z.string().max(320).email();
1339
+ function refineServiceXor(val, ctx, { requireAmount }) {
1340
+ if (val.services != null) {
1341
+ if (val.service != null) {
1342
+ ctx.addIssue({
1343
+ code: import_zod11.z.ZodIssueCode.custom,
1344
+ message: "pass either `service` or `services`, not both",
1345
+ path: ["services"]
1346
+ });
1347
+ }
1348
+ if (val.services.length === 0) {
1349
+ ctx.addIssue({
1350
+ code: import_zod11.z.ZodIssueCode.custom,
1351
+ message: "`services` must not be empty",
1352
+ path: ["services"]
1353
+ });
1354
+ }
1355
+ const keys = val.services.map((s) => s.service);
1356
+ if (new Set(keys).size !== keys.length) {
1357
+ ctx.addIssue({
1358
+ code: import_zod11.z.ZodIssueCode.custom,
1359
+ message: "`services` must not list the same service more than once",
1360
+ path: ["services"]
1361
+ });
1362
+ }
1363
+ if (val.amount_total_cents != null) {
1364
+ const sum = val.services.reduce((acc, s) => acc + s.amount_cents, 0);
1365
+ if (val.amount_total_cents !== sum) {
1366
+ ctx.addIssue({
1367
+ code: import_zod11.z.ZodIssueCode.custom,
1368
+ message: "amount_total_cents must equal the sum of the services amounts (omit it to derive it automatically)",
1369
+ path: ["amount_total_cents"]
1370
+ });
1371
+ }
1372
+ }
1373
+ } else if (requireAmount && val.amount_total_cents == null) {
1374
+ ctx.addIssue({
1375
+ code: import_zod11.z.ZodIssueCode.custom,
1376
+ message: "amount_total_cents is required unless `services` is provided",
1377
+ path: ["amount_total_cents"]
1378
+ });
1379
+ }
1380
+ }
1381
+ var saleCreateSchema = import_zod11.z.object({
1382
+ external_id: import_zod11.z.string().nullable().optional(),
1383
+ description: import_zod11.z.string().nullable().optional(),
1384
+ service: import_zod11.z.string().nullable().optional(),
1385
+ services: import_zod11.z.array(saleServiceSchema).nullable().optional(),
1386
+ currency: currencySchema,
1387
+ // Optional only because the plural `services` form derives it from the sum
1388
+ // (see refineServiceXor); the singular/serviceless path still requires it.
1389
+ amount_total_cents: centsSchema.nullable().optional(),
1390
+ occurred_at: import_zod11.z.string().datetime(),
1391
+ environment: import_zod11.z.enum(TRACKING_ENVIRONMENTS).default("production"),
1392
+ items: import_zod11.z.array(saleItemSchema).default([]),
1393
+ metadata: metadataSchema.nullable().optional(),
1394
+ customer_name: customerNameSchema.nullable().optional(),
1395
+ customer_phone: customerPhoneSchema.nullable().optional(),
1396
+ customer_email: customerEmailSchema.nullable().optional()
1397
+ }).strict().superRefine((val, ctx) => refineServiceXor(val, ctx, { requireAmount: true }));
1398
+ var saleUpdateSchema = import_zod11.z.object({
1399
+ description: import_zod11.z.string().nullable().optional(),
1400
+ service: import_zod11.z.string().nullable().optional(),
1401
+ services: import_zod11.z.array(saleServiceSchema).nullable().optional(),
1402
+ currency: currencySchema.optional(),
1403
+ amount_total_cents: centsSchema.optional(),
1404
+ occurred_at: import_zod11.z.string().datetime().optional(),
1405
+ items: import_zod11.z.array(saleItemSchema).optional(),
1406
+ metadata: metadataSchema.nullable().optional(),
1407
+ customer_name: customerNameSchema.nullable().optional(),
1408
+ customer_phone: customerPhoneSchema.nullable().optional(),
1409
+ customer_email: customerEmailSchema.nullable().optional()
1410
+ }).strict().superRefine((val, ctx) => refineServiceXor(val, ctx, { requireAmount: false }));
1411
+ var TRACKING_RANGES = ["24h", "7d", "30d"];
1412
+ var NAMED_RANGES = [
1413
+ "today",
1414
+ "yesterday",
1415
+ "wtd",
1416
+ "mtd",
1417
+ "qtd",
1418
+ "ytd",
1419
+ "24h",
1420
+ "7d",
1421
+ "30d",
1422
+ "90d",
1423
+ "custom"
1424
+ ];
1425
+
1426
+ // ../tracking-core/src/resources/services.ts
1427
+ async function fetchServices(config) {
1428
+ return salesRequest(config, "GET", "/services");
1429
+ }
1430
+
1431
+ // ../tracking-core/src/phone.ts
1432
+ var import_libphonenumber_js = require("libphonenumber-js");
1433
+ var DEFAULT_PHONE_COUNTRY = "CA";
1434
+ function parsePhone(raw, country) {
1435
+ const region = country ?? DEFAULT_PHONE_COUNTRY;
1436
+ const parsed = (0, import_libphonenumber_js.parsePhoneNumberFromString)(raw ?? "", region);
1437
+ if (!parsed) {
1438
+ return { e164: null, national: "", international: "", country: region, isValid: false };
1439
+ }
1440
+ const isValid = parsed.isValid();
1441
+ return {
1442
+ // E.164 is only surfaced for a *valid* number — a possible-but-invalid input
1443
+ // (e.g. too few digits) still parses but must not be transmitted.
1444
+ e164: isValid ? parsed.number : null,
1445
+ national: parsed.formatNational(),
1446
+ international: parsed.formatInternational(),
1447
+ country: parsed.country ?? region,
1448
+ isValid
1449
+ };
1450
+ }
1451
+ function toE164(raw, country) {
1452
+ return parsePhone(raw, country).e164;
1453
+ }
1454
+ function formatPhone(value, format = "national", country) {
1455
+ const parsed = parsePhone(value, country);
1456
+ if (typeof format === "function") return format(parsed);
1457
+ switch (format) {
1458
+ case "international":
1459
+ return parsed.international || value;
1460
+ case "e164":
1461
+ return parsed.e164 ?? value;
1462
+ case "national":
1463
+ default:
1464
+ return parsed.national || value;
1465
+ }
1466
+ }
1467
+ function formatPhoneAsTyped(raw, country) {
1468
+ return new import_libphonenumber_js.AsYouType(country ?? DEFAULT_PHONE_COUNTRY).input(raw ?? "");
1469
+ }
1470
+
1471
+ // ../tracking-core/src/phone-field.ts
1472
+ function phoneField(name, raw, country) {
1473
+ return { name, type: "phone", value: toE164(raw, country) };
1474
+ }
1239
1475
 
1240
1476
  // src/ConsentBanner.tsx
1241
1477
  var import_react2 = require("react");
@@ -1504,13 +1740,101 @@ function GoogleAdsTracking(props) {
1504
1740
  var import_navigation = require("next/navigation");
1505
1741
 
1506
1742
  // package.json
1507
- var version = "0.11.0";
1743
+ var version = "0.12.1";
1508
1744
 
1509
1745
  // src/factory.tsx
1746
+ var import_react4 = require("react");
1747
+
1748
+ // ../tracking-core/src/phone-react.tsx
1510
1749
  var import_react3 = require("react");
1511
1750
  var import_jsx_runtime3 = require("react/jsx-runtime");
1751
+ var _phoneConfigContext;
1752
+ function phoneConfigContext() {
1753
+ return _phoneConfigContext ?? (_phoneConfigContext = (0, import_react3.createContext)(null));
1754
+ }
1755
+ function PhoneConfigProvider({
1756
+ value,
1757
+ children
1758
+ }) {
1759
+ const Ctx = phoneConfigContext();
1760
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Ctx.Provider, { value, children });
1761
+ }
1762
+ function usePhoneConfig() {
1763
+ const ctx = (0, import_react3.useContext)(phoneConfigContext());
1764
+ return {
1765
+ defaultCountry: ctx?.defaultCountry ?? DEFAULT_PHONE_COUNTRY,
1766
+ display: ctx?.display ?? "national"
1767
+ };
1768
+ }
1769
+ function usePhoneField(opts = {}) {
1770
+ const cfg = usePhoneConfig();
1771
+ const country = opts.country ?? cfg.defaultCountry;
1772
+ const display = opts.display ?? cfg.display;
1773
+ const { onValueChange } = opts;
1774
+ const [value, setValue] = (0, import_react3.useState)(() => formatPhoneAsTyped(opts.defaultValue ?? "", country));
1775
+ const [touched, setTouched] = (0, import_react3.useState)(false);
1776
+ const parsed = (0, import_react3.useMemo)(() => parsePhone(value, country), [value, country]);
1777
+ const onChange = (0, import_react3.useCallback)(
1778
+ (event) => {
1779
+ const next = formatPhoneAsTyped(event.target.value, country);
1780
+ setValue(next);
1781
+ onValueChange?.(parsePhone(next, country).e164);
1782
+ },
1783
+ [country, onValueChange]
1784
+ );
1785
+ const onBlur = (0, import_react3.useCallback)(
1786
+ (_event) => {
1787
+ setTouched(true);
1788
+ setValue((current) => {
1789
+ const p = parsePhone(current, country);
1790
+ return p.isValid ? formatPhone(current, display, country) : current;
1791
+ });
1792
+ },
1793
+ [country, display]
1794
+ );
1795
+ const error = touched && value.length > 0 && !parsed.isValid ? "Enter a valid phone number" : null;
1796
+ return {
1797
+ value,
1798
+ e164: parsed.e164,
1799
+ isValid: parsed.isValid,
1800
+ error,
1801
+ parsed,
1802
+ inputProps: { value, onChange, onBlur, type: "tel", inputMode: "tel", autoComplete: "tel" }
1803
+ };
1804
+ }
1805
+ var PhoneField = (0, import_react3.forwardRef)(function PhoneField2({ country, value, defaultValue, onChange, onE164Change, ...rest }, ref) {
1806
+ const cfg = usePhoneConfig();
1807
+ const resolvedCountry = country ?? cfg.defaultCountry;
1808
+ const isControlled = value !== void 0;
1809
+ const [internal, setInternal] = (0, import_react3.useState)(
1810
+ () => formatPhoneAsTyped(defaultValue ?? "", resolvedCountry)
1811
+ );
1812
+ const handleChange = (event) => {
1813
+ const formatted = formatPhoneAsTyped(event.target.value, resolvedCountry);
1814
+ event.target.value = formatted;
1815
+ onE164Change?.(parsePhone(formatted, resolvedCountry).e164);
1816
+ if (!isControlled) setInternal(formatted);
1817
+ onChange?.(event);
1818
+ };
1819
+ const shown = isControlled ? formatPhoneAsTyped(value, resolvedCountry) : internal;
1820
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1821
+ "input",
1822
+ {
1823
+ ...rest,
1824
+ ref,
1825
+ type: "tel",
1826
+ inputMode: "tel",
1827
+ autoComplete: "tel",
1828
+ value: shown,
1829
+ onChange: handleChange
1830
+ }
1831
+ );
1832
+ });
1833
+
1834
+ // src/factory.tsx
1835
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1512
1836
  function createTracking(options) {
1513
- const { apiKey, endpoint, triggers, environment, gtagIds, debug } = options;
1837
+ const { apiKey, endpoint, triggers, environment, gtagIds, debug, phone } = options;
1514
1838
  if (!apiKey || !endpoint) {
1515
1839
  if (apiKey || endpoint) {
1516
1840
  console.warn(
@@ -1526,17 +1850,17 @@ function createTracking(options) {
1526
1850
  getVisitorId: () => ""
1527
1851
  };
1528
1852
  return {
1529
- TrackingProvider: ({ children }) => children,
1853
+ TrackingProvider: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PhoneConfigProvider, { value: phone ?? null, children }),
1530
1854
  useTracking: () => noopClient
1531
1855
  };
1532
1856
  }
1533
- const TrackingContext = (0, import_react3.createContext)(null);
1857
+ const TrackingContext = (0, import_react4.createContext)(null);
1534
1858
  const specificPageVisitConfig = triggers.automatic.specific_page_visit ?? null;
1535
1859
  const timeOnSiteConfig = triggers.automatic.time_on_site ?? null;
1536
1860
  function TrackingProvider({ children }) {
1537
1861
  const pathname = (0, import_navigation.usePathname)();
1538
1862
  const searchParams = (0, import_navigation.useSearchParams)();
1539
- const client = (0, import_react3.useMemo)(
1863
+ const client = (0, import_react4.useMemo)(
1540
1864
  () => createTypedClient(
1541
1865
  getOrCreateTrackingClient({
1542
1866
  apiKey,
@@ -1554,7 +1878,7 @@ function createTracking(options) {
1554
1878
  ),
1555
1879
  []
1556
1880
  );
1557
- (0, import_react3.useEffect)(() => {
1881
+ (0, import_react4.useEffect)(() => {
1558
1882
  const rawClient = getOrCreateTrackingClient({
1559
1883
  apiKey,
1560
1884
  endpoint,
@@ -1567,8 +1891,8 @@ function createTracking(options) {
1567
1891
  });
1568
1892
  fireManualPageView(rawClient);
1569
1893
  }, [pathname, searchParams]);
1570
- const firedPagesRef = (0, import_react3.useRef)(/* @__PURE__ */ new Set());
1571
- (0, import_react3.useEffect)(() => {
1894
+ const firedPagesRef = (0, import_react4.useRef)(/* @__PURE__ */ new Set());
1895
+ (0, import_react4.useEffect)(() => {
1572
1896
  if (!specificPageVisitConfig || pathname === null) return;
1573
1897
  const rawClient = getOrCreateTrackingClient({
1574
1898
  apiKey,
@@ -1593,7 +1917,7 @@ function createTracking(options) {
1593
1917
  });
1594
1918
  }
1595
1919
  }, [pathname]);
1596
- (0, import_react3.useEffect)(() => {
1920
+ (0, import_react4.useEffect)(() => {
1597
1921
  const rawClient = getOrCreateTrackingClient({
1598
1922
  apiKey,
1599
1923
  endpoint,
@@ -1606,7 +1930,7 @@ function createTracking(options) {
1606
1930
  });
1607
1931
  return attachBfcacheRestore(rawClient);
1608
1932
  }, []);
1609
- (0, import_react3.useEffect)(() => {
1933
+ (0, import_react4.useEffect)(() => {
1610
1934
  if (!timeOnSiteConfig) return;
1611
1935
  const rawClient = getOrCreateTrackingClient({
1612
1936
  apiKey,
@@ -1621,8 +1945,8 @@ function createTracking(options) {
1621
1945
  return attachTimeOnSite(rawClient, timeOnSiteConfig);
1622
1946
  }, []);
1623
1947
  const multiPageSessionConfig = triggers.automatic.multi_page_session ?? null;
1624
- const mpsLastPathRef = (0, import_react3.useRef)(null);
1625
- (0, import_react3.useEffect)(() => {
1948
+ const mpsLastPathRef = (0, import_react4.useRef)(null);
1949
+ (0, import_react4.useEffect)(() => {
1626
1950
  if (!multiPageSessionConfig || pathname === null) return;
1627
1951
  if (pathname === mpsLastPathRef.current) return;
1628
1952
  mpsLastPathRef.current = pathname;
@@ -1669,7 +1993,7 @@ function createTracking(options) {
1669
1993
  } catch {
1670
1994
  }
1671
1995
  }, [pathname]);
1672
- (0, import_react3.useEffect)(() => {
1996
+ (0, import_react4.useEffect)(() => {
1673
1997
  const detachers = [];
1674
1998
  const rawClient = getOrCreateTrackingClient({
1675
1999
  apiKey,
@@ -1695,10 +2019,10 @@ function createTracking(options) {
1695
2019
  }
1696
2020
  };
1697
2021
  }, []);
1698
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TrackingContext.Provider, { value: client, children });
2022
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TrackingContext.Provider, { value: client, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PhoneConfigProvider, { value: phone ?? null, children }) });
1699
2023
  }
1700
2024
  function useTracking() {
1701
- const client = (0, import_react3.useContext)(TrackingContext);
2025
+ const client = (0, import_react4.useContext)(TrackingContext);
1702
2026
  if (client === null) {
1703
2027
  throw new Error(
1704
2028
  "useTracking must be called inside a <TrackingProvider> returned by createTracking()"
@@ -1712,8 +2036,13 @@ function createTracking(options) {
1712
2036
  0 && (module.exports = {
1713
2037
  AranovaApiError,
1714
2038
  ConsentBanner,
2039
+ DEFAULT_PHONE_COUNTRY,
1715
2040
  GoogleAdsTracking,
2041
+ NAMED_RANGES,
2042
+ PhoneField,
2043
+ SUPPORTED_CURRENCIES,
1716
2044
  TRACKING_PARAM_KEYS,
2045
+ TRACKING_RANGES,
1717
2046
  captureTrackingParamsFromLocation,
1718
2047
  createSalesClient,
1719
2048
  createTracking,
@@ -1721,15 +2050,28 @@ function createTracking(options) {
1721
2050
  createTrackingEventCreatePayload,
1722
2051
  createTrackingSessionUpsertPayload,
1723
2052
  fetchServices,
2053
+ formatDateInTz,
1724
2054
  formatMoney,
2055
+ formatPhone,
2056
+ formatPhoneAsTyped,
1725
2057
  fromMinor,
1726
2058
  getConsentState,
2059
+ parsePhone,
2060
+ phoneField,
1727
2061
  resetConsent,
2062
+ saleCreateSchema,
2063
+ saleItemSchema,
2064
+ saleServiceSchema,
2065
+ saleUpdateSchema,
2066
+ salesRequest,
1728
2067
  setConsentState,
2068
+ toE164,
1729
2069
  toMinor,
1730
2070
  useConsent,
1731
2071
  useConsentState,
1732
2072
  useGclid,
2073
+ usePhoneConfig,
2074
+ usePhoneField,
1733
2075
  useTrackingParams
1734
2076
  });
1735
2077
  //# sourceMappingURL=index.js.map