@aranova/tracking-next 0.9.0 → 0.10.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 +64 -3
- package/dist/index.d.mts +178 -6
- package/dist/index.d.ts +178 -6
- package/dist/index.js +241 -58
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +241 -60
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -200,10 +200,15 @@ const sales = createSalesClient<AranovaService>({
|
|
|
200
200
|
endpoint: process.env.ARANOVA_TRACKING_ENDPOINT!,
|
|
201
201
|
});
|
|
202
202
|
const { items, next_cursor } = await sales.list({ limit: 50 });
|
|
203
|
+
const summary = await sales.summary({ range: '30d' }); // currency-grouped aggregations
|
|
203
204
|
```
|
|
204
205
|
|
|
205
|
-
|
|
206
|
-
|
|
206
|
+
`sales.summary({ range })` returns revenue and average order value per currency,
|
|
207
|
+
distinct customers, by-service / by-currency / by-category breakdowns, and a
|
|
208
|
+
revenue/count trend — a secret-key read scoped to the key's business.
|
|
209
|
+
|
|
210
|
+
A public-key client calling `list`/`summary`/`get`/`update`/`delete` gets a `403`
|
|
211
|
+
telling it to use a secret key server-side.
|
|
207
212
|
|
|
208
213
|
Generate the typed `AranovaService` union from your dashboard services with the CLI
|
|
209
214
|
(install it as a **devDependency**):
|
|
@@ -216,9 +221,65 @@ npx @aranova/tracking-cli gen # reads ARANOVA_TRACKING_SECRET_KEY from
|
|
|
216
221
|
See the full guide: [sales-tracking.md](https://github.com/AranovaIO/aranova_internal/blob/master/docs/tracking-package/sales-tracking.md)
|
|
217
222
|
and the CLI reference: [cli.md](https://github.com/AranovaIO/aranova_internal/blob/master/docs/tracking-package/cli.md).
|
|
218
223
|
|
|
224
|
+
## Consent UI
|
|
225
|
+
|
|
226
|
+
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.
|
|
227
|
+
|
|
228
|
+
```tsx
|
|
229
|
+
import { ConsentBanner } from '@aranova/tracking-next';
|
|
230
|
+
|
|
231
|
+
// Drop-in (already wired in the root layout example above)
|
|
232
|
+
<ConsentBanner />
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
All props are optional:
|
|
236
|
+
|
|
237
|
+
```tsx
|
|
238
|
+
<ConsentBanner
|
|
239
|
+
title="Cookies"
|
|
240
|
+
message="We use cookies to track ad performance."
|
|
241
|
+
acceptLabel="Sure"
|
|
242
|
+
declineLabel="No thanks"
|
|
243
|
+
policyHref="/privacy"
|
|
244
|
+
policyLabel="Privacy policy" // default: "Learn more"
|
|
245
|
+
onAccept={() => track('consent_accepted')}
|
|
246
|
+
onDecline={() => track('consent_declined')}
|
|
247
|
+
position="bottom" // or "top"
|
|
248
|
+
theme="light" // "light" | "dark" | "auto"
|
|
249
|
+
className="my-extra-classes"
|
|
250
|
+
style={{ background: '#fafafa' }} // wins over the theme defaults
|
|
251
|
+
/>
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Fully custom UI — `useConsent()`
|
|
255
|
+
|
|
256
|
+
For a bespoke banner, skip the component and drive your own UI with the headless hook:
|
|
257
|
+
|
|
258
|
+
```tsx
|
|
259
|
+
'use client';
|
|
260
|
+
import { useConsent } from '@aranova/tracking-next';
|
|
261
|
+
|
|
262
|
+
function CookieBar() {
|
|
263
|
+
const { state, accept, decline, reset, isPending } = useConsent();
|
|
264
|
+
|
|
265
|
+
if (!isPending) {
|
|
266
|
+
// Footer link: re-open the banner if they change their mind.
|
|
267
|
+
return <button onClick={reset}>Cookie preferences</button>;
|
|
268
|
+
}
|
|
269
|
+
return (
|
|
270
|
+
<MyBespokeBanner>
|
|
271
|
+
<button onClick={decline}>No thanks</button>
|
|
272
|
+
<button onClick={accept}>Sure</button>
|
|
273
|
+
</MyBespokeBanner>
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
The hook handles localStorage persistence, gtag sync, and cross-tab propagation — same machinery the default banner uses. `resetConsent()` is also exported as a standalone for non-component contexts (server actions that revalidate after an account change, etc.).
|
|
279
|
+
|
|
219
280
|
## Exports
|
|
220
281
|
|
|
221
|
-
- Root package: `createTracking`, `TrackingProvider`, `useTracking`, `GoogleAdsTracking`, `ConsentBanner`,
|
|
282
|
+
- Root package: `createTracking`, `TrackingProvider`, `useTracking`, `GoogleAdsTracking`, `ConsentBanner` (+ `ConsentBannerProps`), `useConsent` (+ `UseConsentResult`), `useConsentState`, `useGclid`, `useTrackingParams`, standalone consent helpers (`getConsentState`, `setConsentState`, `resetConsent`), event types, and `createSalesClient()` (isomorphic sales client — public key writes, secret key reads/CRUD) + money helpers (`toMinor`/`fromMinor`/`formatMoney`)
|
|
222
283
|
- `@aranova/tracking-next/middleware`: `createTrackingMiddleware()`
|
|
223
284
|
- `@aranova/tracking-next/server`: `getTrackingParamsServer()`
|
|
224
285
|
- Codegen: [`@aranova/tracking-cli`](https://www.npmjs.com/package/@aranova/tracking-cli) — `gen` typed service unions (devDependency)
|
package/dist/index.d.mts
CHANGED
|
@@ -2,8 +2,8 @@ import { C as ConsentState, T as TrackingInstallSurface, a as TrackingEnvironmen
|
|
|
2
2
|
export { f as TrackingInitConfig } from './types-BPJLgMsG.mjs';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import * as src from 'src';
|
|
5
|
+
import { ReactNode, CSSProperties } from 'react';
|
|
5
6
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
6
|
-
import { ReactNode } from 'react';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Google Consent Mode value sent to `gtag('consent', 'update', ...)`.
|
|
@@ -21,6 +21,22 @@ declare function getConsentState(): ConsentState;
|
|
|
21
21
|
* loaded.
|
|
22
22
|
*/
|
|
23
23
|
declare function setConsentState(state: GtagConsentValue): void;
|
|
24
|
+
/**
|
|
25
|
+
* Clear the stored consent choice so the banner re-appears on next render.
|
|
26
|
+
*
|
|
27
|
+
* Power a "Cookie preferences" link in a footer so visitors can change their
|
|
28
|
+
* mind without losing access to your site:
|
|
29
|
+
*
|
|
30
|
+
* ```tsx
|
|
31
|
+
* const { reset } = useConsent();
|
|
32
|
+
* <button onClick={reset}>Cookie preferences</button>
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* Does NOT push an `update` to gtag — there's nothing to update because the
|
|
36
|
+
* visitor hasn't chosen anything yet. The next `setConsentState()` call will
|
|
37
|
+
* sync gtag once they re-choose.
|
|
38
|
+
*/
|
|
39
|
+
declare function resetConsent(): void;
|
|
24
40
|
|
|
25
41
|
interface TrackingContextInput {
|
|
26
42
|
packageName?: string | null;
|
|
@@ -1487,6 +1503,61 @@ interface SaleListQuery extends SaleFilters {
|
|
|
1487
1503
|
limit?: number;
|
|
1488
1504
|
cursor?: string | null;
|
|
1489
1505
|
}
|
|
1506
|
+
declare const TRACKING_RANGES: readonly ["24h", "7d", "30d"];
|
|
1507
|
+
type TrackingOverviewRange = (typeof TRACKING_RANGES)[number];
|
|
1508
|
+
/** Query input for `SalesClient.summary()` — filters + range + options. */
|
|
1509
|
+
interface SaleSummaryQuery extends SaleFilters {
|
|
1510
|
+
range: TrackingOverviewRange;
|
|
1511
|
+
/** Include the per-category line-item breakdown (extra join; default false). */
|
|
1512
|
+
include_categories?: boolean;
|
|
1513
|
+
/** Surface soft-deleted services individually (flagged "(deleted)") instead of
|
|
1514
|
+
* rolling them into a single "Deleted services" bucket. Default false. */
|
|
1515
|
+
include_deleted_services?: boolean;
|
|
1516
|
+
/** Cap on the by-service / by-category rows (1–50, default 10). */
|
|
1517
|
+
top_n?: number;
|
|
1518
|
+
}
|
|
1519
|
+
interface CurrencyRevenue {
|
|
1520
|
+
currency: SupportedCurrency;
|
|
1521
|
+
sale_count: number;
|
|
1522
|
+
revenue_cents: number;
|
|
1523
|
+
average_order_value_cents: number;
|
|
1524
|
+
}
|
|
1525
|
+
interface SalesServiceBreakdown {
|
|
1526
|
+
service_id: string | null;
|
|
1527
|
+
service_key: string | null;
|
|
1528
|
+
/** "Unassigned" when the sale has no service. */
|
|
1529
|
+
service_label: string | null;
|
|
1530
|
+
currency: SupportedCurrency;
|
|
1531
|
+
sale_count: number;
|
|
1532
|
+
revenue_cents: number;
|
|
1533
|
+
}
|
|
1534
|
+
interface SalesCategoryBreakdown {
|
|
1535
|
+
category: string | null;
|
|
1536
|
+
currency: SupportedCurrency;
|
|
1537
|
+
/** sum(unit_price_cents * quantity) — advisory, not authoritative. */
|
|
1538
|
+
revenue_cents: number;
|
|
1539
|
+
/** Decimal string. */
|
|
1540
|
+
quantity: string;
|
|
1541
|
+
}
|
|
1542
|
+
interface SalesTrendPoint {
|
|
1543
|
+
bucket_start: string;
|
|
1544
|
+
currency: SupportedCurrency;
|
|
1545
|
+
sale_count: number;
|
|
1546
|
+
revenue_cents: number;
|
|
1547
|
+
}
|
|
1548
|
+
interface SaleSummary {
|
|
1549
|
+
range: TrackingOverviewRange;
|
|
1550
|
+
business_id: string | null;
|
|
1551
|
+
metrics: {
|
|
1552
|
+
sale_count: number;
|
|
1553
|
+
distinct_customers: number;
|
|
1554
|
+
by_currency: CurrencyRevenue[];
|
|
1555
|
+
};
|
|
1556
|
+
by_service: SalesServiceBreakdown[];
|
|
1557
|
+
by_currency: CurrencyRevenue[];
|
|
1558
|
+
by_category: SalesCategoryBreakdown[];
|
|
1559
|
+
series: SalesTrendPoint[];
|
|
1560
|
+
}
|
|
1490
1561
|
|
|
1491
1562
|
/** Shared config for every sales HTTP helper. */
|
|
1492
1563
|
interface SalesTransportConfig {
|
|
@@ -1526,6 +1597,12 @@ interface SalesClient<TService extends string = string> {
|
|
|
1526
1597
|
occurred_at?: string;
|
|
1527
1598
|
}): Promise<Sale>;
|
|
1528
1599
|
list(query?: SaleListQuery): Promise<SaleCursorPage>;
|
|
1600
|
+
/**
|
|
1601
|
+
* Currency-grouped aggregations for the key's business (revenue per currency,
|
|
1602
|
+
* AOV, distinct customers, by-service / by-currency / by-category breakdowns,
|
|
1603
|
+
* and a revenue/count trend). Secret key only — a public key gets a `403`.
|
|
1604
|
+
*/
|
|
1605
|
+
summary(query: SaleSummaryQuery): Promise<SaleSummary>;
|
|
1529
1606
|
get(id: string): Promise<Sale>;
|
|
1530
1607
|
update(id: string, patch: Omit<SaleUpdateInput, 'service'> & {
|
|
1531
1608
|
service?: TService | null;
|
|
@@ -1580,12 +1657,69 @@ declare class AranovaApiError extends Error {
|
|
|
1580
1657
|
}
|
|
1581
1658
|
|
|
1582
1659
|
/**
|
|
1583
|
-
* Default non-blocking consent banner
|
|
1660
|
+
* Default non-blocking consent banner.
|
|
1661
|
+
*
|
|
1662
|
+
* Renders only while consent is `pending`; collapses to `null` once the
|
|
1663
|
+
* visitor has chosen.
|
|
1664
|
+
*
|
|
1665
|
+
* **Styling is intentionally self-contained** — inline styles, zero CSS
|
|
1666
|
+
* dependencies, no Tailwind required at the consumer. The Tailwind-based
|
|
1667
|
+
* banner shipped before 0.9.1 rendered as transparent in any consumer that
|
|
1668
|
+
* didn't configure their content array to scan
|
|
1669
|
+
* `node_modules/@aranova/tracking-next/dist/**`; this version sidesteps that
|
|
1670
|
+
* class of bug entirely.
|
|
1671
|
+
*
|
|
1672
|
+
* For a fully bespoke banner, skip this component and use {@link useConsent}
|
|
1673
|
+
* directly to drive your own UI.
|
|
1674
|
+
*
|
|
1675
|
+
* @example
|
|
1676
|
+
* // Drop-in default
|
|
1677
|
+
* <ConsentBanner />
|
|
1584
1678
|
*
|
|
1585
|
-
*
|
|
1586
|
-
*
|
|
1679
|
+
* @example
|
|
1680
|
+
* // Customized
|
|
1681
|
+
* <ConsentBanner
|
|
1682
|
+
* message="We use cookies to learn which ads drive bookings."
|
|
1683
|
+
* acceptLabel="Sounds good"
|
|
1684
|
+
* declineLabel="No thanks"
|
|
1685
|
+
* policyHref="/privacy"
|
|
1686
|
+
* policyLabel="Privacy policy"
|
|
1687
|
+
* theme="dark"
|
|
1688
|
+
* onAccept={() => track('consent_accepted')}
|
|
1689
|
+
* onDecline={() => track('consent_declined')}
|
|
1690
|
+
* />
|
|
1587
1691
|
*/
|
|
1588
|
-
|
|
1692
|
+
interface ConsentBannerProps {
|
|
1693
|
+
/** Body text. Defaults to the standard cookies-for-ad-performance message. */
|
|
1694
|
+
message?: ReactNode;
|
|
1695
|
+
/** Optional bold title above the body text. */
|
|
1696
|
+
title?: ReactNode;
|
|
1697
|
+
/** Label for the accept button. Default: `"Accept"`. */
|
|
1698
|
+
acceptLabel?: string;
|
|
1699
|
+
/** Label for the decline button. Default: `"Decline"`. */
|
|
1700
|
+
declineLabel?: string;
|
|
1701
|
+
/** Optional link inline with the message (e.g. to a privacy policy). */
|
|
1702
|
+
policyHref?: string;
|
|
1703
|
+
/** Visible text for {@link policyHref}. Default: `"Learn more"`. */
|
|
1704
|
+
policyLabel?: string;
|
|
1705
|
+
/**
|
|
1706
|
+
* Fires after the consent state is persisted + propagated to gtag. Useful
|
|
1707
|
+
* for emitting your own analytics event on the choice.
|
|
1708
|
+
*/
|
|
1709
|
+
onAccept?: () => void;
|
|
1710
|
+
onDecline?: () => void;
|
|
1711
|
+
/** Where the banner docks. Default: `"bottom"`. */
|
|
1712
|
+
position?: 'top' | 'bottom';
|
|
1713
|
+
/**
|
|
1714
|
+
* Visual theme. `"auto"` follows `prefers-color-scheme`. Default: `"light"`.
|
|
1715
|
+
*/
|
|
1716
|
+
theme?: 'light' | 'dark' | 'auto';
|
|
1717
|
+
/** Class added to the outer wrapper for additional styling hooks. */
|
|
1718
|
+
className?: string;
|
|
1719
|
+
/** Inline style overrides applied to the outer wrapper after the defaults. */
|
|
1720
|
+
style?: CSSProperties;
|
|
1721
|
+
}
|
|
1722
|
+
declare function ConsentBanner({ message, title, acceptLabel, declineLabel, policyHref, policyLabel, onAccept, onDecline, position, theme, className, style, }?: ConsentBannerProps): ReactNode;
|
|
1589
1723
|
|
|
1590
1724
|
/**
|
|
1591
1725
|
* Read the captured Google Ads click id from first-party cookies.
|
|
@@ -1602,8 +1736,46 @@ declare function useTrackingParams(): TrackingParams;
|
|
|
1602
1736
|
/**
|
|
1603
1737
|
* Read the current visitor consent state and update when another tab changes
|
|
1604
1738
|
* the stored value.
|
|
1739
|
+
*
|
|
1740
|
+
* Prefer {@link useConsent} for new code — it returns the same state plus
|
|
1741
|
+
* the `accept` / `decline` / `reset` actions a custom consent UI needs.
|
|
1742
|
+
* `useConsentState` is kept as a convenience for callers that only need to
|
|
1743
|
+
* read.
|
|
1605
1744
|
*/
|
|
1606
1745
|
declare function useConsentState(): ConsentState;
|
|
1746
|
+
/**
|
|
1747
|
+
* The headless consent surface — state + actions in one hook.
|
|
1748
|
+
*
|
|
1749
|
+
* Build a fully-custom banner without losing the gtag-sync, localStorage
|
|
1750
|
+
* persistence, or cross-tab propagation:
|
|
1751
|
+
*
|
|
1752
|
+
* ```tsx
|
|
1753
|
+
* const { state, accept, decline, reset, isPending } = useConsent();
|
|
1754
|
+
*
|
|
1755
|
+
* if (!isPending) {
|
|
1756
|
+
* return <button onClick={reset}>Cookie preferences</button>;
|
|
1757
|
+
* }
|
|
1758
|
+
* return (
|
|
1759
|
+
* <MyBannerStyling>
|
|
1760
|
+
* <button onClick={decline}>No thanks</button>
|
|
1761
|
+
* <button onClick={accept}>Sure</button>
|
|
1762
|
+
* </MyBannerStyling>
|
|
1763
|
+
* );
|
|
1764
|
+
* ```
|
|
1765
|
+
*
|
|
1766
|
+
* The boolean helpers (`isPending` / `isGranted` / `isDenied`) are equivalent
|
|
1767
|
+
* to comparing `state` directly — they're there for readability at call sites.
|
|
1768
|
+
*/
|
|
1769
|
+
interface UseConsentResult {
|
|
1770
|
+
state: ConsentState;
|
|
1771
|
+
isPending: boolean;
|
|
1772
|
+
isGranted: boolean;
|
|
1773
|
+
isDenied: boolean;
|
|
1774
|
+
accept: () => void;
|
|
1775
|
+
decline: () => void;
|
|
1776
|
+
reset: () => void;
|
|
1777
|
+
}
|
|
1778
|
+
declare function useConsent(): UseConsentResult;
|
|
1607
1779
|
|
|
1608
1780
|
/**
|
|
1609
1781
|
* Props for the Next.js Google Ads tracking component.
|
|
@@ -1692,4 +1864,4 @@ interface CreateTrackingResult<TRegistry extends TriggerRegistryConfig> {
|
|
|
1692
1864
|
*/
|
|
1693
1865
|
declare function createTracking<TRegistry extends TriggerRegistryConfig>(options: CreateTrackingOptions<TRegistry>): CreateTrackingResult<TRegistry>;
|
|
1694
1866
|
|
|
1695
|
-
export { AranovaApiError, type AutomaticEventName, ConsentBanner, ConsentState, type CreateTrackingOptions, type CreateTrackingResult, type CtaClickConfig, type CtaClickMetadata, type EventConfig, type EventMetadata, type EventName, type FormStartConfig, type FormStartMetadata, type FormSubmitConfig, type FormSubmitMetadata, GoogleAdsTracking, type GoogleAdsTrackingProps, type JsonValue, type ManualEventName, type MultiPageSessionConfig, type MultiPageSessionMetadata, type PageViewConfig, type PageViewMetadata, type PhoneClickConfig, type PhoneClickMetadata, type PublicServiceItem, type RegisteredAutomaticEvents, type RegisteredManualEvents, type Sale, type SaleCursorPage, type SaleInput, type SaleItem, type SaleItemInput, type SaleListPage, type SaleListQuery, type SaleUpdateInput, type SalesClient, type SalesClientConfig, type SalesTransportConfig, type ScrollDepthConfig, type ScrollDepthMetadata, type SpecificPageName, type SpecificPageVisitConfig, type SpecificPageVisitMetadata, type SupportedCurrency, TRACKING_PARAM_KEYS, type TimeOnSiteConfig, type TimeOnSiteMetadata, type TrackingClient, TrackingClientContext, TrackingEventCreatePayload, TrackingInstallSurface, TrackingParams, type TrackingProviderProps, TrackingSessionUpsertPayload, type TriggerRegistryConfig, type TypedTrackEventOptions, type TypedTrackingClient, captureTrackingParamsFromLocation, createSalesClient, createTracking, createTrackingClientContext, createTrackingEventCreatePayload, createTrackingSessionUpsertPayload, fetchServices, formatMoney, fromMinor, getConsentState, setConsentState, toMinor, useConsentState, useGclid, useTrackingParams };
|
|
1867
|
+
export { AranovaApiError, type AutomaticEventName, ConsentBanner, type ConsentBannerProps, ConsentState, type CreateTrackingOptions, type CreateTrackingResult, type CtaClickConfig, type CtaClickMetadata, type CurrencyRevenue, type EventConfig, type EventMetadata, type EventName, type FormStartConfig, type FormStartMetadata, type FormSubmitConfig, type FormSubmitMetadata, GoogleAdsTracking, type GoogleAdsTrackingProps, type JsonValue, type ManualEventName, type MultiPageSessionConfig, type MultiPageSessionMetadata, type PageViewConfig, type PageViewMetadata, type PhoneClickConfig, type PhoneClickMetadata, type PublicServiceItem, type RegisteredAutomaticEvents, type RegisteredManualEvents, type Sale, type SaleCursorPage, type SaleInput, type SaleItem, type SaleItemInput, type SaleListPage, type SaleListQuery, type SaleSummary, type SaleSummaryQuery, type SaleUpdateInput, type SalesCategoryBreakdown, type SalesClient, type SalesClientConfig, type SalesServiceBreakdown, type SalesTransportConfig, type SalesTrendPoint, type ScrollDepthConfig, type ScrollDepthMetadata, type SpecificPageName, type SpecificPageVisitConfig, type SpecificPageVisitMetadata, type SupportedCurrency, TRACKING_PARAM_KEYS, type TimeOnSiteConfig, type TimeOnSiteMetadata, type TrackingClient, TrackingClientContext, TrackingEventCreatePayload, TrackingInstallSurface, type TrackingOverviewRange, TrackingParams, type TrackingProviderProps, TrackingSessionUpsertPayload, type TriggerRegistryConfig, type TypedTrackEventOptions, type TypedTrackingClient, type UseConsentResult, captureTrackingParamsFromLocation, createSalesClient, createTracking, createTrackingClientContext, createTrackingEventCreatePayload, createTrackingSessionUpsertPayload, fetchServices, formatMoney, fromMinor, getConsentState, resetConsent, setConsentState, toMinor, useConsent, useConsentState, useGclid, useTrackingParams };
|
package/dist/index.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ import { C as ConsentState, T as TrackingInstallSurface, a as TrackingEnvironmen
|
|
|
2
2
|
export { f as TrackingInitConfig } from './types-BPJLgMsG.js';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import * as src from 'src';
|
|
5
|
+
import { ReactNode, CSSProperties } from 'react';
|
|
5
6
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
6
|
-
import { ReactNode } from 'react';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Google Consent Mode value sent to `gtag('consent', 'update', ...)`.
|
|
@@ -21,6 +21,22 @@ declare function getConsentState(): ConsentState;
|
|
|
21
21
|
* loaded.
|
|
22
22
|
*/
|
|
23
23
|
declare function setConsentState(state: GtagConsentValue): void;
|
|
24
|
+
/**
|
|
25
|
+
* Clear the stored consent choice so the banner re-appears on next render.
|
|
26
|
+
*
|
|
27
|
+
* Power a "Cookie preferences" link in a footer so visitors can change their
|
|
28
|
+
* mind without losing access to your site:
|
|
29
|
+
*
|
|
30
|
+
* ```tsx
|
|
31
|
+
* const { reset } = useConsent();
|
|
32
|
+
* <button onClick={reset}>Cookie preferences</button>
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* Does NOT push an `update` to gtag — there's nothing to update because the
|
|
36
|
+
* visitor hasn't chosen anything yet. The next `setConsentState()` call will
|
|
37
|
+
* sync gtag once they re-choose.
|
|
38
|
+
*/
|
|
39
|
+
declare function resetConsent(): void;
|
|
24
40
|
|
|
25
41
|
interface TrackingContextInput {
|
|
26
42
|
packageName?: string | null;
|
|
@@ -1487,6 +1503,61 @@ interface SaleListQuery extends SaleFilters {
|
|
|
1487
1503
|
limit?: number;
|
|
1488
1504
|
cursor?: string | null;
|
|
1489
1505
|
}
|
|
1506
|
+
declare const TRACKING_RANGES: readonly ["24h", "7d", "30d"];
|
|
1507
|
+
type TrackingOverviewRange = (typeof TRACKING_RANGES)[number];
|
|
1508
|
+
/** Query input for `SalesClient.summary()` — filters + range + options. */
|
|
1509
|
+
interface SaleSummaryQuery extends SaleFilters {
|
|
1510
|
+
range: TrackingOverviewRange;
|
|
1511
|
+
/** Include the per-category line-item breakdown (extra join; default false). */
|
|
1512
|
+
include_categories?: boolean;
|
|
1513
|
+
/** Surface soft-deleted services individually (flagged "(deleted)") instead of
|
|
1514
|
+
* rolling them into a single "Deleted services" bucket. Default false. */
|
|
1515
|
+
include_deleted_services?: boolean;
|
|
1516
|
+
/** Cap on the by-service / by-category rows (1–50, default 10). */
|
|
1517
|
+
top_n?: number;
|
|
1518
|
+
}
|
|
1519
|
+
interface CurrencyRevenue {
|
|
1520
|
+
currency: SupportedCurrency;
|
|
1521
|
+
sale_count: number;
|
|
1522
|
+
revenue_cents: number;
|
|
1523
|
+
average_order_value_cents: number;
|
|
1524
|
+
}
|
|
1525
|
+
interface SalesServiceBreakdown {
|
|
1526
|
+
service_id: string | null;
|
|
1527
|
+
service_key: string | null;
|
|
1528
|
+
/** "Unassigned" when the sale has no service. */
|
|
1529
|
+
service_label: string | null;
|
|
1530
|
+
currency: SupportedCurrency;
|
|
1531
|
+
sale_count: number;
|
|
1532
|
+
revenue_cents: number;
|
|
1533
|
+
}
|
|
1534
|
+
interface SalesCategoryBreakdown {
|
|
1535
|
+
category: string | null;
|
|
1536
|
+
currency: SupportedCurrency;
|
|
1537
|
+
/** sum(unit_price_cents * quantity) — advisory, not authoritative. */
|
|
1538
|
+
revenue_cents: number;
|
|
1539
|
+
/** Decimal string. */
|
|
1540
|
+
quantity: string;
|
|
1541
|
+
}
|
|
1542
|
+
interface SalesTrendPoint {
|
|
1543
|
+
bucket_start: string;
|
|
1544
|
+
currency: SupportedCurrency;
|
|
1545
|
+
sale_count: number;
|
|
1546
|
+
revenue_cents: number;
|
|
1547
|
+
}
|
|
1548
|
+
interface SaleSummary {
|
|
1549
|
+
range: TrackingOverviewRange;
|
|
1550
|
+
business_id: string | null;
|
|
1551
|
+
metrics: {
|
|
1552
|
+
sale_count: number;
|
|
1553
|
+
distinct_customers: number;
|
|
1554
|
+
by_currency: CurrencyRevenue[];
|
|
1555
|
+
};
|
|
1556
|
+
by_service: SalesServiceBreakdown[];
|
|
1557
|
+
by_currency: CurrencyRevenue[];
|
|
1558
|
+
by_category: SalesCategoryBreakdown[];
|
|
1559
|
+
series: SalesTrendPoint[];
|
|
1560
|
+
}
|
|
1490
1561
|
|
|
1491
1562
|
/** Shared config for every sales HTTP helper. */
|
|
1492
1563
|
interface SalesTransportConfig {
|
|
@@ -1526,6 +1597,12 @@ interface SalesClient<TService extends string = string> {
|
|
|
1526
1597
|
occurred_at?: string;
|
|
1527
1598
|
}): Promise<Sale>;
|
|
1528
1599
|
list(query?: SaleListQuery): Promise<SaleCursorPage>;
|
|
1600
|
+
/**
|
|
1601
|
+
* Currency-grouped aggregations for the key's business (revenue per currency,
|
|
1602
|
+
* AOV, distinct customers, by-service / by-currency / by-category breakdowns,
|
|
1603
|
+
* and a revenue/count trend). Secret key only — a public key gets a `403`.
|
|
1604
|
+
*/
|
|
1605
|
+
summary(query: SaleSummaryQuery): Promise<SaleSummary>;
|
|
1529
1606
|
get(id: string): Promise<Sale>;
|
|
1530
1607
|
update(id: string, patch: Omit<SaleUpdateInput, 'service'> & {
|
|
1531
1608
|
service?: TService | null;
|
|
@@ -1580,12 +1657,69 @@ declare class AranovaApiError extends Error {
|
|
|
1580
1657
|
}
|
|
1581
1658
|
|
|
1582
1659
|
/**
|
|
1583
|
-
* Default non-blocking consent banner
|
|
1660
|
+
* Default non-blocking consent banner.
|
|
1661
|
+
*
|
|
1662
|
+
* Renders only while consent is `pending`; collapses to `null` once the
|
|
1663
|
+
* visitor has chosen.
|
|
1664
|
+
*
|
|
1665
|
+
* **Styling is intentionally self-contained** — inline styles, zero CSS
|
|
1666
|
+
* dependencies, no Tailwind required at the consumer. The Tailwind-based
|
|
1667
|
+
* banner shipped before 0.9.1 rendered as transparent in any consumer that
|
|
1668
|
+
* didn't configure their content array to scan
|
|
1669
|
+
* `node_modules/@aranova/tracking-next/dist/**`; this version sidesteps that
|
|
1670
|
+
* class of bug entirely.
|
|
1671
|
+
*
|
|
1672
|
+
* For a fully bespoke banner, skip this component and use {@link useConsent}
|
|
1673
|
+
* directly to drive your own UI.
|
|
1674
|
+
*
|
|
1675
|
+
* @example
|
|
1676
|
+
* // Drop-in default
|
|
1677
|
+
* <ConsentBanner />
|
|
1584
1678
|
*
|
|
1585
|
-
*
|
|
1586
|
-
*
|
|
1679
|
+
* @example
|
|
1680
|
+
* // Customized
|
|
1681
|
+
* <ConsentBanner
|
|
1682
|
+
* message="We use cookies to learn which ads drive bookings."
|
|
1683
|
+
* acceptLabel="Sounds good"
|
|
1684
|
+
* declineLabel="No thanks"
|
|
1685
|
+
* policyHref="/privacy"
|
|
1686
|
+
* policyLabel="Privacy policy"
|
|
1687
|
+
* theme="dark"
|
|
1688
|
+
* onAccept={() => track('consent_accepted')}
|
|
1689
|
+
* onDecline={() => track('consent_declined')}
|
|
1690
|
+
* />
|
|
1587
1691
|
*/
|
|
1588
|
-
|
|
1692
|
+
interface ConsentBannerProps {
|
|
1693
|
+
/** Body text. Defaults to the standard cookies-for-ad-performance message. */
|
|
1694
|
+
message?: ReactNode;
|
|
1695
|
+
/** Optional bold title above the body text. */
|
|
1696
|
+
title?: ReactNode;
|
|
1697
|
+
/** Label for the accept button. Default: `"Accept"`. */
|
|
1698
|
+
acceptLabel?: string;
|
|
1699
|
+
/** Label for the decline button. Default: `"Decline"`. */
|
|
1700
|
+
declineLabel?: string;
|
|
1701
|
+
/** Optional link inline with the message (e.g. to a privacy policy). */
|
|
1702
|
+
policyHref?: string;
|
|
1703
|
+
/** Visible text for {@link policyHref}. Default: `"Learn more"`. */
|
|
1704
|
+
policyLabel?: string;
|
|
1705
|
+
/**
|
|
1706
|
+
* Fires after the consent state is persisted + propagated to gtag. Useful
|
|
1707
|
+
* for emitting your own analytics event on the choice.
|
|
1708
|
+
*/
|
|
1709
|
+
onAccept?: () => void;
|
|
1710
|
+
onDecline?: () => void;
|
|
1711
|
+
/** Where the banner docks. Default: `"bottom"`. */
|
|
1712
|
+
position?: 'top' | 'bottom';
|
|
1713
|
+
/**
|
|
1714
|
+
* Visual theme. `"auto"` follows `prefers-color-scheme`. Default: `"light"`.
|
|
1715
|
+
*/
|
|
1716
|
+
theme?: 'light' | 'dark' | 'auto';
|
|
1717
|
+
/** Class added to the outer wrapper for additional styling hooks. */
|
|
1718
|
+
className?: string;
|
|
1719
|
+
/** Inline style overrides applied to the outer wrapper after the defaults. */
|
|
1720
|
+
style?: CSSProperties;
|
|
1721
|
+
}
|
|
1722
|
+
declare function ConsentBanner({ message, title, acceptLabel, declineLabel, policyHref, policyLabel, onAccept, onDecline, position, theme, className, style, }?: ConsentBannerProps): ReactNode;
|
|
1589
1723
|
|
|
1590
1724
|
/**
|
|
1591
1725
|
* Read the captured Google Ads click id from first-party cookies.
|
|
@@ -1602,8 +1736,46 @@ declare function useTrackingParams(): TrackingParams;
|
|
|
1602
1736
|
/**
|
|
1603
1737
|
* Read the current visitor consent state and update when another tab changes
|
|
1604
1738
|
* the stored value.
|
|
1739
|
+
*
|
|
1740
|
+
* Prefer {@link useConsent} for new code — it returns the same state plus
|
|
1741
|
+
* the `accept` / `decline` / `reset` actions a custom consent UI needs.
|
|
1742
|
+
* `useConsentState` is kept as a convenience for callers that only need to
|
|
1743
|
+
* read.
|
|
1605
1744
|
*/
|
|
1606
1745
|
declare function useConsentState(): ConsentState;
|
|
1746
|
+
/**
|
|
1747
|
+
* The headless consent surface — state + actions in one hook.
|
|
1748
|
+
*
|
|
1749
|
+
* Build a fully-custom banner without losing the gtag-sync, localStorage
|
|
1750
|
+
* persistence, or cross-tab propagation:
|
|
1751
|
+
*
|
|
1752
|
+
* ```tsx
|
|
1753
|
+
* const { state, accept, decline, reset, isPending } = useConsent();
|
|
1754
|
+
*
|
|
1755
|
+
* if (!isPending) {
|
|
1756
|
+
* return <button onClick={reset}>Cookie preferences</button>;
|
|
1757
|
+
* }
|
|
1758
|
+
* return (
|
|
1759
|
+
* <MyBannerStyling>
|
|
1760
|
+
* <button onClick={decline}>No thanks</button>
|
|
1761
|
+
* <button onClick={accept}>Sure</button>
|
|
1762
|
+
* </MyBannerStyling>
|
|
1763
|
+
* );
|
|
1764
|
+
* ```
|
|
1765
|
+
*
|
|
1766
|
+
* The boolean helpers (`isPending` / `isGranted` / `isDenied`) are equivalent
|
|
1767
|
+
* to comparing `state` directly — they're there for readability at call sites.
|
|
1768
|
+
*/
|
|
1769
|
+
interface UseConsentResult {
|
|
1770
|
+
state: ConsentState;
|
|
1771
|
+
isPending: boolean;
|
|
1772
|
+
isGranted: boolean;
|
|
1773
|
+
isDenied: boolean;
|
|
1774
|
+
accept: () => void;
|
|
1775
|
+
decline: () => void;
|
|
1776
|
+
reset: () => void;
|
|
1777
|
+
}
|
|
1778
|
+
declare function useConsent(): UseConsentResult;
|
|
1607
1779
|
|
|
1608
1780
|
/**
|
|
1609
1781
|
* Props for the Next.js Google Ads tracking component.
|
|
@@ -1692,4 +1864,4 @@ interface CreateTrackingResult<TRegistry extends TriggerRegistryConfig> {
|
|
|
1692
1864
|
*/
|
|
1693
1865
|
declare function createTracking<TRegistry extends TriggerRegistryConfig>(options: CreateTrackingOptions<TRegistry>): CreateTrackingResult<TRegistry>;
|
|
1694
1866
|
|
|
1695
|
-
export { AranovaApiError, type AutomaticEventName, ConsentBanner, ConsentState, type CreateTrackingOptions, type CreateTrackingResult, type CtaClickConfig, type CtaClickMetadata, type EventConfig, type EventMetadata, type EventName, type FormStartConfig, type FormStartMetadata, type FormSubmitConfig, type FormSubmitMetadata, GoogleAdsTracking, type GoogleAdsTrackingProps, type JsonValue, type ManualEventName, type MultiPageSessionConfig, type MultiPageSessionMetadata, type PageViewConfig, type PageViewMetadata, type PhoneClickConfig, type PhoneClickMetadata, type PublicServiceItem, type RegisteredAutomaticEvents, type RegisteredManualEvents, type Sale, type SaleCursorPage, type SaleInput, type SaleItem, type SaleItemInput, type SaleListPage, type SaleListQuery, type SaleUpdateInput, type SalesClient, type SalesClientConfig, type SalesTransportConfig, type ScrollDepthConfig, type ScrollDepthMetadata, type SpecificPageName, type SpecificPageVisitConfig, type SpecificPageVisitMetadata, type SupportedCurrency, TRACKING_PARAM_KEYS, type TimeOnSiteConfig, type TimeOnSiteMetadata, type TrackingClient, TrackingClientContext, TrackingEventCreatePayload, TrackingInstallSurface, TrackingParams, type TrackingProviderProps, TrackingSessionUpsertPayload, type TriggerRegistryConfig, type TypedTrackEventOptions, type TypedTrackingClient, captureTrackingParamsFromLocation, createSalesClient, createTracking, createTrackingClientContext, createTrackingEventCreatePayload, createTrackingSessionUpsertPayload, fetchServices, formatMoney, fromMinor, getConsentState, setConsentState, toMinor, useConsentState, useGclid, useTrackingParams };
|
|
1867
|
+
export { AranovaApiError, type AutomaticEventName, ConsentBanner, type ConsentBannerProps, ConsentState, type CreateTrackingOptions, type CreateTrackingResult, type CtaClickConfig, type CtaClickMetadata, type CurrencyRevenue, type EventConfig, type EventMetadata, type EventName, type FormStartConfig, type FormStartMetadata, type FormSubmitConfig, type FormSubmitMetadata, GoogleAdsTracking, type GoogleAdsTrackingProps, type JsonValue, type ManualEventName, type MultiPageSessionConfig, type MultiPageSessionMetadata, type PageViewConfig, type PageViewMetadata, type PhoneClickConfig, type PhoneClickMetadata, type PublicServiceItem, type RegisteredAutomaticEvents, type RegisteredManualEvents, type Sale, type SaleCursorPage, type SaleInput, type SaleItem, type SaleItemInput, type SaleListPage, type SaleListQuery, type SaleSummary, type SaleSummaryQuery, type SaleUpdateInput, type SalesCategoryBreakdown, type SalesClient, type SalesClientConfig, type SalesServiceBreakdown, type SalesTransportConfig, type SalesTrendPoint, type ScrollDepthConfig, type ScrollDepthMetadata, type SpecificPageName, type SpecificPageVisitConfig, type SpecificPageVisitMetadata, type SupportedCurrency, TRACKING_PARAM_KEYS, type TimeOnSiteConfig, type TimeOnSiteMetadata, type TrackingClient, TrackingClientContext, TrackingEventCreatePayload, TrackingInstallSurface, type TrackingOverviewRange, TrackingParams, type TrackingProviderProps, TrackingSessionUpsertPayload, type TriggerRegistryConfig, type TypedTrackEventOptions, type TypedTrackingClient, type UseConsentResult, captureTrackingParamsFromLocation, createSalesClient, createTracking, createTrackingClientContext, createTrackingEventCreatePayload, createTrackingSessionUpsertPayload, fetchServices, formatMoney, fromMinor, getConsentState, resetConsent, setConsentState, toMinor, useConsent, useConsentState, useGclid, useTrackingParams };
|