@aranova/tracking-next 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 +58 -49
- package/dist/index.d.mts +61 -802
- package/dist/index.d.ts +61 -802
- package/dist/index.js +175 -53
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +168 -59
- package/dist/index.mjs.map +1 -1
- package/dist/middleware.js +98 -0
- package/dist/middleware.js.map +1 -1
- package/dist/middleware.mjs +98 -0
- package/dist/middleware.mjs.map +1 -1
- package/dist/{phone-utils-DZ0Ger64.d.mts → phone-utils-dd1tW7sb.d.mts} +7 -6
- package/dist/{phone-utils-DZ0Ger64.d.ts → phone-utils-dd1tW7sb.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/dist/server.d.mts +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/server.js +98 -0
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +98 -0
- package/dist/server.mjs.map +1 -1
- package/package.json +46 -13
package/README.md
CHANGED
|
@@ -14,12 +14,12 @@ Install the tracking middleware so `gclid`, `fbclid`, and UTM params are written
|
|
|
14
14
|
|
|
15
15
|
```ts
|
|
16
16
|
// middleware.ts
|
|
17
|
-
import { createTrackingMiddleware } from
|
|
17
|
+
import { createTrackingMiddleware } from "@aranova/tracking-next/middleware";
|
|
18
18
|
|
|
19
19
|
export default createTrackingMiddleware();
|
|
20
20
|
|
|
21
21
|
export const config = {
|
|
22
|
-
matcher: [
|
|
22
|
+
matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"],
|
|
23
23
|
};
|
|
24
24
|
```
|
|
25
25
|
|
|
@@ -29,7 +29,7 @@ Create one shared tracking module and use its scoped exports throughout your app
|
|
|
29
29
|
|
|
30
30
|
```ts
|
|
31
31
|
// lib/tracking.ts
|
|
32
|
-
import { createTracking } from
|
|
32
|
+
import { createTracking } from "@aranova/tracking-next";
|
|
33
33
|
|
|
34
34
|
export const { TrackingProvider, useTracking } = createTracking({
|
|
35
35
|
apiKey: process.env.NEXT_PUBLIC_ARANOVA_TRACKING_API_KEY!,
|
|
@@ -39,7 +39,7 @@ export const { TrackingProvider, useTracking } = createTracking({
|
|
|
39
39
|
page_view: {},
|
|
40
40
|
time_on_site: { thresholdSeconds: 60 },
|
|
41
41
|
specific_page_visit: {
|
|
42
|
-
pages: [{ name:
|
|
42
|
+
pages: [{ name: "contact_page", pathPattern: /^\/(contact|book|get-started)/ }],
|
|
43
43
|
},
|
|
44
44
|
},
|
|
45
45
|
manual: {
|
|
@@ -48,7 +48,7 @@ export const { TrackingProvider, useTracking } = createTracking({
|
|
|
48
48
|
cta_click: {},
|
|
49
49
|
},
|
|
50
50
|
},
|
|
51
|
-
debug: process.env.NODE_ENV !==
|
|
51
|
+
debug: process.env.NODE_ENV !== "production",
|
|
52
52
|
});
|
|
53
53
|
```
|
|
54
54
|
|
|
@@ -56,8 +56,8 @@ Wrap the root layout.
|
|
|
56
56
|
|
|
57
57
|
```tsx
|
|
58
58
|
// app/layout.tsx
|
|
59
|
-
import { ConsentBanner, GoogleAdsTracking } from
|
|
60
|
-
import { TrackingProvider } from
|
|
59
|
+
import { ConsentBanner, GoogleAdsTracking } from "@aranova/tracking-next";
|
|
60
|
+
import { TrackingProvider } from "@/lib/tracking";
|
|
61
61
|
|
|
62
62
|
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
63
63
|
return (
|
|
@@ -85,7 +85,7 @@ account plus a test MCC. Each entry fires `gtag('config', …)` on every page; t
|
|
|
85
85
|
the dashboard's SDK table. Pass `environment` to the factory to tag events for dashboard filtering.
|
|
86
86
|
|
|
87
87
|
```tsx
|
|
88
|
-
<GoogleAdsTracking gtagIds={{ production:
|
|
88
|
+
<GoogleAdsTracking gtagIds={{ production: "AW-111111111", test: "AW-222222222" }} />
|
|
89
89
|
```
|
|
90
90
|
|
|
91
91
|
## Manual Events
|
|
@@ -93,9 +93,9 @@ the dashboard's SDK table. Pass `environment` to the factory to tag events for d
|
|
|
93
93
|
Import `useTracking` from your local `lib/tracking` module, not directly from the package.
|
|
94
94
|
|
|
95
95
|
```tsx
|
|
96
|
-
|
|
96
|
+
"use client";
|
|
97
97
|
|
|
98
|
-
import { useTracking } from
|
|
98
|
+
import { useTracking } from "@/lib/tracking";
|
|
99
99
|
|
|
100
100
|
export function LeadForm() {
|
|
101
101
|
const tracking = useTracking();
|
|
@@ -108,22 +108,22 @@ export function LeadForm() {
|
|
|
108
108
|
const form = event.currentTarget;
|
|
109
109
|
const data = new FormData(form);
|
|
110
110
|
|
|
111
|
-
tracking.trackEvent(
|
|
111
|
+
tracking.trackEvent("form_submit", {
|
|
112
112
|
form: {
|
|
113
113
|
id: form.id,
|
|
114
|
-
action: form.getAttribute(
|
|
114
|
+
action: form.getAttribute("action"),
|
|
115
115
|
fields: [
|
|
116
116
|
{
|
|
117
|
-
name:
|
|
118
|
-
type:
|
|
119
|
-
label:
|
|
120
|
-
value: String(data.get(
|
|
117
|
+
name: "service_interest",
|
|
118
|
+
type: "select",
|
|
119
|
+
label: "Service interest",
|
|
120
|
+
value: String(data.get("service_interest") ?? ""),
|
|
121
121
|
},
|
|
122
122
|
{
|
|
123
|
-
name:
|
|
124
|
-
type:
|
|
125
|
-
label:
|
|
126
|
-
value: data.get(
|
|
123
|
+
name: "is_existing_patient",
|
|
124
|
+
type: "checkbox",
|
|
125
|
+
label: "Existing patient",
|
|
126
|
+
value: data.get("is_existing_patient") === "on",
|
|
127
127
|
},
|
|
128
128
|
],
|
|
129
129
|
},
|
|
@@ -145,11 +145,11 @@ Bundled `libphonenumber-js`: parse/format utils + a React input. Display is conf
|
|
|
145
145
|
value sent to the backend is **always E.164**. Configure once via `createTracking({ phone: { defaultCountry: 'CA', display: 'national' } })`.
|
|
146
146
|
|
|
147
147
|
```tsx
|
|
148
|
-
|
|
149
|
-
import { usePhoneField, PhoneField, toE164 } from
|
|
148
|
+
"use client";
|
|
149
|
+
import { usePhoneField, PhoneField, toE164 } from "@aranova/tracking-next";
|
|
150
150
|
|
|
151
|
-
const phone = usePhoneField();
|
|
152
|
-
<input {...phone.inputProps} />;
|
|
151
|
+
const phone = usePhoneField(); // phone.value (display), phone.e164 (wire), .isValid, .error
|
|
152
|
+
<input {...phone.inputProps} />; // or the batteries-included <PhoneField name="phone" />
|
|
153
153
|
```
|
|
154
154
|
|
|
155
155
|
Pure, isomorphic utils (usable in Server Components / route handlers) are at
|
|
@@ -161,11 +161,11 @@ Pure, isomorphic utils (usable in Server Components / route handlers) are at
|
|
|
161
161
|
Read attribution cookies from Server Components or server actions.
|
|
162
162
|
|
|
163
163
|
```tsx
|
|
164
|
-
import { getTrackingParamsServer } from
|
|
164
|
+
import { getTrackingParamsServer } from "@aranova/tracking-next/server";
|
|
165
165
|
|
|
166
166
|
export default function Page() {
|
|
167
167
|
const { gclid, utm_source } = getTrackingParamsServer();
|
|
168
|
-
return gclid || utm_source ===
|
|
168
|
+
return gclid || utm_source === "google" ? <GoogleLanding /> : <OrganicLanding />;
|
|
169
169
|
}
|
|
170
170
|
```
|
|
171
171
|
|
|
@@ -179,30 +179,39 @@ key may do is enforced by the backend, not by hiding methods. Browser write with
|
|
|
179
179
|
your **public** key, from a client component:
|
|
180
180
|
|
|
181
181
|
```tsx
|
|
182
|
-
|
|
183
|
-
import { createSalesClient, toMinor } from
|
|
182
|
+
"use client";
|
|
183
|
+
import { createSalesClient, toMinor } from "@aranova/tracking-next";
|
|
184
184
|
|
|
185
|
-
const sales = createSalesClient({
|
|
186
|
-
|
|
185
|
+
const sales = createSalesClient({
|
|
186
|
+
apiKey: process.env.NEXT_PUBLIC_ARANOVA_TRACKING_API_KEY!,
|
|
187
|
+
endpoint,
|
|
188
|
+
});
|
|
189
|
+
await sales.record({ currency: "CAD", amount_total_cents: toMinor(250, "CAD"), service: "tires" });
|
|
187
190
|
```
|
|
188
191
|
|
|
189
|
-
Full CRUD from a route handler / server action
|
|
190
|
-
|
|
192
|
+
Full CRUD from a route handler / server action / **Server Component** with your
|
|
193
|
+
**secret** key. Import from the **`/sales`** subpath — it's React-free, so it loads
|
|
194
|
+
in an RSC or any server module without dragging the provider/components into the
|
|
195
|
+
server graph (keep the secret key in server env, never in client code):
|
|
191
196
|
|
|
192
197
|
```ts
|
|
193
|
-
import { createSalesClient } from
|
|
194
|
-
import type { AranovaService } from
|
|
198
|
+
import { createSalesClient } from "@aranova/tracking-next/sales";
|
|
199
|
+
import type { AranovaService } from "./aranova-services"; // generated, see below
|
|
195
200
|
|
|
196
201
|
const sales = createSalesClient<AranovaService>({
|
|
197
202
|
apiKey: process.env.ARANOVA_TRACKING_SECRET_KEY!,
|
|
198
203
|
endpoint: process.env.ARANOVA_TRACKING_ENDPOINT!,
|
|
199
204
|
});
|
|
200
|
-
await sales.list({ sort:
|
|
201
|
-
await sales.summary({ range:
|
|
202
|
-
await sales.customers.list({ segment:
|
|
203
|
-
const cfg = await sales.business.config();
|
|
205
|
+
await sales.list({ sort: "amount_total_cents", want_total: true }); // → { items, total_count, … }
|
|
206
|
+
await sales.summary({ range: "mtd", timezone: "America/Toronto", compare_to: "previous_period" });
|
|
207
|
+
await sales.customers.list({ segment: "returning", sort: "total_spent" }); // phone-keyed roster
|
|
208
|
+
const cfg = await sales.business.config(); // tz / currencies / services
|
|
204
209
|
```
|
|
205
210
|
|
|
211
|
+
The root entry (`@aranova/tracking-next`) still re-exports `createSalesClient` and the
|
|
212
|
+
money/date helpers for back-compat, so existing imports keep working — but prefer
|
|
213
|
+
`/sales` in server code so the React surface never reaches your server bundle.
|
|
214
|
+
|
|
206
215
|
Dashboard reads are all currency-grouped (never summed). `summary()` gains tz-aware calendar/custom
|
|
207
216
|
ranges, `granularity`, and period-over-period `compare_to` (legacy `24h/7d/30d` unchanged); a
|
|
208
217
|
**customer is their phone (E.164)**, so `customers.*` is a live roster with no separate table.
|
|
@@ -224,10 +233,10 @@ and the CLI reference: [cli.md](https://github.com/AranovaIO/aranova_internal/bl
|
|
|
224
233
|
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.
|
|
225
234
|
|
|
226
235
|
```tsx
|
|
227
|
-
import { ConsentBanner } from
|
|
236
|
+
import { ConsentBanner } from "@aranova/tracking-next";
|
|
228
237
|
|
|
229
238
|
// Drop-in (already wired in the root layout example above)
|
|
230
|
-
<ConsentBanner
|
|
239
|
+
<ConsentBanner />;
|
|
231
240
|
```
|
|
232
241
|
|
|
233
242
|
All props are optional:
|
|
@@ -239,13 +248,13 @@ All props are optional:
|
|
|
239
248
|
acceptLabel="Sure"
|
|
240
249
|
declineLabel="No thanks"
|
|
241
250
|
policyHref="/privacy"
|
|
242
|
-
policyLabel="Privacy policy"
|
|
243
|
-
onAccept={() => track(
|
|
244
|
-
onDecline={() => track(
|
|
245
|
-
position="bottom"
|
|
246
|
-
theme="light"
|
|
251
|
+
policyLabel="Privacy policy" // default: "Learn more"
|
|
252
|
+
onAccept={() => track("consent_accepted")}
|
|
253
|
+
onDecline={() => track("consent_declined")}
|
|
254
|
+
position="bottom" // or "top"
|
|
255
|
+
theme="light" // "light" | "dark" | "auto"
|
|
247
256
|
className="my-extra-classes"
|
|
248
|
-
style={{ background:
|
|
257
|
+
style={{ background: "#fafafa" }} // wins over the theme defaults
|
|
249
258
|
/>
|
|
250
259
|
```
|
|
251
260
|
|
|
@@ -254,8 +263,8 @@ All props are optional:
|
|
|
254
263
|
For a bespoke banner, skip the component and drive your own UI with the headless hook:
|
|
255
264
|
|
|
256
265
|
```tsx
|
|
257
|
-
|
|
258
|
-
import { useConsent } from
|
|
266
|
+
"use client";
|
|
267
|
+
import { useConsent } from "@aranova/tracking-next";
|
|
259
268
|
|
|
260
269
|
function CookieBar() {
|
|
261
270
|
const { state, accept, decline, reset, isPending } = useConsent();
|
|
@@ -278,8 +287,8 @@ The hook handles localStorage persistence, gtag sync, and cross-tab propagation
|
|
|
278
287
|
## Exports
|
|
279
288
|
|
|
280
289
|
- Root package: `createTracking`, `TrackingProvider`, `useTracking`, `GoogleAdsTracking`, `ConsentBanner` (+ `ConsentBannerProps`), consent hooks/helpers, attribution hooks, event types; `createSalesClient()` (isomorphic — public key writes; secret key reads/CRUD, `summary`, `customers.*`, `business.config`) + `toMinor`/`fromMinor`/`formatMoney`/`formatDateInTz`; phone (`parsePhone`/`toE164`/`formatPhone`/`phoneField`, `usePhoneField`, `PhoneField`)
|
|
290
|
+
- `@aranova/tracking-next/sales`: **React-free** server-safe SDK — `createSalesClient`, money/date helpers, and all sale/customer/config types. Use this in Server Components, route handlers, and Node servers; the root entry re-exports the same symbols for back-compat.
|
|
281
291
|
- `@aranova/tracking-next/middleware`: `createTrackingMiddleware()`
|
|
282
292
|
- `@aranova/tracking-next/server`: `getTrackingParamsServer()`
|
|
283
293
|
- `@aranova/tracking-next/phone`: isomorphic phone utils (no React)
|
|
284
294
|
- Codegen: [`@aranova/tracking-cli`](https://www.npmjs.com/package/@aranova/tracking-cli) — `gen` typed service unions (devDependency)
|
|
285
|
-
|