@rovela-ai/sdk 0.4.3 → 0.5.2
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/admin/components/AdminNav.d.ts.map +1 -1
- package/dist/admin/components/AdminNav.js +10 -1
- package/dist/admin/components/AdminNav.js.map +1 -1
- package/dist/admin/components/ExampleContentBanner.js +2 -2
- package/dist/admin/components/ExampleContentBanner.js.map +1 -1
- package/dist/admin/components/SetupGuide.d.ts.map +1 -1
- package/dist/admin/components/SetupGuide.js +4 -4
- package/dist/admin/components/SetupGuide.js.map +1 -1
- package/dist/admin/components/index.d.ts +0 -1
- package/dist/admin/components/index.d.ts.map +1 -1
- package/dist/admin/components/index.js +0 -1
- package/dist/admin/components/index.js.map +1 -1
- package/dist/admin/hooks/fetchAdminApi.d.ts.map +1 -1
- package/dist/admin/hooks/fetchAdminApi.js +6 -0
- package/dist/admin/hooks/fetchAdminApi.js.map +1 -1
- package/dist/admin/index.d.ts +1 -1
- package/dist/admin/index.d.ts.map +1 -1
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/styles/admin-theme.css +11 -0
- package/dist/analytics/api/dashboard.d.ts +16 -0
- package/dist/analytics/api/dashboard.d.ts.map +1 -0
- package/dist/analytics/api/dashboard.js +37 -0
- package/dist/analytics/api/dashboard.js.map +1 -0
- package/dist/analytics/api/events.d.ts +23 -0
- package/dist/analytics/api/events.d.ts.map +1 -0
- package/dist/analytics/api/events.js +55 -0
- package/dist/analytics/api/events.js.map +1 -0
- package/dist/analytics/api/index.d.ts +15 -0
- package/dist/analytics/api/index.d.ts.map +1 -0
- package/dist/analytics/api/index.js +15 -0
- package/dist/analytics/api/index.js.map +1 -0
- package/dist/analytics/api/track.d.ts +20 -0
- package/dist/analytics/api/track.d.ts.map +1 -0
- package/dist/analytics/api/track.js +233 -0
- package/dist/analytics/api/track.js.map +1 -0
- package/dist/analytics/api/visitors.d.ts +19 -0
- package/dist/analytics/api/visitors.d.ts.map +1 -0
- package/dist/analytics/api/visitors.js +49 -0
- package/dist/analytics/api/visitors.js.map +1 -0
- package/dist/analytics/client/tracker.d.ts +51 -0
- package/dist/analytics/client/tracker.d.ts.map +1 -0
- package/dist/analytics/client/tracker.js +208 -0
- package/dist/analytics/client/tracker.js.map +1 -0
- package/dist/analytics/components/AnalyticsDashboard.d.ts +2 -0
- package/dist/analytics/components/AnalyticsDashboard.d.ts.map +1 -0
- package/dist/analytics/components/AnalyticsDashboard.js +26 -0
- package/dist/analytics/components/AnalyticsDashboard.js.map +1 -0
- package/dist/analytics/components/AnalyticsPeriodContext.d.ts +13 -0
- package/dist/analytics/components/AnalyticsPeriodContext.d.ts.map +1 -0
- package/dist/analytics/components/AnalyticsPeriodContext.js +28 -0
- package/dist/analytics/components/AnalyticsPeriodContext.js.map +1 -0
- package/dist/analytics/components/AnalyticsProvider.d.ts +22 -0
- package/dist/analytics/components/AnalyticsProvider.d.ts.map +1 -0
- package/dist/analytics/components/AnalyticsProvider.js +152 -0
- package/dist/analytics/components/AnalyticsProvider.js.map +1 -0
- package/dist/analytics/components/AnalyticsTabNav.d.ts +14 -0
- package/dist/analytics/components/AnalyticsTabNav.d.ts.map +1 -0
- package/dist/analytics/components/AnalyticsTabNav.js +42 -0
- package/dist/analytics/components/AnalyticsTabNav.js.map +1 -0
- package/dist/analytics/hooks/useAnalytics.d.ts +9 -0
- package/dist/analytics/hooks/useAnalytics.d.ts.map +1 -0
- package/dist/analytics/hooks/useAnalytics.js +8 -0
- package/dist/analytics/hooks/useAnalytics.js.map +1 -0
- package/dist/analytics/hooks/useAnalyticsDashboard.d.ts +9 -0
- package/dist/analytics/hooks/useAnalyticsDashboard.d.ts.map +1 -0
- package/dist/analytics/hooks/useAnalyticsDashboard.js +45 -0
- package/dist/analytics/hooks/useAnalyticsDashboard.js.map +1 -0
- package/dist/analytics/hooks/useEventsLog.d.ts +24 -0
- package/dist/analytics/hooks/useEventsLog.d.ts.map +1 -0
- package/dist/analytics/hooks/useEventsLog.js +85 -0
- package/dist/analytics/hooks/useEventsLog.js.map +1 -0
- package/dist/analytics/hooks/useVisitorsList.d.ts +20 -0
- package/dist/analytics/hooks/useVisitorsList.d.ts.map +1 -0
- package/dist/analytics/hooks/useVisitorsList.js +73 -0
- package/dist/analytics/hooks/useVisitorsList.js.map +1 -0
- package/dist/analytics/index.d.ts +44 -0
- package/dist/analytics/index.d.ts.map +1 -0
- package/dist/analytics/index.js +39 -0
- package/dist/analytics/index.js.map +1 -0
- package/dist/analytics/server/index.d.ts +10 -0
- package/dist/analytics/server/index.d.ts.map +1 -0
- package/dist/analytics/server/index.js +9 -0
- package/dist/analytics/server/index.js.map +1 -0
- package/dist/analytics/server/normalize.d.ts +23 -0
- package/dist/analytics/server/normalize.d.ts.map +1 -0
- package/dist/analytics/server/normalize.js +75 -0
- package/dist/analytics/server/normalize.js.map +1 -0
- package/dist/analytics/server/queries.d.ts +74 -0
- package/dist/analytics/server/queries.d.ts.map +1 -0
- package/dist/analytics/server/queries.js +470 -0
- package/dist/analytics/server/queries.js.map +1 -0
- package/dist/analytics/types.d.ts +186 -0
- package/dist/analytics/types.d.ts.map +1 -0
- package/dist/analytics/types.js +16 -0
- package/dist/analytics/types.js.map +1 -0
- package/dist/analytics/views/DashboardsView.d.ts +6 -0
- package/dist/analytics/views/DashboardsView.d.ts.map +1 -0
- package/dist/analytics/views/DashboardsView.js +93 -0
- package/dist/analytics/views/DashboardsView.js.map +1 -0
- package/dist/analytics/views/EventsView.d.ts +6 -0
- package/dist/analytics/views/EventsView.d.ts.map +1 -0
- package/dist/analytics/views/EventsView.js +85 -0
- package/dist/analytics/views/EventsView.js.map +1 -0
- package/dist/analytics/views/VisitorsView.d.ts +6 -0
- package/dist/analytics/views/VisitorsView.d.ts.map +1 -0
- package/dist/analytics/views/VisitorsView.js +57 -0
- package/dist/analytics/views/VisitorsView.js.map +1 -0
- package/dist/cart/store.d.ts.map +1 -1
- package/dist/cart/store.js +12 -0
- package/dist/cart/store.js.map +1 -1
- package/dist/checkout/components/CheckoutFlow.d.ts.map +1 -1
- package/dist/checkout/components/CheckoutFlow.js +26 -2
- package/dist/checkout/components/CheckoutFlow.js.map +1 -1
- package/dist/checkout/components/ShippingForm.js +10 -5
- package/dist/checkout/components/ShippingForm.js.map +1 -1
- package/dist/checkout/hooks/useCheckout.d.ts.map +1 -1
- package/dist/checkout/hooks/useCheckout.js +12 -1
- package/dist/checkout/hooks/useCheckout.js.map +1 -1
- package/dist/checkout/server/handle-webhook.js +15 -0
- package/dist/checkout/server/handle-webhook.js.map +1 -1
- package/dist/checkout/types.d.ts +13 -0
- package/dist/checkout/types.d.ts.map +1 -1
- package/dist/core/db/client.d.ts +14 -0
- package/dist/core/db/client.d.ts.map +1 -1
- package/dist/core/db/client.js +12 -0
- package/dist/core/db/client.js.map +1 -1
- package/dist/core/db/index.d.ts +2 -1
- package/dist/core/db/index.d.ts.map +1 -1
- package/dist/core/db/index.js +1 -1
- package/dist/core/db/index.js.map +1 -1
- package/dist/core/db/queries.d.ts +8 -7
- package/dist/core/db/queries.d.ts.map +1 -1
- package/dist/core/db/queries.js +80 -0
- package/dist/core/db/queries.js.map +1 -1
- package/dist/core/db/schema.d.ts +340 -4
- package/dist/core/db/schema.d.ts.map +1 -1
- package/dist/core/db/schema.js +55 -1
- package/dist/core/db/schema.js.map +1 -1
- package/dist/core/server/index.d.ts +2 -2
- package/dist/core/server/index.d.ts.map +1 -1
- package/dist/core/server/index.js +2 -0
- package/dist/core/server/index.js.map +1 -1
- package/package.json +25 -1
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* @rovela-ai/sdk/analytics/components/AnalyticsPeriodContext
|
|
5
|
+
*
|
|
6
|
+
* Period state shared across the three Insights tabs. Mounted at the
|
|
7
|
+
* Insights layout level so navigating Dashboards → Events → Visitors
|
|
8
|
+
* preserves the selected window (Next.js App Router preserves layout
|
|
9
|
+
* instances across child route changes — the context lives as long as
|
|
10
|
+
* the user is on /admin/analytics/*).
|
|
11
|
+
*
|
|
12
|
+
* Defaults to '30d' on first mount.
|
|
13
|
+
*/
|
|
14
|
+
import { createContext, useContext, useState } from 'react';
|
|
15
|
+
const AnalyticsPeriodContext = createContext(null);
|
|
16
|
+
export function AnalyticsPeriodProvider({ children, defaultPeriod = '30d', }) {
|
|
17
|
+
const [period, setPeriod] = useState(defaultPeriod);
|
|
18
|
+
return (_jsx(AnalyticsPeriodContext.Provider, { value: { period, setPeriod }, children: children }));
|
|
19
|
+
}
|
|
20
|
+
export function useAnalyticsPeriod() {
|
|
21
|
+
const ctx = useContext(AnalyticsPeriodContext);
|
|
22
|
+
if (!ctx) {
|
|
23
|
+
throw new Error('useAnalyticsPeriod must be used inside <AnalyticsPeriodProvider>. ' +
|
|
24
|
+
'Mount the provider at the /admin/analytics layout level.');
|
|
25
|
+
}
|
|
26
|
+
return ctx;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=AnalyticsPeriodContext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AnalyticsPeriodContext.js","sourceRoot":"","sources":["../../../src/analytics/components/AnalyticsPeriodContext.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAQ3D,MAAM,sBAAsB,GAAG,aAAa,CAC1C,IAAI,CACL,CAAA;AAOD,MAAM,UAAU,uBAAuB,CAAC,EACtC,QAAQ,EACR,aAAa,GAAG,KAAK,GACQ;IAC7B,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAkB,aAAa,CAAC,CAAA;IACpE,OAAO,CACL,KAAC,sBAAsB,CAAC,QAAQ,IAAC,KAAK,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,YAC1D,QAAQ,GACuB,CACnC,CAAA;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,MAAM,GAAG,GAAG,UAAU,CAAC,sBAAsB,CAAC,CAAA;IAC9C,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CACb,oEAAoE;YAClE,0DAA0D,CAC7D,CAAA;IACH,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { AnalyticsPayload } from '../types';
|
|
2
|
+
interface AnalyticsContextValue {
|
|
3
|
+
/** True when events will actually fire (consent granted + not an admin). */
|
|
4
|
+
enabled: boolean;
|
|
5
|
+
/** Fire a single typed event. No-op if disabled. Path / utm / identity are
|
|
6
|
+
* derived automatically by emitEvent. */
|
|
7
|
+
track: (payload: AnalyticsPayload) => void;
|
|
8
|
+
}
|
|
9
|
+
export interface AnalyticsProviderProps {
|
|
10
|
+
children: React.ReactNode;
|
|
11
|
+
/** Override the consent gate (e.g. for testing). Default: respect cookie consent. */
|
|
12
|
+
forceEnabled?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare function AnalyticsProvider({ children, forceEnabled, }: AnalyticsProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
/**
|
|
16
|
+
* Storefront-component hook. Returns a track() that no-ops when consent is
|
|
17
|
+
* denied or an admin is browsing — so call sites can fire unconditionally
|
|
18
|
+
* without manual guards.
|
|
19
|
+
*/
|
|
20
|
+
export declare function useAnalytics(): AnalyticsContextValue;
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=AnalyticsProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AnalyticsProvider.d.ts","sourceRoot":"","sources":["../../../src/analytics/components/AnalyticsProvider.tsx"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAMhD,UAAU,qBAAqB;IAC7B,4EAA4E;IAC5E,OAAO,EAAE,OAAO,CAAA;IAChB;8CAC0C;IAC1C,KAAK,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,IAAI,CAAA;CAC3C;AAWD,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,qFAAqF;IACrF,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB;AAED,wBAAgB,iBAAiB,CAAC,EAChC,QAAQ,EACR,YAAY,GACb,EAAE,sBAAsB,2CAoHxB;AAMD;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,qBAAqB,CAEpD"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* @rovela-ai/sdk/analytics/components/AnalyticsProvider
|
|
5
|
+
*
|
|
6
|
+
* Storefront analytics provider. Mounts ONCE inside the customer branch of
|
|
7
|
+
* LayoutContent.tsx (NEVER inside the admin branch). Responsibilities:
|
|
8
|
+
*
|
|
9
|
+
* 1. Auto-fire `session_start` once per session (per-tab, 30-min idle).
|
|
10
|
+
* 2. Auto-fire `page_view` on every route change.
|
|
11
|
+
* 3. Gate everything on cookie consent (§26 useCookieConsent().analytics).
|
|
12
|
+
* 4. Stay silent when an admin is signed in (no merchant self-bias).
|
|
13
|
+
* 5. Stay silent during SSR (typeof window guard).
|
|
14
|
+
* 6. Provide a useAnalytics() hook so SDK + storefront components can fire
|
|
15
|
+
* manual events (add_to_cart, begin_checkout, etc.).
|
|
16
|
+
*
|
|
17
|
+
* Order of evaluation per render:
|
|
18
|
+
* admin? → skip everything
|
|
19
|
+
* consent denied? → skip everything
|
|
20
|
+
* otherwise → fire (debounced page_view for rapid client-nav)
|
|
21
|
+
*
|
|
22
|
+
* SSR-safe: every effect short-circuits if `pathname` is undefined or window
|
|
23
|
+
* is missing.
|
|
24
|
+
*/
|
|
25
|
+
import { createContext, useContext, useEffect, useRef, useState } from 'react';
|
|
26
|
+
import { usePathname } from 'next/navigation';
|
|
27
|
+
import { useCookieConsent } from '../../core/cookie-consent';
|
|
28
|
+
import { useAdminSession } from '../../admin/hooks/useAdminSession';
|
|
29
|
+
import { emitEvent, getSessionId } from '../client/tracker';
|
|
30
|
+
const AnalyticsContext = createContext({
|
|
31
|
+
enabled: false,
|
|
32
|
+
track: () => undefined,
|
|
33
|
+
});
|
|
34
|
+
export function AnalyticsProvider({ children, forceEnabled, }) {
|
|
35
|
+
const pathname = usePathname();
|
|
36
|
+
const { analytics: analyticsConsent } = useCookieConsent();
|
|
37
|
+
const { data: adminSession } = useAdminSession();
|
|
38
|
+
// Hydrate the gate post-mount so SSR + first paint don't fire (window not
|
|
39
|
+
// yet ready; consent provider value may flip after hydration).
|
|
40
|
+
// Pattern B — post-mount hydration to avoid SSR mismatch.
|
|
41
|
+
const [mounted, setMounted] = useState(false);
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
// eslint-disable-next-line react-hooks/set-state-in-effect
|
|
44
|
+
setMounted(true);
|
|
45
|
+
}, []);
|
|
46
|
+
const isAdmin = Boolean(adminSession?.user?.id);
|
|
47
|
+
const enabled = mounted && !isAdmin && (forceEnabled || analyticsConsent);
|
|
48
|
+
// Auto-fire page_view on route change (debounced for rapid client-nav).
|
|
49
|
+
// sessionStorage check inside getSessionId() handles session_start.
|
|
50
|
+
const lastPathRef = useRef(null);
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
if (!enabled || !pathname)
|
|
53
|
+
return;
|
|
54
|
+
if (lastPathRef.current === pathname)
|
|
55
|
+
return;
|
|
56
|
+
const prev = lastPathRef.current;
|
|
57
|
+
lastPathRef.current = pathname;
|
|
58
|
+
// Tiny debounce — Next.js can rapid-fire usePathname() during transitions.
|
|
59
|
+
const t = setTimeout(() => {
|
|
60
|
+
// session_start fires automatically when the session ID is fresh,
|
|
61
|
+
// BEFORE the first page_view of a new session. This keeps the order
|
|
62
|
+
// session_start → page_view consistent in dashboard reads.
|
|
63
|
+
const { isNew } = getSessionId();
|
|
64
|
+
if (isNew) {
|
|
65
|
+
emitEvent({ event: 'session_start', path: pathname });
|
|
66
|
+
}
|
|
67
|
+
emitEvent({
|
|
68
|
+
event: 'page_view',
|
|
69
|
+
path: pathname,
|
|
70
|
+
referrer: prev ? `${window.location.origin}${prev}` : document.referrer || null,
|
|
71
|
+
});
|
|
72
|
+
}, 50);
|
|
73
|
+
return () => clearTimeout(t);
|
|
74
|
+
}, [enabled, pathname]);
|
|
75
|
+
// Session lifecycle: heartbeat + end. Mounted once at the provider level
|
|
76
|
+
// (NOT per-route) so the cadence is stable across client-nav. Pauses on
|
|
77
|
+
// tab-hidden; resumes on tab-visible. Fires `session_end` on pagehide
|
|
78
|
+
// (more reliable than beforeunload on mobile Safari).
|
|
79
|
+
//
|
|
80
|
+
// 30s cadence — matches what Plausible/Fathom use. Tight enough to give
|
|
81
|
+
// good session-duration resolution (±15s), loose enough that a 10-min
|
|
82
|
+
// session generates only 20 events.
|
|
83
|
+
const HEARTBEAT_MS = 30_000;
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
if (!enabled)
|
|
86
|
+
return;
|
|
87
|
+
if (typeof document === 'undefined')
|
|
88
|
+
return;
|
|
89
|
+
let interval = null;
|
|
90
|
+
const start = () => {
|
|
91
|
+
if (interval !== null)
|
|
92
|
+
return;
|
|
93
|
+
interval = setInterval(() => {
|
|
94
|
+
// Use the live pathname via window — pathname from React closure may
|
|
95
|
+
// be stale if a client-nav happened between heartbeats.
|
|
96
|
+
emitEvent({
|
|
97
|
+
event: 'session_heartbeat',
|
|
98
|
+
path: window.location.pathname,
|
|
99
|
+
});
|
|
100
|
+
}, HEARTBEAT_MS);
|
|
101
|
+
};
|
|
102
|
+
const stop = () => {
|
|
103
|
+
if (interval === null)
|
|
104
|
+
return;
|
|
105
|
+
clearInterval(interval);
|
|
106
|
+
interval = null;
|
|
107
|
+
};
|
|
108
|
+
const onVisibilityChange = () => {
|
|
109
|
+
if (document.visibilityState === 'visible')
|
|
110
|
+
start();
|
|
111
|
+
else
|
|
112
|
+
stop();
|
|
113
|
+
};
|
|
114
|
+
const onPageHide = () => {
|
|
115
|
+
// sendBeacon is the only reliable transport during unload — emitEvent
|
|
116
|
+
// already prefers it. Fire-and-forget; no await.
|
|
117
|
+
emitEvent({
|
|
118
|
+
event: 'session_end',
|
|
119
|
+
path: window.location.pathname,
|
|
120
|
+
});
|
|
121
|
+
stop();
|
|
122
|
+
};
|
|
123
|
+
// Initial state — start immediately if the tab is visible.
|
|
124
|
+
if (document.visibilityState === 'visible')
|
|
125
|
+
start();
|
|
126
|
+
document.addEventListener('visibilitychange', onVisibilityChange);
|
|
127
|
+
window.addEventListener('pagehide', onPageHide);
|
|
128
|
+
return () => {
|
|
129
|
+
document.removeEventListener('visibilitychange', onVisibilityChange);
|
|
130
|
+
window.removeEventListener('pagehide', onPageHide);
|
|
131
|
+
stop();
|
|
132
|
+
};
|
|
133
|
+
}, [enabled]);
|
|
134
|
+
const track = (payload) => {
|
|
135
|
+
if (!enabled)
|
|
136
|
+
return;
|
|
137
|
+
emitEvent(payload);
|
|
138
|
+
};
|
|
139
|
+
return (_jsx(AnalyticsContext.Provider, { value: { enabled, track }, children: children }));
|
|
140
|
+
}
|
|
141
|
+
// =============================================================================
|
|
142
|
+
// Hook
|
|
143
|
+
// =============================================================================
|
|
144
|
+
/**
|
|
145
|
+
* Storefront-component hook. Returns a track() that no-ops when consent is
|
|
146
|
+
* denied or an admin is browsing — so call sites can fire unconditionally
|
|
147
|
+
* without manual guards.
|
|
148
|
+
*/
|
|
149
|
+
export function useAnalytics() {
|
|
150
|
+
return useContext(AnalyticsContext);
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=AnalyticsProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AnalyticsProvider.js","sourceRoot":"","sources":["../../../src/analytics/components/AnalyticsProvider.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface AnalyticsTabNavProps {
|
|
2
|
+
/** Header above the tab strip (default: 'Insights'). */
|
|
3
|
+
title?: string;
|
|
4
|
+
/** Subtitle under the header (optional). */
|
|
5
|
+
subtitle?: string;
|
|
6
|
+
/** Base href for the three tab routes. Defaults to the admin path so the
|
|
7
|
+
* SDK admin pages don't have to pass it explicitly. The platform side
|
|
8
|
+
* passes `/projects/<id>/insights` to reuse the same shell. */
|
|
9
|
+
baseHref?: string;
|
|
10
|
+
/** Optional right-aligned controls (period selector, etc.). */
|
|
11
|
+
trailing?: React.ReactNode;
|
|
12
|
+
}
|
|
13
|
+
export declare function AnalyticsTabNav({ title, subtitle, baseHref, trailing, }: AnalyticsTabNavProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
//# sourceMappingURL=AnalyticsTabNav.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AnalyticsTabNav.d.ts","sourceRoot":"","sources":["../../../src/analytics/components/AnalyticsTabNav.tsx"],"names":[],"mappings":"AAkBA,MAAM,WAAW,oBAAoB;IACnC,wDAAwD;IACxD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;oEAEgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC3B;AAwBD,wBAAgB,eAAe,CAAC,EAC9B,KAAkB,EAClB,QAAQ,EACR,QAA6B,EAC7B,QAAQ,GACT,EAAE,oBAAoB,2CA4CtB"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* @rovela-ai/sdk/analytics/components/AnalyticsTabNav
|
|
5
|
+
*
|
|
6
|
+
* Underline-style tab nav for the Insights surface. Three links — Dashboards
|
|
7
|
+
* / Events / Visitors — wired to route-per-tab URLs. Active tab is derived
|
|
8
|
+
* from pathname (no controlled state needed).
|
|
9
|
+
*
|
|
10
|
+
* Matches the Ploy aesthetic: underline beneath the active tab, muted labels
|
|
11
|
+
* for the inactive ones, no background fills. Also renders the "Default"
|
|
12
|
+
* pill (single dashboard, no creation affordance) when the active tab is
|
|
13
|
+
* Dashboards — reserves the slot for a future multi-dashboard system.
|
|
14
|
+
*/
|
|
15
|
+
import Link from 'next/link';
|
|
16
|
+
import { usePathname } from 'next/navigation';
|
|
17
|
+
const TABS = [
|
|
18
|
+
{ id: 'dashboards', label: 'Dashboards', sub: '' },
|
|
19
|
+
{ id: 'events', label: 'Events', sub: '/events' },
|
|
20
|
+
{ id: 'visitors', label: 'Visitors', sub: '/visitors' },
|
|
21
|
+
];
|
|
22
|
+
function resolveActiveTab(pathname, baseHref) {
|
|
23
|
+
if (!pathname)
|
|
24
|
+
return 'dashboards';
|
|
25
|
+
if (pathname.endsWith('/events') || pathname.includes('/events/'))
|
|
26
|
+
return 'events';
|
|
27
|
+
if (pathname.endsWith('/visitors') || pathname.includes('/visitors/'))
|
|
28
|
+
return 'visitors';
|
|
29
|
+
// Default — the baseHref itself or anything else under it
|
|
30
|
+
return pathname.startsWith(baseHref) ? 'dashboards' : 'dashboards';
|
|
31
|
+
}
|
|
32
|
+
export function AnalyticsTabNav({ title = 'Insights', subtitle, baseHref = '/admin/analytics', trailing, }) {
|
|
33
|
+
const pathname = usePathname();
|
|
34
|
+
const active = resolveActiveTab(pathname, baseHref);
|
|
35
|
+
return (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-2xl font-bold text-foreground sm:text-3xl", children: title }), subtitle && (_jsx("p", { className: "mt-1 text-muted-foreground", children: subtitle }))] }), trailing && _jsx("div", { className: "flex items-center gap-2", children: trailing })] }), _jsx("div", { className: "border-b border-border", children: _jsx("nav", { className: "-mb-px flex gap-6", children: TABS.map((tab) => {
|
|
36
|
+
const isActive = active === tab.id;
|
|
37
|
+
return (_jsx(Link, { href: `${baseHref}${tab.sub}`, "aria-current": isActive ? 'page' : undefined, className: isActive
|
|
38
|
+
? 'border-b-2 border-foreground px-1 pb-3 pt-1 text-sm font-semibold text-foreground'
|
|
39
|
+
: 'border-b-2 border-transparent px-1 pb-3 pt-1 text-sm font-medium text-muted-foreground transition-colors hover:text-foreground', children: tab.label }, tab.id));
|
|
40
|
+
}) }) })] }));
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=AnalyticsTabNav.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AnalyticsTabNav.js","sourceRoot":"","sources":["../../../src/analytics/components/AnalyticsTabNav.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ;;;;;;;;;;;GAWG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAsB7C,MAAM,IAAI,GAAU;IAClB,EAAE,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,EAAE,EAAE;IAClD,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE;IACjD,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,WAAW,EAAE;CACxD,CAAA;AAED,SAAS,gBAAgB,CAAC,QAAuB,EAAE,QAAgB;IACjE,IAAI,CAAC,QAAQ;QAAE,OAAO,YAAY,CAAA;IAClC,IAAI,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC;QAAE,OAAO,QAAQ,CAAA;IAClF,IAAI,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC;QACnE,OAAO,UAAU,CAAA;IACnB,0DAA0D;IAC1D,OAAO,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY,CAAA;AACpE,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,EAC9B,KAAK,GAAG,UAAU,EAClB,QAAQ,EACR,QAAQ,GAAG,kBAAkB,EAC7B,QAAQ,GACa;IACrB,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAA;IAC9B,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;IAEnD,OAAO,CACL,eAAK,SAAS,EAAC,WAAW,aAExB,eAAK,SAAS,EAAC,oEAAoE,aACjF,0BACE,aAAI,SAAS,EAAC,gDAAgD,YAC3D,KAAK,GACH,EACJ,QAAQ,IAAI,CACX,YAAG,SAAS,EAAC,4BAA4B,YAAE,QAAQ,GAAK,CACzD,IACG,EACL,QAAQ,IAAI,cAAK,SAAS,EAAC,yBAAyB,YAAE,QAAQ,GAAO,IAClE,EAGN,cAAK,SAAS,EAAC,wBAAwB,YACrC,cAAK,SAAS,EAAC,mBAAmB,YAC/B,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;wBAChB,MAAM,QAAQ,GAAG,MAAM,KAAK,GAAG,CAAC,EAAE,CAAA;wBAClC,OAAO,CACL,KAAC,IAAI,IAEH,IAAI,EAAE,GAAG,QAAQ,GAAG,GAAG,CAAC,GAAG,EAAE,kBACf,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,EAC3C,SAAS,EACP,QAAQ;gCACN,CAAC,CAAC,mFAAmF;gCACrF,CAAC,CAAC,gIAAgI,YAGrI,GAAG,CAAC,KAAK,IATL,GAAG,CAAC,EAAE,CAUN,CACR,CAAA;oBACH,CAAC,CAAC,GACE,GACF,IAEF,CACP,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @rovela-ai/sdk/analytics/hooks/useAnalytics
|
|
3
|
+
*
|
|
4
|
+
* Re-export of the useAnalytics hook from the provider module. Lives here
|
|
5
|
+
* so the import path matches every other SDK hook (`../hooks/useFoo`).
|
|
6
|
+
*/
|
|
7
|
+
export { useAnalytics, AnalyticsProvider } from '../components/AnalyticsProvider';
|
|
8
|
+
export type { AnalyticsProviderProps } from '../components/AnalyticsProvider';
|
|
9
|
+
//# sourceMappingURL=useAnalytics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAnalytics.d.ts","sourceRoot":"","sources":["../../../src/analytics/hooks/useAnalytics.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA;AACjF,YAAY,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAA"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @rovela-ai/sdk/analytics/hooks/useAnalytics
|
|
3
|
+
*
|
|
4
|
+
* Re-export of the useAnalytics hook from the provider module. Lives here
|
|
5
|
+
* so the import path matches every other SDK hook (`../hooks/useFoo`).
|
|
6
|
+
*/
|
|
7
|
+
export { useAnalytics, AnalyticsProvider } from '../components/AnalyticsProvider';
|
|
8
|
+
//# sourceMappingURL=useAnalytics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAnalytics.js","sourceRoot":"","sources":["../../../src/analytics/hooks/useAnalytics.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { AnalyticsDashboardPayload, AnalyticsPeriod } from '../types';
|
|
2
|
+
export interface UseAnalyticsDashboardReturn {
|
|
3
|
+
data: AnalyticsDashboardPayload | null;
|
|
4
|
+
isLoading: boolean;
|
|
5
|
+
error: string | null;
|
|
6
|
+
refresh: () => Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
export declare function useAnalyticsDashboard(period: AnalyticsPeriod): UseAnalyticsDashboardReturn;
|
|
9
|
+
//# sourceMappingURL=useAnalyticsDashboard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAnalyticsDashboard.d.ts","sourceRoot":"","sources":["../../../src/analytics/hooks/useAnalyticsDashboard.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EACV,yBAAyB,EACzB,eAAe,EAChB,MAAM,UAAU,CAAA;AAEjB,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,yBAAyB,GAAG,IAAI,CAAA;IACtC,SAAS,EAAE,OAAO,CAAA;IAClB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7B;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,eAAe,GACtB,2BAA2B,CAyC7B"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
/**
|
|
3
|
+
* @rovela-ai/sdk/analytics/hooks/useAnalyticsDashboard
|
|
4
|
+
*
|
|
5
|
+
* Admin dashboard hook — fetches /api/admin/analytics scoped to a period.
|
|
6
|
+
* Mirrors the shape of `useAdminStats` so callers get the same {data,
|
|
7
|
+
* isLoading, error, refresh} ergonomics.
|
|
8
|
+
*
|
|
9
|
+
* AbortController-managed: rapid period flips cancel the prior request.
|
|
10
|
+
*/
|
|
11
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
12
|
+
import { fetchAdminApi } from '../../admin/hooks/fetchAdminApi';
|
|
13
|
+
export function useAnalyticsDashboard(period) {
|
|
14
|
+
const [data, setData] = useState(null);
|
|
15
|
+
const [error, setError] = useState(null);
|
|
16
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
17
|
+
const abortRef = useRef(null);
|
|
18
|
+
const fetchDashboard = useCallback(async (p) => {
|
|
19
|
+
abortRef.current?.abort();
|
|
20
|
+
const controller = new AbortController();
|
|
21
|
+
abortRef.current = controller;
|
|
22
|
+
setIsLoading(true);
|
|
23
|
+
const res = await fetchAdminApi(`/api/admin/analytics?period=${p}`, { signal: controller.signal });
|
|
24
|
+
if (controller.signal.aborted)
|
|
25
|
+
return;
|
|
26
|
+
setIsLoading(false);
|
|
27
|
+
if (!res.ok) {
|
|
28
|
+
setError(res.error);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
setError(null);
|
|
32
|
+
setData(res.data);
|
|
33
|
+
}, []);
|
|
34
|
+
// Pattern C — populate state from async-loaded data.
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
// eslint-disable-next-line react-hooks/set-state-in-effect
|
|
37
|
+
fetchDashboard(period);
|
|
38
|
+
return () => {
|
|
39
|
+
abortRef.current?.abort();
|
|
40
|
+
};
|
|
41
|
+
}, [period, fetchDashboard]);
|
|
42
|
+
const refresh = useCallback(() => fetchDashboard(period), [period, fetchDashboard]);
|
|
43
|
+
return { data, isLoading, error, refresh };
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=useAnalyticsDashboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAnalyticsDashboard.js","sourceRoot":"","sources":["../../../src/analytics/hooks/useAnalyticsDashboard.ts"],"names":[],"mappings":"AAAA,YAAY,CAAA;AAEZ;;;;;;;;GAQG;AAEH,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAA;AAa/D,MAAM,UAAU,qBAAqB,CACnC,MAAuB;IAEvB,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAmC,IAAI,CAAC,CAAA;IACxE,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAA;IACvD,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAA;IAChD,MAAM,QAAQ,GAAG,MAAM,CAAyB,IAAI,CAAC,CAAA;IAErD,MAAM,cAAc,GAAG,WAAW,CAChC,KAAK,EAAE,CAAkB,EAAiB,EAAE;QAC1C,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,CAAA;QACzB,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;QACxC,QAAQ,CAAC,OAAO,GAAG,UAAU,CAAA;QAE7B,YAAY,CAAC,IAAI,CAAC,CAAA;QAClB,MAAM,GAAG,GAAG,MAAM,aAAa,CAC7B,+BAA+B,CAAC,EAAE,EAClC,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAC9B,CAAA;QACD,IAAI,UAAU,CAAC,MAAM,CAAC,OAAO;YAAE,OAAM;QACrC,YAAY,CAAC,KAAK,CAAC,CAAA;QACnB,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;YACnB,OAAM;QACR,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC,CAAA;QACd,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IACnB,CAAC,EACD,EAAE,CACH,CAAA;IAED,qDAAqD;IACrD,SAAS,CAAC,GAAG,EAAE;QACb,2DAA2D;QAC3D,cAAc,CAAC,MAAM,CAAC,CAAA;QACtB,OAAO,GAAG,EAAE;YACV,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,CAAA;QAC3B,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAA;IAE5B,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAA;IAEnF,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,CAAA;AAC5C,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { AnalyticsEventsLogPage, AnalyticsPeriod, AnalyticsSortDir } from '../types';
|
|
2
|
+
type SortColumn = 'ts' | 'event' | 'path' | 'referrer' | 'country';
|
|
3
|
+
export interface UseEventsLogOptions {
|
|
4
|
+
period: AnalyticsPeriod;
|
|
5
|
+
sortBy?: SortColumn;
|
|
6
|
+
sortDir?: AnalyticsSortDir;
|
|
7
|
+
hideHeartbeats?: boolean;
|
|
8
|
+
limit?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface UseEventsLogReturn {
|
|
11
|
+
page: AnalyticsEventsLogPage | null;
|
|
12
|
+
isLoading: boolean;
|
|
13
|
+
error: string | null;
|
|
14
|
+
/** Cursor for the page currently displayed. null = first page. */
|
|
15
|
+
cursor: string | null;
|
|
16
|
+
/** Advance to next page (does nothing when nextCursor is null). */
|
|
17
|
+
nextPage: () => void;
|
|
18
|
+
/** Reset to first page. */
|
|
19
|
+
firstPage: () => void;
|
|
20
|
+
refresh: () => Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
export declare function useEventsLog(options: UseEventsLogOptions): UseEventsLogReturn;
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=useEventsLog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useEventsLog.d.ts","sourceRoot":"","sources":["../../../src/analytics/hooks/useEventsLog.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EACV,sBAAsB,EACtB,eAAe,EACf,gBAAgB,EACjB,MAAM,UAAU,CAAA;AAEjB,KAAK,UAAU,GAAG,IAAI,GAAG,OAAO,GAAG,MAAM,GAAG,UAAU,GAAG,SAAS,CAAA;AAElE,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,eAAe,CAAA;IACvB,MAAM,CAAC,EAAE,UAAU,CAAA;IACnB,OAAO,CAAC,EAAE,gBAAgB,CAAA;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,sBAAsB,GAAG,IAAI,CAAA;IACnC,SAAS,EAAE,OAAO,CAAA;IAClB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,kEAAkE;IAClE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,mEAAmE;IACnE,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,2BAA2B;IAC3B,SAAS,EAAE,MAAM,IAAI,CAAA;IACrB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7B;AAED,wBAAgB,YAAY,CAC1B,OAAO,EAAE,mBAAmB,GAC3B,kBAAkB,CAyFpB"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
/**
|
|
3
|
+
* @rovela-ai/sdk/analytics/hooks/useEventsLog
|
|
4
|
+
*
|
|
5
|
+
* Admin Events tab hook — cursor-paginated event log with sort + heartbeat
|
|
6
|
+
* toggle. AbortController-managed: param changes cancel the prior request.
|
|
7
|
+
*
|
|
8
|
+
* Shape mirrors useAnalyticsDashboard for consistency. Returns the page +
|
|
9
|
+
* helpers to advance pagination and replace filters.
|
|
10
|
+
*/
|
|
11
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
12
|
+
import { fetchAdminApi } from '../../admin/hooks/fetchAdminApi';
|
|
13
|
+
export function useEventsLog(options) {
|
|
14
|
+
const [page, setPage] = useState(null);
|
|
15
|
+
const [error, setError] = useState(null);
|
|
16
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
17
|
+
const [cursor, setCursor] = useState(null);
|
|
18
|
+
const abortRef = useRef(null);
|
|
19
|
+
const fetchPage = useCallback(async (opts, c) => {
|
|
20
|
+
abortRef.current?.abort();
|
|
21
|
+
const controller = new AbortController();
|
|
22
|
+
abortRef.current = controller;
|
|
23
|
+
setIsLoading(true);
|
|
24
|
+
const params = new URLSearchParams();
|
|
25
|
+
params.set('period', opts.period);
|
|
26
|
+
if (opts.sortBy)
|
|
27
|
+
params.set('sortBy', opts.sortBy);
|
|
28
|
+
if (opts.sortDir)
|
|
29
|
+
params.set('sortDir', opts.sortDir);
|
|
30
|
+
params.set('hideHeartbeats', opts.hideHeartbeats === false ? 'false' : 'true');
|
|
31
|
+
if (opts.limit)
|
|
32
|
+
params.set('limit', String(opts.limit));
|
|
33
|
+
if (c)
|
|
34
|
+
params.set('cursor', c);
|
|
35
|
+
const res = await fetchAdminApi(`/api/admin/analytics/events?${params.toString()}`, { signal: controller.signal });
|
|
36
|
+
if (controller.signal.aborted)
|
|
37
|
+
return;
|
|
38
|
+
setIsLoading(false);
|
|
39
|
+
if (!res.ok) {
|
|
40
|
+
setError(res.error);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
setError(null);
|
|
44
|
+
setPage(res.data);
|
|
45
|
+
}, []);
|
|
46
|
+
// Reset cursor when filters change (any options change → back to page 1).
|
|
47
|
+
// Pattern C — populate state from async-loaded data.
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
// eslint-disable-next-line react-hooks/set-state-in-effect
|
|
50
|
+
setCursor(null);
|
|
51
|
+
}, [
|
|
52
|
+
options.period,
|
|
53
|
+
options.sortBy,
|
|
54
|
+
options.sortDir,
|
|
55
|
+
options.hideHeartbeats,
|
|
56
|
+
options.limit,
|
|
57
|
+
]);
|
|
58
|
+
// Effect deps intentionally list each scalar prop instead of `options`
|
|
59
|
+
// itself — the parent passes a fresh `options` object reference every
|
|
60
|
+
// render, which would otherwise re-fire this effect on every parent
|
|
61
|
+
// re-render and stack up aborted in-flight requests.
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
// eslint-disable-next-line react-hooks/set-state-in-effect
|
|
64
|
+
fetchPage(options, cursor);
|
|
65
|
+
return () => abortRef.current?.abort();
|
|
66
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
67
|
+
}, [
|
|
68
|
+
options.period,
|
|
69
|
+
options.sortBy,
|
|
70
|
+
options.sortDir,
|
|
71
|
+
options.hideHeartbeats,
|
|
72
|
+
options.limit,
|
|
73
|
+
cursor,
|
|
74
|
+
fetchPage,
|
|
75
|
+
]);
|
|
76
|
+
const nextCursorVal = page?.nextCursor ?? null;
|
|
77
|
+
const nextPage = useCallback(() => {
|
|
78
|
+
if (nextCursorVal)
|
|
79
|
+
setCursor(nextCursorVal);
|
|
80
|
+
}, [nextCursorVal]);
|
|
81
|
+
const firstPage = useCallback(() => setCursor(null), []);
|
|
82
|
+
const refresh = useCallback(() => fetchPage(options, cursor), [options, cursor, fetchPage]);
|
|
83
|
+
return { page, isLoading, error, cursor, nextPage, firstPage, refresh };
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=useEventsLog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useEventsLog.js","sourceRoot":"","sources":["../../../src/analytics/hooks/useEventsLog.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AnalyticsPeriod, AnalyticsSortDir, AnalyticsVisitorsPage } from '../types';
|
|
2
|
+
type SortColumn = 'last_seen' | 'first_seen' | 'sessions' | 'pageviews' | 'country';
|
|
3
|
+
export interface UseVisitorsListOptions {
|
|
4
|
+
period: AnalyticsPeriod;
|
|
5
|
+
sortBy?: SortColumn;
|
|
6
|
+
sortDir?: AnalyticsSortDir;
|
|
7
|
+
limit?: number;
|
|
8
|
+
}
|
|
9
|
+
export interface UseVisitorsListReturn {
|
|
10
|
+
page: AnalyticsVisitorsPage | null;
|
|
11
|
+
isLoading: boolean;
|
|
12
|
+
error: string | null;
|
|
13
|
+
cursor: string | null;
|
|
14
|
+
nextPage: () => void;
|
|
15
|
+
firstPage: () => void;
|
|
16
|
+
refresh: () => Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
export declare function useVisitorsList(options: UseVisitorsListOptions): UseVisitorsListReturn;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=useVisitorsList.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useVisitorsList.d.ts","sourceRoot":"","sources":["../../../src/analytics/hooks/useVisitorsList.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EACV,eAAe,EACf,gBAAgB,EAChB,qBAAqB,EACtB,MAAM,UAAU,CAAA;AAEjB,KAAK,UAAU,GAAG,WAAW,GAAG,YAAY,GAAG,UAAU,GAAG,WAAW,GAAG,SAAS,CAAA;AAEnF,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,eAAe,CAAA;IACvB,MAAM,CAAC,EAAE,UAAU,CAAA;IACnB,OAAO,CAAC,EAAE,gBAAgB,CAAA;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,qBAAqB,GAAG,IAAI,CAAA;IAClC,SAAS,EAAE,OAAO,CAAA;IAClB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,SAAS,EAAE,MAAM,IAAI,CAAA;IACrB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7B;AAED,wBAAgB,eAAe,CAC7B,OAAO,EAAE,sBAAsB,GAC9B,qBAAqB,CA0EvB"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
/**
|
|
3
|
+
* @rovela-ai/sdk/analytics/hooks/useVisitorsList
|
|
4
|
+
*
|
|
5
|
+
* Admin Visitors tab hook — offset-paginated per-visitor aggregate with sort.
|
|
6
|
+
* Mirrors useEventsLog shape.
|
|
7
|
+
*/
|
|
8
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
9
|
+
import { fetchAdminApi } from '../../admin/hooks/fetchAdminApi';
|
|
10
|
+
export function useVisitorsList(options) {
|
|
11
|
+
const [page, setPage] = useState(null);
|
|
12
|
+
const [error, setError] = useState(null);
|
|
13
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
14
|
+
const [cursor, setCursor] = useState(null);
|
|
15
|
+
const abortRef = useRef(null);
|
|
16
|
+
const fetchPage = useCallback(async (opts, c) => {
|
|
17
|
+
abortRef.current?.abort();
|
|
18
|
+
const controller = new AbortController();
|
|
19
|
+
abortRef.current = controller;
|
|
20
|
+
setIsLoading(true);
|
|
21
|
+
const params = new URLSearchParams();
|
|
22
|
+
params.set('period', opts.period);
|
|
23
|
+
if (opts.sortBy)
|
|
24
|
+
params.set('sortBy', opts.sortBy);
|
|
25
|
+
if (opts.sortDir)
|
|
26
|
+
params.set('sortDir', opts.sortDir);
|
|
27
|
+
if (opts.limit)
|
|
28
|
+
params.set('limit', String(opts.limit));
|
|
29
|
+
if (c)
|
|
30
|
+
params.set('cursor', c);
|
|
31
|
+
const res = await fetchAdminApi(`/api/admin/analytics/visitors?${params.toString()}`, { signal: controller.signal });
|
|
32
|
+
if (controller.signal.aborted)
|
|
33
|
+
return;
|
|
34
|
+
setIsLoading(false);
|
|
35
|
+
if (!res.ok) {
|
|
36
|
+
setError(res.error);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
setError(null);
|
|
40
|
+
setPage(res.data);
|
|
41
|
+
}, []);
|
|
42
|
+
// Pattern C — populate state from async-loaded data.
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
// eslint-disable-next-line react-hooks/set-state-in-effect
|
|
45
|
+
setCursor(null);
|
|
46
|
+
}, [options.period, options.sortBy, options.sortDir, options.limit]);
|
|
47
|
+
// Effect deps intentionally list each scalar prop instead of `options`
|
|
48
|
+
// itself — the parent passes a fresh `options` object reference every
|
|
49
|
+
// render, which would otherwise re-fire this effect on every parent
|
|
50
|
+
// re-render and stack up aborted in-flight requests.
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
// eslint-disable-next-line react-hooks/set-state-in-effect
|
|
53
|
+
fetchPage(options, cursor);
|
|
54
|
+
return () => abortRef.current?.abort();
|
|
55
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
56
|
+
}, [
|
|
57
|
+
options.period,
|
|
58
|
+
options.sortBy,
|
|
59
|
+
options.sortDir,
|
|
60
|
+
options.limit,
|
|
61
|
+
cursor,
|
|
62
|
+
fetchPage,
|
|
63
|
+
]);
|
|
64
|
+
const nextCursorVal = page?.nextCursor ?? null;
|
|
65
|
+
const nextPage = useCallback(() => {
|
|
66
|
+
if (nextCursorVal)
|
|
67
|
+
setCursor(nextCursorVal);
|
|
68
|
+
}, [nextCursorVal]);
|
|
69
|
+
const firstPage = useCallback(() => setCursor(null), []);
|
|
70
|
+
const refresh = useCallback(() => fetchPage(options, cursor), [options, cursor, fetchPage]);
|
|
71
|
+
return { page, isLoading, error, cursor, nextPage, firstPage, refresh };
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=useVisitorsList.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useVisitorsList.js","sourceRoot":"","sources":["../../../src/analytics/hooks/useVisitorsList.ts"],"names":[],"mappings":"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"}
|