@aranova/tracking-next 0.10.0 → 0.12.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/dist/index.js CHANGED
@@ -32,7 +32,10 @@ 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
+ PhoneConfigContext: () => PhoneConfigContext,
38
+ PhoneField: () => PhoneField,
36
39
  TRACKING_PARAM_KEYS: () => TRACKING_PARAM_KEYS,
37
40
  captureTrackingParamsFromLocation: () => captureTrackingParamsFromLocation,
38
41
  createSalesClient: () => createSalesClient,
@@ -41,15 +44,23 @@ __export(src_exports, {
41
44
  createTrackingEventCreatePayload: () => createTrackingEventCreatePayload,
42
45
  createTrackingSessionUpsertPayload: () => createTrackingSessionUpsertPayload,
43
46
  fetchServices: () => fetchServices,
47
+ formatDateInTz: () => formatDateInTz,
44
48
  formatMoney: () => formatMoney,
49
+ formatPhone: () => formatPhone,
50
+ formatPhoneAsTyped: () => formatPhoneAsTyped,
45
51
  fromMinor: () => fromMinor,
46
52
  getConsentState: () => getConsentState,
53
+ parsePhone: () => parsePhone,
54
+ phoneField: () => phoneField,
47
55
  resetConsent: () => resetConsent,
48
56
  setConsentState: () => setConsentState,
57
+ toE164: () => toE164,
49
58
  toMinor: () => toMinor,
50
59
  useConsent: () => useConsent,
51
60
  useConsentState: () => useConsentState,
52
61
  useGclid: () => useGclid,
62
+ usePhoneConfig: () => usePhoneConfig,
63
+ usePhoneField: () => usePhoneField,
53
64
  useTrackingParams: () => useTrackingParams
54
65
  });
55
66
  module.exports = __toCommonJS(src_exports);
@@ -1183,21 +1194,40 @@ function createSalesClient(config) {
1183
1194
  return salesRequest(config, "POST", "/sales", body);
1184
1195
  },
1185
1196
  async list(query) {
1186
- const { cursor, limit, ...filters } = query ?? {};
1197
+ const { cursor, limit, sort, order, want_total, ...filters } = query ?? {};
1187
1198
  return salesRequest(config, "POST", "/sales/query", {
1188
1199
  filters,
1189
1200
  ...limit !== void 0 ? { limit } : {},
1190
- ...cursor !== void 0 ? { cursor } : {}
1201
+ ...cursor !== void 0 ? { cursor } : {},
1202
+ ...sort !== void 0 ? { sort } : {},
1203
+ ...order !== void 0 ? { order } : {},
1204
+ ...want_total !== void 0 ? { want_total } : {}
1191
1205
  });
1192
1206
  },
1193
1207
  async summary(query) {
1194
- const { range, include_categories, include_deleted_services, top_n, ...filters } = query;
1208
+ const {
1209
+ range,
1210
+ include_categories,
1211
+ include_deleted_services,
1212
+ top_n,
1213
+ since,
1214
+ until,
1215
+ timezone,
1216
+ granularity,
1217
+ compare_to,
1218
+ ...filters
1219
+ } = query;
1195
1220
  return salesRequest(config, "POST", "/sales/summary", {
1196
1221
  filters,
1197
- range,
1222
+ ...range !== void 0 ? { range } : {},
1198
1223
  ...include_categories !== void 0 ? { include_categories } : {},
1199
1224
  ...include_deleted_services !== void 0 ? { include_deleted_services } : {},
1200
- ...top_n !== void 0 ? { top_n } : {}
1225
+ ...top_n !== void 0 ? { top_n } : {},
1226
+ ...since !== void 0 ? { since } : {},
1227
+ ...until !== void 0 ? { until } : {},
1228
+ ...timezone !== void 0 ? { timezone } : {},
1229
+ ...granularity !== void 0 ? { granularity } : {},
1230
+ ...compare_to !== void 0 ? { compare_to } : {}
1201
1231
  });
1202
1232
  },
1203
1233
  async get(id) {
@@ -1208,6 +1238,49 @@ function createSalesClient(config) {
1208
1238
  },
1209
1239
  async delete(id) {
1210
1240
  await salesRequest(config, "DELETE", `/sales/${id}`);
1241
+ },
1242
+ customers: {
1243
+ async list(query) {
1244
+ const { segment, sort, order, cursor, limit, want_total, ...filters } = query ?? {};
1245
+ return salesRequest(config, "POST", "/customers/query", {
1246
+ filters,
1247
+ ...segment !== void 0 ? { segment } : {},
1248
+ ...sort !== void 0 ? { sort } : {},
1249
+ ...order !== void 0 ? { order } : {},
1250
+ ...cursor !== void 0 ? { cursor } : {},
1251
+ ...limit !== void 0 ? { limit } : {},
1252
+ ...want_total !== void 0 ? { want_total } : {}
1253
+ });
1254
+ },
1255
+ async get(id, options) {
1256
+ const params = new URLSearchParams();
1257
+ if (options?.include_sales !== void 0)
1258
+ params.set("include_sales", String(options.include_sales));
1259
+ if (options?.limit !== void 0) params.set("limit", String(options.limit));
1260
+ if (options?.cursor != null) params.set("cursor", options.cursor);
1261
+ const qs = params.toString();
1262
+ return salesRequest(
1263
+ config,
1264
+ "GET",
1265
+ `/customers/${encodeURIComponent(id)}${qs ? `?${qs}` : ""}`
1266
+ );
1267
+ },
1268
+ async summary(query) {
1269
+ const { range, since, until, timezone, compare_to, ...filters } = query ?? {};
1270
+ return salesRequest(config, "POST", "/customers/summary", {
1271
+ filters,
1272
+ ...range !== void 0 ? { range } : {},
1273
+ ...since !== void 0 ? { since } : {},
1274
+ ...until !== void 0 ? { until } : {},
1275
+ ...timezone !== void 0 ? { timezone } : {},
1276
+ ...compare_to !== void 0 ? { compare_to } : {}
1277
+ });
1278
+ }
1279
+ },
1280
+ business: {
1281
+ async config() {
1282
+ return salesRequest(config, "GET", "/business/config");
1283
+ }
1211
1284
  }
1212
1285
  };
1213
1286
  }
@@ -1236,6 +1309,64 @@ function formatMoney(cents, currency, locale) {
1236
1309
  fromMinor(cents, currency)
1237
1310
  );
1238
1311
  }
1312
+ function formatDateInTz(iso, timeZone, opts, locale) {
1313
+ const date = new Date(iso);
1314
+ if (Number.isNaN(date.getTime())) return iso;
1315
+ return new Intl.DateTimeFormat(locale, {
1316
+ year: "numeric",
1317
+ month: "short",
1318
+ day: "2-digit",
1319
+ hour: "2-digit",
1320
+ minute: "2-digit",
1321
+ ...opts,
1322
+ timeZone
1323
+ }).format(date);
1324
+ }
1325
+
1326
+ // ../tracking-core/src/phone.ts
1327
+ var import_libphonenumber_js = require("libphonenumber-js");
1328
+ var DEFAULT_PHONE_COUNTRY = "CA";
1329
+ function parsePhone(raw, country) {
1330
+ const region = country ?? DEFAULT_PHONE_COUNTRY;
1331
+ const parsed = (0, import_libphonenumber_js.parsePhoneNumberFromString)(raw ?? "", region);
1332
+ if (!parsed) {
1333
+ return { e164: null, national: "", international: "", country: region, isValid: false };
1334
+ }
1335
+ const isValid = parsed.isValid();
1336
+ return {
1337
+ // E.164 is only surfaced for a *valid* number — a possible-but-invalid input
1338
+ // (e.g. too few digits) still parses but must not be transmitted.
1339
+ e164: isValid ? parsed.number : null,
1340
+ national: parsed.formatNational(),
1341
+ international: parsed.formatInternational(),
1342
+ country: parsed.country ?? region,
1343
+ isValid
1344
+ };
1345
+ }
1346
+ function toE164(raw, country) {
1347
+ return parsePhone(raw, country).e164;
1348
+ }
1349
+ function formatPhone(value, format = "national", country) {
1350
+ const parsed = parsePhone(value, country);
1351
+ if (typeof format === "function") return format(parsed);
1352
+ switch (format) {
1353
+ case "international":
1354
+ return parsed.international || value;
1355
+ case "e164":
1356
+ return parsed.e164 ?? value;
1357
+ case "national":
1358
+ default:
1359
+ return parsed.national || value;
1360
+ }
1361
+ }
1362
+ function formatPhoneAsTyped(raw, country) {
1363
+ return new import_libphonenumber_js.AsYouType(country ?? DEFAULT_PHONE_COUNTRY).input(raw ?? "");
1364
+ }
1365
+
1366
+ // ../tracking-core/src/phone-field.ts
1367
+ function phoneField(name, raw, country) {
1368
+ return { name, type: "phone", value: toE164(raw, country) };
1369
+ }
1239
1370
 
1240
1371
  // src/ConsentBanner.tsx
1241
1372
  var import_react2 = require("react");
@@ -1504,13 +1635,91 @@ function GoogleAdsTracking(props) {
1504
1635
  var import_navigation = require("next/navigation");
1505
1636
 
1506
1637
  // package.json
1507
- var version = "0.10.0";
1638
+ var version = "0.12.0";
1508
1639
 
1509
1640
  // src/factory.tsx
1641
+ var import_react4 = require("react");
1642
+
1643
+ // ../tracking-core/src/phone-react.tsx
1510
1644
  var import_react3 = require("react");
1511
1645
  var import_jsx_runtime3 = require("react/jsx-runtime");
1646
+ var PhoneConfigContext = (0, import_react3.createContext)(null);
1647
+ function usePhoneConfig() {
1648
+ const ctx = (0, import_react3.useContext)(PhoneConfigContext);
1649
+ return {
1650
+ defaultCountry: ctx?.defaultCountry ?? DEFAULT_PHONE_COUNTRY,
1651
+ display: ctx?.display ?? "national"
1652
+ };
1653
+ }
1654
+ function usePhoneField(opts = {}) {
1655
+ const cfg = usePhoneConfig();
1656
+ const country = opts.country ?? cfg.defaultCountry;
1657
+ const display = opts.display ?? cfg.display;
1658
+ const { onValueChange } = opts;
1659
+ const [value, setValue] = (0, import_react3.useState)(() => formatPhoneAsTyped(opts.defaultValue ?? "", country));
1660
+ const [touched, setTouched] = (0, import_react3.useState)(false);
1661
+ const parsed = (0, import_react3.useMemo)(() => parsePhone(value, country), [value, country]);
1662
+ const onChange = (0, import_react3.useCallback)(
1663
+ (event) => {
1664
+ const next = formatPhoneAsTyped(event.target.value, country);
1665
+ setValue(next);
1666
+ onValueChange?.(parsePhone(next, country).e164);
1667
+ },
1668
+ [country, onValueChange]
1669
+ );
1670
+ const onBlur = (0, import_react3.useCallback)(
1671
+ (_event) => {
1672
+ setTouched(true);
1673
+ setValue((current) => {
1674
+ const p = parsePhone(current, country);
1675
+ return p.isValid ? formatPhone(current, display, country) : current;
1676
+ });
1677
+ },
1678
+ [country, display]
1679
+ );
1680
+ const error = touched && value.length > 0 && !parsed.isValid ? "Enter a valid phone number" : null;
1681
+ return {
1682
+ value,
1683
+ e164: parsed.e164,
1684
+ isValid: parsed.isValid,
1685
+ error,
1686
+ parsed,
1687
+ inputProps: { value, onChange, onBlur, type: "tel", inputMode: "tel", autoComplete: "tel" }
1688
+ };
1689
+ }
1690
+ var PhoneField = (0, import_react3.forwardRef)(function PhoneField2({ country, value, defaultValue, onChange, onE164Change, ...rest }, ref) {
1691
+ const cfg = usePhoneConfig();
1692
+ const resolvedCountry = country ?? cfg.defaultCountry;
1693
+ const isControlled = value !== void 0;
1694
+ const [internal, setInternal] = (0, import_react3.useState)(
1695
+ () => formatPhoneAsTyped(defaultValue ?? "", resolvedCountry)
1696
+ );
1697
+ const handleChange = (event) => {
1698
+ const formatted = formatPhoneAsTyped(event.target.value, resolvedCountry);
1699
+ event.target.value = formatted;
1700
+ onE164Change?.(parsePhone(formatted, resolvedCountry).e164);
1701
+ if (!isControlled) setInternal(formatted);
1702
+ onChange?.(event);
1703
+ };
1704
+ const shown = isControlled ? formatPhoneAsTyped(value, resolvedCountry) : internal;
1705
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1706
+ "input",
1707
+ {
1708
+ ...rest,
1709
+ ref,
1710
+ type: "tel",
1711
+ inputMode: "tel",
1712
+ autoComplete: "tel",
1713
+ value: shown,
1714
+ onChange: handleChange
1715
+ }
1716
+ );
1717
+ });
1718
+
1719
+ // src/factory.tsx
1720
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1512
1721
  function createTracking(options) {
1513
- const { apiKey, endpoint, triggers, environment, gtagIds, debug } = options;
1722
+ const { apiKey, endpoint, triggers, environment, gtagIds, debug, phone } = options;
1514
1723
  if (!apiKey || !endpoint) {
1515
1724
  if (apiKey || endpoint) {
1516
1725
  console.warn(
@@ -1526,17 +1735,17 @@ function createTracking(options) {
1526
1735
  getVisitorId: () => ""
1527
1736
  };
1528
1737
  return {
1529
- TrackingProvider: ({ children }) => children,
1738
+ TrackingProvider: ({ children }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PhoneConfigContext.Provider, { value: phone ?? null, children }),
1530
1739
  useTracking: () => noopClient
1531
1740
  };
1532
1741
  }
1533
- const TrackingContext = (0, import_react3.createContext)(null);
1742
+ const TrackingContext = (0, import_react4.createContext)(null);
1534
1743
  const specificPageVisitConfig = triggers.automatic.specific_page_visit ?? null;
1535
1744
  const timeOnSiteConfig = triggers.automatic.time_on_site ?? null;
1536
1745
  function TrackingProvider({ children }) {
1537
1746
  const pathname = (0, import_navigation.usePathname)();
1538
1747
  const searchParams = (0, import_navigation.useSearchParams)();
1539
- const client = (0, import_react3.useMemo)(
1748
+ const client = (0, import_react4.useMemo)(
1540
1749
  () => createTypedClient(
1541
1750
  getOrCreateTrackingClient({
1542
1751
  apiKey,
@@ -1554,7 +1763,7 @@ function createTracking(options) {
1554
1763
  ),
1555
1764
  []
1556
1765
  );
1557
- (0, import_react3.useEffect)(() => {
1766
+ (0, import_react4.useEffect)(() => {
1558
1767
  const rawClient = getOrCreateTrackingClient({
1559
1768
  apiKey,
1560
1769
  endpoint,
@@ -1567,8 +1776,8 @@ function createTracking(options) {
1567
1776
  });
1568
1777
  fireManualPageView(rawClient);
1569
1778
  }, [pathname, searchParams]);
1570
- const firedPagesRef = (0, import_react3.useRef)(/* @__PURE__ */ new Set());
1571
- (0, import_react3.useEffect)(() => {
1779
+ const firedPagesRef = (0, import_react4.useRef)(/* @__PURE__ */ new Set());
1780
+ (0, import_react4.useEffect)(() => {
1572
1781
  if (!specificPageVisitConfig || pathname === null) return;
1573
1782
  const rawClient = getOrCreateTrackingClient({
1574
1783
  apiKey,
@@ -1593,7 +1802,7 @@ function createTracking(options) {
1593
1802
  });
1594
1803
  }
1595
1804
  }, [pathname]);
1596
- (0, import_react3.useEffect)(() => {
1805
+ (0, import_react4.useEffect)(() => {
1597
1806
  const rawClient = getOrCreateTrackingClient({
1598
1807
  apiKey,
1599
1808
  endpoint,
@@ -1606,7 +1815,7 @@ function createTracking(options) {
1606
1815
  });
1607
1816
  return attachBfcacheRestore(rawClient);
1608
1817
  }, []);
1609
- (0, import_react3.useEffect)(() => {
1818
+ (0, import_react4.useEffect)(() => {
1610
1819
  if (!timeOnSiteConfig) return;
1611
1820
  const rawClient = getOrCreateTrackingClient({
1612
1821
  apiKey,
@@ -1621,8 +1830,8 @@ function createTracking(options) {
1621
1830
  return attachTimeOnSite(rawClient, timeOnSiteConfig);
1622
1831
  }, []);
1623
1832
  const multiPageSessionConfig = triggers.automatic.multi_page_session ?? null;
1624
- const mpsLastPathRef = (0, import_react3.useRef)(null);
1625
- (0, import_react3.useEffect)(() => {
1833
+ const mpsLastPathRef = (0, import_react4.useRef)(null);
1834
+ (0, import_react4.useEffect)(() => {
1626
1835
  if (!multiPageSessionConfig || pathname === null) return;
1627
1836
  if (pathname === mpsLastPathRef.current) return;
1628
1837
  mpsLastPathRef.current = pathname;
@@ -1669,7 +1878,7 @@ function createTracking(options) {
1669
1878
  } catch {
1670
1879
  }
1671
1880
  }, [pathname]);
1672
- (0, import_react3.useEffect)(() => {
1881
+ (0, import_react4.useEffect)(() => {
1673
1882
  const detachers = [];
1674
1883
  const rawClient = getOrCreateTrackingClient({
1675
1884
  apiKey,
@@ -1695,10 +1904,10 @@ function createTracking(options) {
1695
1904
  }
1696
1905
  };
1697
1906
  }, []);
1698
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TrackingContext.Provider, { value: client, children });
1907
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TrackingContext.Provider, { value: client, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PhoneConfigContext.Provider, { value: phone ?? null, children }) });
1699
1908
  }
1700
1909
  function useTracking() {
1701
- const client = (0, import_react3.useContext)(TrackingContext);
1910
+ const client = (0, import_react4.useContext)(TrackingContext);
1702
1911
  if (client === null) {
1703
1912
  throw new Error(
1704
1913
  "useTracking must be called inside a <TrackingProvider> returned by createTracking()"
@@ -1712,7 +1921,10 @@ function createTracking(options) {
1712
1921
  0 && (module.exports = {
1713
1922
  AranovaApiError,
1714
1923
  ConsentBanner,
1924
+ DEFAULT_PHONE_COUNTRY,
1715
1925
  GoogleAdsTracking,
1926
+ PhoneConfigContext,
1927
+ PhoneField,
1716
1928
  TRACKING_PARAM_KEYS,
1717
1929
  captureTrackingParamsFromLocation,
1718
1930
  createSalesClient,
@@ -1721,15 +1933,23 @@ function createTracking(options) {
1721
1933
  createTrackingEventCreatePayload,
1722
1934
  createTrackingSessionUpsertPayload,
1723
1935
  fetchServices,
1936
+ formatDateInTz,
1724
1937
  formatMoney,
1938
+ formatPhone,
1939
+ formatPhoneAsTyped,
1725
1940
  fromMinor,
1726
1941
  getConsentState,
1942
+ parsePhone,
1943
+ phoneField,
1727
1944
  resetConsent,
1728
1945
  setConsentState,
1946
+ toE164,
1729
1947
  toMinor,
1730
1948
  useConsent,
1731
1949
  useConsentState,
1732
1950
  useGclid,
1951
+ usePhoneConfig,
1952
+ usePhoneField,
1733
1953
  useTrackingParams
1734
1954
  });
1735
1955
  //# sourceMappingURL=index.js.map