@aranova/tracking-react 0.12.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 +59 -48
- package/dist/index.d.mts +61 -802
- package/dist/index.d.ts +61 -802
- package/dist/index.js +190 -79
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +183 -84
- package/dist/index.mjs.map +1 -1
- package/dist/{phone-utils-CVX7JmqB.d.mts → phone-utils-DXAki8pO.d.mts} +7 -6
- package/dist/{phone-utils-CVX7JmqB.d.ts → phone-utils-DXAki8pO.d.ts} +7 -6
- package/dist/phone.d.mts +1 -1
- package/dist/phone.d.ts +1 -1
- package/dist/phone.js +98 -0
- package/dist/phone.js.map +1 -1
- package/dist/phone.mjs +98 -0
- package/dist/phone.mjs.map +1 -1
- 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 +30 -7
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ Create one shared tracking module and import the scoped `TrackingProvider` / `us
|
|
|
14
14
|
|
|
15
15
|
```ts
|
|
16
16
|
// src/lib/tracking.ts
|
|
17
|
-
import { createTracking } from
|
|
17
|
+
import { createTracking } from "@aranova/tracking-react";
|
|
18
18
|
|
|
19
19
|
export const { TrackingProvider, useTracking } = createTracking({
|
|
20
20
|
apiKey: import.meta.env.VITE_ARANOVA_TRACKING_API_KEY,
|
|
@@ -24,7 +24,7 @@ export const { TrackingProvider, useTracking } = createTracking({
|
|
|
24
24
|
page_view: {},
|
|
25
25
|
time_on_site: { thresholdSeconds: 60 },
|
|
26
26
|
specific_page_visit: {
|
|
27
|
-
pages: [{ name:
|
|
27
|
+
pages: [{ name: "contact_page", pathPattern: /^\/(contact|book|get-started)/ }],
|
|
28
28
|
},
|
|
29
29
|
},
|
|
30
30
|
manual: {
|
|
@@ -33,7 +33,7 @@ export const { TrackingProvider, useTracking } = createTracking({
|
|
|
33
33
|
cta_click: {},
|
|
34
34
|
},
|
|
35
35
|
},
|
|
36
|
-
debug: import.meta.env.MODE !==
|
|
36
|
+
debug: import.meta.env.MODE !== "production",
|
|
37
37
|
});
|
|
38
38
|
```
|
|
39
39
|
|
|
@@ -41,11 +41,11 @@ Mount the provider at the root of your React tree.
|
|
|
41
41
|
|
|
42
42
|
```tsx
|
|
43
43
|
// src/main.tsx
|
|
44
|
-
import { createRoot } from
|
|
45
|
-
import { App } from
|
|
46
|
-
import { TrackingProvider } from
|
|
44
|
+
import { createRoot } from "react-dom/client";
|
|
45
|
+
import { App } from "./App";
|
|
46
|
+
import { TrackingProvider } from "./lib/tracking";
|
|
47
47
|
|
|
48
|
-
createRoot(document.getElementById(
|
|
48
|
+
createRoot(document.getElementById("root")!).render(
|
|
49
49
|
<TrackingProvider gtagId={import.meta.env.VITE_GTAG_ID}>
|
|
50
50
|
<App />
|
|
51
51
|
</TrackingProvider>,
|
|
@@ -59,7 +59,7 @@ account plus a test MCC. Each entry fires `gtag('config', …)` on every page; t
|
|
|
59
59
|
the dashboard's SDK table. Stamp events with `environment` to filter out test traffic.
|
|
60
60
|
|
|
61
61
|
```tsx
|
|
62
|
-
<TrackingProvider gtagIds={{ production:
|
|
62
|
+
<TrackingProvider gtagIds={{ production: "AW-111111111", test: "AW-222222222" }}>
|
|
63
63
|
<App />
|
|
64
64
|
</TrackingProvider>
|
|
65
65
|
```
|
|
@@ -69,7 +69,7 @@ the dashboard's SDK table. Stamp events with `environment` to filter out test tr
|
|
|
69
69
|
Manual events must be registered under `triggers.manual` before `trackEvent()` accepts them.
|
|
70
70
|
|
|
71
71
|
```tsx
|
|
72
|
-
import { useTracking } from
|
|
72
|
+
import { useTracking } from "./lib/tracking";
|
|
73
73
|
|
|
74
74
|
export function LeadForm() {
|
|
75
75
|
const tracking = useTracking();
|
|
@@ -78,22 +78,22 @@ export function LeadForm() {
|
|
|
78
78
|
const form = event.currentTarget;
|
|
79
79
|
const data = new FormData(form);
|
|
80
80
|
|
|
81
|
-
tracking.trackEvent(
|
|
81
|
+
tracking.trackEvent("form_submit", {
|
|
82
82
|
form: {
|
|
83
83
|
id: form.id,
|
|
84
|
-
action: form.getAttribute(
|
|
84
|
+
action: form.getAttribute("action"),
|
|
85
85
|
fields: [
|
|
86
86
|
{
|
|
87
|
-
name:
|
|
88
|
-
type:
|
|
89
|
-
label:
|
|
90
|
-
value: String(data.get(
|
|
87
|
+
name: "service_interest",
|
|
88
|
+
type: "select",
|
|
89
|
+
label: "Service interest",
|
|
90
|
+
value: String(data.get("service_interest") ?? ""),
|
|
91
91
|
},
|
|
92
92
|
{
|
|
93
|
-
name:
|
|
94
|
-
type:
|
|
95
|
-
label:
|
|
96
|
-
value: data.get(
|
|
93
|
+
name: "is_existing_patient",
|
|
94
|
+
type: "checkbox",
|
|
95
|
+
label: "Existing patient",
|
|
96
|
+
value: data.get("is_existing_patient") === "on",
|
|
97
97
|
},
|
|
98
98
|
],
|
|
99
99
|
},
|
|
@@ -101,17 +101,21 @@ export function LeadForm() {
|
|
|
101
101
|
});
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
return
|
|
104
|
+
return (
|
|
105
|
+
<form id="lead-form" action="/api/lead" onSubmit={handleSubmit}>
|
|
106
|
+
{/* fields */}
|
|
107
|
+
</form>
|
|
108
|
+
);
|
|
105
109
|
}
|
|
106
110
|
```
|
|
107
111
|
|
|
108
112
|
`fields[].value` can be any JSON value: string, number, boolean, null, array, or object. Values must be JSON-serializable because events are stored as JSONB. Only send reviewed, allowlisted, non-sensitive values; do not send names, emails, phone numbers entered by the visitor, addresses, payment data, medical details, passwords, file contents, or free-text messages.
|
|
109
113
|
|
|
110
114
|
```tsx
|
|
111
|
-
tracking.trackEvent(
|
|
112
|
-
phone_number:
|
|
115
|
+
tracking.trackEvent("phone_click", {
|
|
116
|
+
phone_number: "+14165550199",
|
|
113
117
|
page: { path: window.location.pathname },
|
|
114
|
-
section:
|
|
118
|
+
section: "header",
|
|
115
119
|
});
|
|
116
120
|
```
|
|
117
121
|
|
|
@@ -121,12 +125,12 @@ Bundled `libphonenumber-js`: parse/format utils + a React input. Display is conf
|
|
|
121
125
|
value sent to the backend is **always E.164**. Configure once via `createTracking({ phone: { defaultCountry: 'CA', display: 'national' } })`.
|
|
122
126
|
|
|
123
127
|
```tsx
|
|
124
|
-
import { usePhoneField, PhoneField, toE164 } from
|
|
128
|
+
import { usePhoneField, PhoneField, toE164 } from "@aranova/tracking-react";
|
|
125
129
|
|
|
126
|
-
const phone = usePhoneField();
|
|
127
|
-
<input {...phone.inputProps} />;
|
|
130
|
+
const phone = usePhoneField(); // phone.value (display), phone.e164 (wire), .isValid, .error
|
|
131
|
+
<input {...phone.inputProps} />; // or the batteries-included <PhoneField name="phone" />
|
|
128
132
|
|
|
129
|
-
toE164(
|
|
133
|
+
toE164("416-555-0199"); // '+14165550199' (null if invalid)
|
|
130
134
|
```
|
|
131
135
|
|
|
132
136
|
Pure, isomorphic utils are also at `@aranova/tracking-react/phone` (no React). Full guide:
|
|
@@ -142,19 +146,23 @@ key may do is enforced by the backend, not by hiding methods. Browser write with
|
|
|
142
146
|
your **public** key:
|
|
143
147
|
|
|
144
148
|
```tsx
|
|
145
|
-
import { createSalesClient, toMinor } from
|
|
149
|
+
import { createSalesClient, toMinor } from "@aranova/tracking-react";
|
|
146
150
|
|
|
147
|
-
const sales = createSalesClient({
|
|
148
|
-
|
|
151
|
+
const sales = createSalesClient({
|
|
152
|
+
apiKey: import.meta.env.VITE_ARANOVA_TRACKING_API_KEY,
|
|
153
|
+
endpoint,
|
|
154
|
+
});
|
|
155
|
+
await sales.record({ currency: "CAD", amount_total_cents: toMinor(250, "CAD"), service: "tires" });
|
|
149
156
|
```
|
|
150
157
|
|
|
151
158
|
Reads / full CRUD require a **secret** key and must run server-side — never ship a
|
|
152
159
|
secret key in the browser bundle. In a Vite + Vercel app, hold it in a serverless
|
|
153
|
-
function
|
|
160
|
+
function. Import from the **`/sales`** subpath — it's React-free, so the server
|
|
161
|
+
bundle never pulls in the provider/components:
|
|
154
162
|
|
|
155
163
|
```ts
|
|
156
164
|
// api/sales.ts (Vercel serverless function — runs on the server)
|
|
157
|
-
import { createSalesClient } from
|
|
165
|
+
import { createSalesClient } from "@aranova/tracking-react/sales";
|
|
158
166
|
|
|
159
167
|
const sales = createSalesClient({
|
|
160
168
|
apiKey: process.env.ARANOVA_TRACKING_SECRET_KEY!,
|
|
@@ -168,17 +176,21 @@ export default async function handler(_req, res) {
|
|
|
168
176
|
Secret-key reads power dashboards (all currency-grouped — never summed across currencies):
|
|
169
177
|
|
|
170
178
|
```ts
|
|
171
|
-
await sales.summary({ range:
|
|
172
|
-
await sales.list({ sort:
|
|
173
|
-
await sales.customers.list({ segment:
|
|
174
|
-
await sales.customers.summary({ range:
|
|
175
|
-
const cfg = await sales.business.config();
|
|
179
|
+
await sales.summary({ range: "mtd", timezone: "America/Toronto", compare_to: "previous_period" });
|
|
180
|
+
await sales.list({ sort: "amount_total_cents", want_total: true }); // → { items, total_count, … }
|
|
181
|
+
await sales.customers.list({ segment: "returning", sort: "total_spent" }); // phone-keyed roster
|
|
182
|
+
await sales.customers.summary({ range: "mtd" });
|
|
183
|
+
const cfg = await sales.business.config(); // tz / currencies / services (pk or sk)
|
|
176
184
|
```
|
|
177
185
|
|
|
178
186
|
`summary()` gains tz-aware calendar/custom ranges, `granularity`, and period-over-period
|
|
179
187
|
`compare_to`; legacy `24h/7d/30d` are unchanged. A **customer is their phone (E.164)** — `customers.*`
|
|
180
188
|
is a live roster, no separate table. A public-key client calling any read gets a `403`.
|
|
181
189
|
|
|
190
|
+
The root entry (`@aranova/tracking-react`) still re-exports `createSalesClient` and the
|
|
191
|
+
money/date helpers for back-compat, so existing imports keep working — but prefer `/sales`
|
|
192
|
+
in server code so the React surface never reaches your server bundle.
|
|
193
|
+
|
|
182
194
|
Generate the typed `AranovaService` union from your dashboard services with the CLI
|
|
183
195
|
(install it as a **devDependency**):
|
|
184
196
|
|
|
@@ -195,10 +207,10 @@ and the CLI reference: [cli.md](https://github.com/AranovaIO/aranova_internal/bl
|
|
|
195
207
|
The bundled `<ConsentBanner />` renders a non-blocking bottom-docked banner while consent is `pending`, persists the visitor's choice to `localStorage`, and propagates it to Google Consent Mode v2 when gtag is loaded. **Inline-styled** — no Tailwind or CSS imports required at the consumer.
|
|
196
208
|
|
|
197
209
|
```tsx
|
|
198
|
-
import { ConsentBanner } from
|
|
210
|
+
import { ConsentBanner } from "@aranova/tracking-react";
|
|
199
211
|
|
|
200
212
|
// Drop-in, defaults work everywhere
|
|
201
|
-
<ConsentBanner
|
|
213
|
+
<ConsentBanner />;
|
|
202
214
|
```
|
|
203
215
|
|
|
204
216
|
All props are optional:
|
|
@@ -210,13 +222,13 @@ All props are optional:
|
|
|
210
222
|
acceptLabel="Sure"
|
|
211
223
|
declineLabel="No thanks"
|
|
212
224
|
policyHref="/privacy"
|
|
213
|
-
policyLabel="Privacy policy"
|
|
214
|
-
onAccept={() => track(
|
|
215
|
-
onDecline={() => track(
|
|
216
|
-
position="bottom"
|
|
217
|
-
theme="light"
|
|
225
|
+
policyLabel="Privacy policy" // default: "Learn more"
|
|
226
|
+
onAccept={() => track("consent_accepted")}
|
|
227
|
+
onDecline={() => track("consent_declined")}
|
|
228
|
+
position="bottom" // or "top"
|
|
229
|
+
theme="light" // "light" | "dark" | "auto"
|
|
218
230
|
className="my-extra-classes"
|
|
219
|
-
style={{ background:
|
|
231
|
+
style={{ background: "#fafafa" }} // wins over the theme defaults
|
|
220
232
|
/>
|
|
221
233
|
```
|
|
222
234
|
|
|
@@ -225,7 +237,7 @@ All props are optional:
|
|
|
225
237
|
For a bespoke banner, skip the component and drive your own UI with the headless hook:
|
|
226
238
|
|
|
227
239
|
```tsx
|
|
228
|
-
import { useConsent } from
|
|
240
|
+
import { useConsent } from "@aranova/tracking-react";
|
|
229
241
|
|
|
230
242
|
function CookieBar() {
|
|
231
243
|
const { state, accept, decline, reset, isPending } = useConsent();
|
|
@@ -254,8 +266,7 @@ The hook handles localStorage persistence, gtag sync, and cross-tab propagation
|
|
|
254
266
|
- Consent hooks: `useConsent()` + `UseConsentResult` (headless); `useConsentState()` (read-only alias)
|
|
255
267
|
- Standalone consent helpers: `getConsentState()`, `setConsentState()`, `resetConsent()`
|
|
256
268
|
- Attribution hooks: `useTrackingParams()`, `useGclid()`
|
|
257
|
-
- `createSalesClient()` (isomorphic — public key writes; secret key reads/CRUD, `summary`, `customers.*`, `business.config`) + money/date helpers (`toMinor`/`fromMinor`/`formatMoney`/`formatDateInTz`)
|
|
269
|
+
- `createSalesClient()` (isomorphic — public key writes; secret key reads/CRUD, `summary`, `customers.*`, `business.config`) + money/date helpers (`toMinor`/`fromMinor`/`formatMoney`/`formatDateInTz`). Also available React-free at **`@aranova/tracking-react/sales`** (with all sale/customer/config types) — the recommended import for server/serverless code.
|
|
258
270
|
- Phone: `parsePhone`/`toE164`/`formatPhone`/`formatPhoneAsTyped`/`phoneField`, `usePhoneField`, `PhoneField` (utils also at `/phone`)
|
|
259
271
|
- Codegen: [`@aranova/tracking-cli`](https://www.npmjs.com/package/@aranova/tracking-cli) — `gen` typed service unions (devDependency)
|
|
260
272
|
- Event metadata/config types such as `FormSubmitMetadata`, `PhoneClickMetadata`, and `JsonValue`
|
|
261
|
-
|