@carlonicora/nextjs-jsonapi 3.24.2 → 3.25.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.
Files changed (178) hide show
  1. package/dist/{AssistantMessageInterface-1Kbz8RVs.d.ts → AssistantMessageInterface-CubxuBIJ.d.ts} +1 -1
  2. package/dist/{AssistantMessageInterface-CoxJyuFM.d.mts → AssistantMessageInterface-sHjI2zPN.d.mts} +1 -1
  3. package/dist/{BlockNoteEditor-65HR6ULV.mjs → BlockNoteEditor-46O3JC4Z.mjs} +5 -5
  4. package/dist/{BlockNoteEditor-35D4R7HJ.js → BlockNoteEditor-HKS6AXDA.js} +20 -20
  5. package/dist/{BlockNoteEditor-35D4R7HJ.js.map → BlockNoteEditor-HKS6AXDA.js.map} +1 -1
  6. package/dist/{BlockNoteViewer-QDXDVYEM.js → BlockNoteViewer-7BFNTN4E.js} +4 -4
  7. package/dist/{BlockNoteViewer-QDXDVYEM.js.map → BlockNoteViewer-7BFNTN4E.js.map} +1 -1
  8. package/dist/{BlockNoteViewer-KDKGUIG5.mjs → BlockNoteViewer-KRTAFTUX.mjs} +3 -3
  9. package/dist/{HandbookSectionInterface-OePKPbqN.d.ts → HandbookSectionInterface-Ck1wZJ81.d.ts} +1 -1
  10. package/dist/{HandbookSectionInterface-BYsmnPEz.d.mts → HandbookSectionInterface-DgYH--Ik.d.mts} +1 -1
  11. package/dist/JsonApiRequest-TE5WD3WS.js +26 -0
  12. package/dist/{JsonApiRequest-G625QAH5.js.map → JsonApiRequest-TE5WD3WS.js.map} +1 -1
  13. package/dist/{JsonApiRequest-RRMNV7YE.mjs → JsonApiRequest-UHOWNI3O.mjs} +2 -2
  14. package/dist/analytics.modules-CfczU12P.d.ts +25 -0
  15. package/dist/analytics.modules-pzGwMASI.d.mts +25 -0
  16. package/dist/{auth.interface-BC1jp_ni.d.ts → auth.interface-BzI4onI_.d.ts} +1 -1
  17. package/dist/{auth.interface-dR2-6gPM.d.mts → auth.interface-Df4vXbNz.d.mts} +1 -1
  18. package/dist/billing/index.js +402 -402
  19. package/dist/billing/index.mjs +4 -4
  20. package/dist/{chunk-YXRVPEEJ.js → chunk-26MQIJNB.js} +1 -1
  21. package/dist/{chunk-YXRVPEEJ.js.map → chunk-26MQIJNB.js.map} +1 -1
  22. package/dist/{chunk-T76WLDE5.mjs → chunk-37DMFVLN.mjs} +1 -1
  23. package/dist/chunk-4Z2UONN2.mjs +110 -0
  24. package/dist/chunk-4Z2UONN2.mjs.map +1 -0
  25. package/dist/{chunk-3AR4KA5D.js → chunk-4Z45NYPR.js} +13 -13
  26. package/dist/{chunk-3AR4KA5D.js.map → chunk-4Z45NYPR.js.map} +1 -1
  27. package/dist/chunk-7B4E42R5.mjs +280 -0
  28. package/dist/chunk-7B4E42R5.mjs.map +1 -0
  29. package/dist/{chunk-U7QVISQS.js → chunk-CAKOFJZD.js} +450 -40
  30. package/dist/chunk-CAKOFJZD.js.map +1 -0
  31. package/dist/{chunk-IBVKPLHT.mjs → chunk-E3I4MT53.mjs} +422 -12
  32. package/dist/chunk-E3I4MT53.mjs.map +1 -0
  33. package/dist/chunk-GHFMKH3M.js +280 -0
  34. package/dist/chunk-GHFMKH3M.js.map +1 -0
  35. package/dist/chunk-KLV6RLDE.js +110 -0
  36. package/dist/chunk-KLV6RLDE.js.map +1 -0
  37. package/dist/{chunk-ZJI5ZZW5.mjs → chunk-Q6J2ICKO.mjs} +3 -3
  38. package/dist/{chunk-4O7R2Z2O.mjs → chunk-XDYILJ2S.mjs} +1749 -1737
  39. package/dist/{chunk-4O7R2Z2O.mjs.map → chunk-XDYILJ2S.mjs.map} +1 -1
  40. package/dist/{chunk-2XCUAHQT.js → chunk-Y3OKEQGL.js} +1126 -1114
  41. package/dist/chunk-Y3OKEQGL.js.map +1 -0
  42. package/dist/client/index.d.mts +6 -5
  43. package/dist/client/index.d.ts +6 -5
  44. package/dist/client/index.js +5 -5
  45. package/dist/client/index.js.map +1 -1
  46. package/dist/client/index.mjs +4 -4
  47. package/dist/components/index.d.mts +17 -7
  48. package/dist/components/index.d.ts +17 -7
  49. package/dist/components/index.js +5 -5
  50. package/dist/components/index.mjs +4 -4
  51. package/dist/{config-B6UB7j69.d.ts → config-3N1LSrcC.d.ts} +1 -1
  52. package/dist/{config-Cd5xTEfZ.d.ts → config-AVtuvfM1.d.ts} +1 -1
  53. package/dist/{config-n-ZpPmOL.d.mts → config-BSKTYDoh.d.mts} +1 -1
  54. package/dist/{config-YyhFHxkU.d.mts → config-BmufyEj6.d.mts} +1 -1
  55. package/dist/contexts/index.d.mts +5 -4
  56. package/dist/contexts/index.d.ts +5 -4
  57. package/dist/contexts/index.js +5 -5
  58. package/dist/contexts/index.mjs +4 -4
  59. package/dist/core/index.d.mts +31 -14
  60. package/dist/core/index.d.ts +31 -14
  61. package/dist/core/index.js +9 -5
  62. package/dist/core/index.js.map +1 -1
  63. package/dist/core/index.mjs +8 -4
  64. package/dist/features/analytics/index.css +30 -0
  65. package/dist/features/analytics/index.css.map +1 -0
  66. package/dist/features/analytics/index.d.mts +508 -0
  67. package/dist/features/analytics/index.d.ts +508 -0
  68. package/dist/features/analytics/index.js +1166 -0
  69. package/dist/features/analytics/index.js.map +1 -0
  70. package/dist/features/analytics/index.mjs +1166 -0
  71. package/dist/features/analytics/index.mjs.map +1 -0
  72. package/dist/features/analytics/server.d.mts +28 -0
  73. package/dist/features/analytics/server.d.ts +28 -0
  74. package/dist/features/analytics/server.js +41 -0
  75. package/dist/features/analytics/server.js.map +1 -0
  76. package/dist/features/analytics/server.mjs +41 -0
  77. package/dist/features/analytics/server.mjs.map +1 -0
  78. package/dist/features/help/index.d.mts +2 -2
  79. package/dist/features/help/index.d.ts +2 -2
  80. package/dist/features/help/index.js +38 -38
  81. package/dist/features/help/index.mjs +4 -4
  82. package/dist/features/tokenusage/index.d.mts +2 -2
  83. package/dist/features/tokenusage/index.d.ts +2 -2
  84. package/dist/features/tokenusage/index.js +139 -221
  85. package/dist/features/tokenusage/index.js.map +1 -1
  86. package/dist/features/tokenusage/index.mjs +26 -108
  87. package/dist/features/tokenusage/index.mjs.map +1 -1
  88. package/dist/index.d.mts +11 -9
  89. package/dist/index.d.ts +11 -9
  90. package/dist/index.js +10 -6
  91. package/dist/index.js.map +1 -1
  92. package/dist/index.mjs +9 -5
  93. package/dist/notification.interface-BNCvnVCW.d.ts +34 -0
  94. package/dist/notification.interface-P_pNfzZQ.d.mts +34 -0
  95. package/dist/{s3.service-Bqr-fQmi.d.ts → s3.service-CbUa6a-8.d.ts} +3 -2
  96. package/dist/{s3.service-Buiy1ncj.d.mts → s3.service-DAp8FbuG.d.mts} +3 -2
  97. package/dist/server/index.d.mts +5 -4
  98. package/dist/server/index.d.ts +5 -4
  99. package/dist/server/index.js +39 -279
  100. package/dist/server/index.js.map +1 -1
  101. package/dist/server/index.mjs +20 -260
  102. package/dist/server/index.mjs.map +1 -1
  103. package/dist/{types-bsm8Fp55.d.ts → types-Cn153-mH.d.ts} +1 -1
  104. package/dist/{types-Bq_UA8Lg.d.mts → types-D0uLYV2P.d.mts} +1 -1
  105. package/dist/{usePageUrlGenerator-J_ECv-oQ.d.ts → usePageUrlGenerator-B-3FRKBD.d.ts} +1 -1
  106. package/dist/{usePageUrlGenerator-uKBjAKqC.d.mts → usePageUrlGenerator-CCJ_cdQy.d.mts} +1 -1
  107. package/dist/{useSocket-BcH7l7B8.d.mts → useSocket-B9gTbuCj.d.mts} +1 -1
  108. package/dist/{useSocket-DCZd_eJk.d.ts → useSocket-BHVIyigI.d.ts} +1 -1
  109. package/dist/{notification.interface-MnRt1Tjm.d.mts → user.interface-CSaGWFbg.d.mts} +1 -31
  110. package/dist/{notification.interface-CjzV_KII.d.ts → user.interface-CrmwJLYW.d.ts} +1 -31
  111. package/package.json +11 -1
  112. package/src/client/index.ts +2 -0
  113. package/src/core/index.ts +4 -0
  114. package/src/core/registry/ModuleRegistry.ts +7 -0
  115. package/src/features/__tests__/i18n-keys.contract.spec.ts +1 -0
  116. package/src/features/analytics/__tests__/server-entry.spec.tsx +64 -0
  117. package/src/features/analytics/analytics.modules.ts +30 -0
  118. package/src/features/analytics/components/AnalyticsAdminContainer.tsx +97 -0
  119. package/src/features/analytics/components/AnalyticsAdminFilterBar.tsx +117 -0
  120. package/src/features/analytics/components/AnalyticsAdminPageContainer.tsx +25 -0
  121. package/src/features/analytics/components/AnalyticsAdminTiles.tsx +191 -0
  122. package/src/features/analytics/components/AnalyticsBreakdownTable.tsx +104 -0
  123. package/src/features/analytics/components/AnalyticsJourneyContainer.tsx +246 -0
  124. package/src/features/analytics/components/AnalyticsJourneyPageContainer.tsx +14 -0
  125. package/src/features/analytics/components/AnalyticsSessionsTable.tsx +107 -0
  126. package/src/features/analytics/components/AnalyticsTimelineChart.tsx +175 -0
  127. package/src/features/analytics/components/AnalyticsTracker.tsx +112 -0
  128. package/src/features/analytics/components/__tests__/AnalyticsAdminTiles.spec.tsx +39 -0
  129. package/src/features/analytics/components/__tests__/AnalyticsBreakdownTable.spec.tsx +39 -0
  130. package/src/features/analytics/components/__tests__/AnalyticsJourneyContainer.spec.tsx +124 -0
  131. package/src/features/analytics/components/__tests__/AnalyticsPageContainers.spec.tsx +117 -0
  132. package/src/features/analytics/components/__tests__/AnalyticsSessionsTable.spec.tsx +121 -0
  133. package/src/features/analytics/components/__tests__/AnalyticsTimelineChart.spec.tsx +35 -0
  134. package/src/features/analytics/components/__tests__/AnalyticsTracker.spec.tsx +248 -0
  135. package/src/features/analytics/components/server/AnalyticsAdminPage.tsx +28 -0
  136. package/src/features/analytics/components/server/AnalyticsJourneyPage.tsx +25 -0
  137. package/src/features/analytics/contexts/AnalyticsAdminContext.tsx +273 -0
  138. package/src/features/analytics/contexts/__tests__/AnalyticsAdminContext.spec.tsx +140 -0
  139. package/src/features/analytics/data/AnalyticsAdminService.ts +91 -0
  140. package/src/features/analytics/data/AnalyticsService.ts +23 -0
  141. package/src/features/analytics/data/__tests__/AnalyticsAdminService.spec.ts +117 -0
  142. package/src/features/analytics/data/__tests__/AnalyticsService.spec.ts +56 -0
  143. package/src/features/analytics/data/__tests__/models.spec.ts +300 -0
  144. package/src/features/analytics/data/analytics-breakdown.interface.ts +9 -0
  145. package/src/features/analytics/data/analytics-breakdown.ts +65 -0
  146. package/src/features/analytics/data/analytics-event.interface.ts +7 -0
  147. package/src/features/analytics/data/analytics-event.ts +63 -0
  148. package/src/features/analytics/data/analytics-page-view.interface.ts +9 -0
  149. package/src/features/analytics/data/analytics-page-view.ts +57 -0
  150. package/src/features/analytics/data/analytics-session.interface.ts +23 -0
  151. package/src/features/analytics/data/analytics-session.ts +144 -0
  152. package/src/features/analytics/data/analytics-summary.interface.ts +11 -0
  153. package/src/features/analytics/data/analytics-summary.ts +79 -0
  154. package/src/features/analytics/data/analytics-timeline.interface.ts +10 -0
  155. package/src/features/analytics/data/analytics-timeline.ts +67 -0
  156. package/src/features/analytics/data/analytics.types.ts +97 -0
  157. package/src/features/analytics/data/index.ts +15 -0
  158. package/src/features/analytics/i18n-keys.ts +76 -0
  159. package/src/features/analytics/index.ts +31 -0
  160. package/src/features/analytics/lib/__tests__/utm.spec.ts +20 -0
  161. package/src/features/analytics/lib/__tests__/visitorCookie.spec.ts +63 -0
  162. package/src/features/analytics/lib/utm.ts +29 -0
  163. package/src/features/analytics/lib/visitorCookie.ts +32 -0
  164. package/src/features/analytics/server-entry.ts +8 -0
  165. package/src/features/waitlist/components/lists/WaitlistList.tsx +68 -121
  166. package/src/features/waitlist/data/WaitlistService.ts +2 -2
  167. package/src/features/waitlist/data/index.ts +1 -0
  168. package/src/features/waitlist/data/waitlist.fields.ts +8 -0
  169. package/src/features/waitlist/hooks/useWaitlistTableStructure.tsx +69 -30
  170. package/dist/JsonApiRequest-G625QAH5.js +0 -26
  171. package/dist/chunk-2XCUAHQT.js.map +0 -1
  172. package/dist/chunk-IBVKPLHT.mjs.map +0 -1
  173. package/dist/chunk-U7QVISQS.js.map +0 -1
  174. /package/dist/{BlockNoteEditor-65HR6ULV.mjs.map → BlockNoteEditor-46O3JC4Z.mjs.map} +0 -0
  175. /package/dist/{BlockNoteViewer-KDKGUIG5.mjs.map → BlockNoteViewer-KRTAFTUX.mjs.map} +0 -0
  176. /package/dist/{JsonApiRequest-RRMNV7YE.mjs.map → JsonApiRequest-UHOWNI3O.mjs.map} +0 -0
  177. /package/dist/{chunk-T76WLDE5.mjs.map → chunk-37DMFVLN.mjs.map} +0 -0
  178. /package/dist/{chunk-ZJI5ZZW5.mjs.map → chunk-Q6J2ICKO.mjs.map} +0 -0
@@ -0,0 +1,1166 @@
1
+ "use client";
2
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
3
+
4
+
5
+
6
+ var _chunkKLV6RLDEjs = require('../../chunk-KLV6RLDE.js');
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+
22
+
23
+
24
+
25
+
26
+
27
+
28
+
29
+
30
+
31
+
32
+
33
+
34
+
35
+
36
+ var _chunkY3OKEQGLjs = require('../../chunk-Y3OKEQGL.js');
37
+ require('../../chunk-4Z45NYPR.js');
38
+
39
+
40
+
41
+
42
+
43
+
44
+
45
+
46
+
47
+
48
+
49
+
50
+ var _chunkCAKOFJZDjs = require('../../chunk-CAKOFJZD.js');
51
+ require('../../chunk-26MQIJNB.js');
52
+ require('../../chunk-LXKSUWAV.js');
53
+ require('../../chunk-JTPRJNT2.js');
54
+ require('../../chunk-3EPNHTMH.js');
55
+
56
+
57
+ var _chunk7QVYU63Ejs = require('../../chunk-7QVYU63E.js');
58
+
59
+ // src/features/analytics/components/AnalyticsTracker.tsx
60
+ var _navigation = require('next/navigation');
61
+ var _react = require('react');
62
+ var _uuid = require('uuid');
63
+
64
+ // src/features/analytics/data/AnalyticsService.ts
65
+ var AnalyticsService = class extends _chunkCAKOFJZDjs.AbstractService {
66
+ static {
67
+ _chunk7QVYU63Ejs.__name.call(void 0, this, "AnalyticsService");
68
+ }
69
+ /**
70
+ * Posts one page view. Fire-and-forget: a lost page view must never surface
71
+ * an error to the visitor, so the global handler is suppressed and any
72
+ * rejection is logged at debug level and swallowed here.
73
+ */
74
+ static async track(input) {
75
+ try {
76
+ await this.callApi({
77
+ type: _chunkCAKOFJZDjs.Modules.AnalyticsEvent,
78
+ method: "POST" /* POST */,
79
+ endpoint: new (0, _chunkCAKOFJZDjs.EndpointCreator)({ endpoint: _chunkCAKOFJZDjs.Modules.AnalyticsEvent }).generate(),
80
+ input,
81
+ suppressGlobalError: true
82
+ });
83
+ } catch (error) {
84
+ console.debug("Analytics event not sent", error);
85
+ }
86
+ }
87
+ };
88
+
89
+ // src/features/analytics/lib/utm.ts
90
+ var MAX_LENGTH = 255;
91
+ var UTM_PARAMS = [
92
+ ["utm_source", "utmSource"],
93
+ ["utm_medium", "utmMedium"],
94
+ ["utm_campaign", "utmCampaign"],
95
+ ["utm_term", "utmTerm"],
96
+ ["utm_content", "utmContent"]
97
+ ];
98
+ function readUtm(search) {
99
+ const params = new URLSearchParams(search);
100
+ const response = {};
101
+ for (const [param, field] of UTM_PARAMS) {
102
+ const value = params.get(param);
103
+ if (value) response[field] = value.slice(0, MAX_LENGTH);
104
+ }
105
+ return response;
106
+ }
107
+ _chunk7QVYU63Ejs.__name.call(void 0, readUtm, "readUtm");
108
+
109
+ // src/features/analytics/lib/visitorCookie.ts
110
+ var _cookiesnext = require('cookies-next');
111
+
112
+ var ANALYTICS_VISITOR_COOKIE = "analytics_visitor";
113
+ var MAX_AGE_SECONDS = 395 * 24 * 3600;
114
+ function readVisitorCookie() {
115
+ const value = _cookiesnext.getCookie.call(void 0, ANALYTICS_VISITOR_COOKIE);
116
+ return typeof value === "string" && value !== "" ? value : void 0;
117
+ }
118
+ _chunk7QVYU63Ejs.__name.call(void 0, readVisitorCookie, "readVisitorCookie");
119
+ function ensureVisitorCookie() {
120
+ const existing = readVisitorCookie();
121
+ if (existing) return existing;
122
+ const id = _uuid.v4.call(void 0, );
123
+ _cookiesnext.setCookie.call(void 0, ANALYTICS_VISITOR_COOKIE, id, {
124
+ maxAge: MAX_AGE_SECONDS,
125
+ sameSite: "lax",
126
+ path: "/",
127
+ secure: typeof location !== "undefined" && location.protocol === "https:"
128
+ });
129
+ return id;
130
+ }
131
+ _chunk7QVYU63Ejs.__name.call(void 0, ensureVisitorCookie, "ensureVisitorCookie");
132
+ function clearVisitorCookie() {
133
+ _cookiesnext.deleteCookie.call(void 0, ANALYTICS_VISITOR_COOKIE, { path: "/" });
134
+ }
135
+ _chunk7QVYU63Ejs.__name.call(void 0, clearVisitorCookie, "clearVisitorCookie");
136
+
137
+ // src/features/analytics/components/AnalyticsTracker.tsx
138
+ var EXCLUDED_PREFIX = "/administration/analytics";
139
+ var MAX_REFERRER_LENGTH = 2048;
140
+ function readExternalReferrer() {
141
+ if (!document.referrer) return void 0;
142
+ try {
143
+ if (new URL(document.referrer).host === window.location.host) return void 0;
144
+ } catch (e) {
145
+ return void 0;
146
+ }
147
+ return document.referrer.slice(0, MAX_REFERRER_LENGTH);
148
+ }
149
+ _chunk7QVYU63Ejs.__name.call(void 0, readExternalReferrer, "readExternalReferrer");
150
+ function maskSensitivePath(path, sensitivePrefixes) {
151
+ if (!sensitivePrefixes) return path;
152
+ for (const prefix of sensitivePrefixes) {
153
+ if (path === prefix) return path;
154
+ if (path.startsWith(`${prefix}/`)) {
155
+ const segments = path.slice(prefix.length + 1).split("/").filter((segment) => segment.length > 0);
156
+ return [prefix, ...segments.map(() => ":code")].join("/");
157
+ }
158
+ }
159
+ return path;
160
+ }
161
+ _chunk7QVYU63Ejs.__name.call(void 0, maskSensitivePath, "maskSensitivePath");
162
+ function AnalyticsTracker({ hasConsent, resolveSection, sensitivePrefixes }) {
163
+ const pathname = _navigation.usePathname.call(void 0, );
164
+ const lastPath = _react.useRef.call(void 0, null);
165
+ const lastConsent = _react.useRef.call(void 0, false);
166
+ const attribution = _react.useRef.call(void 0, null);
167
+ _react.useEffect.call(void 0, () => {
168
+ if (!hasConsent) clearVisitorCookie();
169
+ if (!pathname) return;
170
+ if (typeof navigator !== "undefined" && navigator.webdriver) return;
171
+ const path = pathname.split(/[?#]/)[0] || "/";
172
+ if (path.startsWith(EXCLUDED_PREFIX)) return;
173
+ const isNewPath = lastPath.current !== path;
174
+ const consentJustGranted = hasConsent && !lastConsent.current;
175
+ lastConsent.current = hasConsent;
176
+ if (!isNewPath && !consentJustGranted) return;
177
+ lastPath.current = path;
178
+ const sentPath = maskSensitivePath(path, sensitivePrefixes);
179
+ const input = {
180
+ id: _uuid.v4.call(void 0, ),
181
+ path: sentPath,
182
+ section: resolveSection(sentPath),
183
+ screenWidth: window.innerWidth
184
+ };
185
+ if (hasConsent) input.visitorId = ensureVisitorCookie();
186
+ const isFirstEvent = attribution.current === null;
187
+ if (isFirstEvent) {
188
+ const referrer = readExternalReferrer();
189
+ attribution.current = { ...referrer ? { referrer } : {}, ...readUtm(window.location.search) };
190
+ }
191
+ if (isFirstEvent || consentJustGranted) Object.assign(input, attribution.current);
192
+ void AnalyticsService.track(input);
193
+ }, [pathname, hasConsent, resolveSection, sensitivePrefixes]);
194
+ return null;
195
+ }
196
+ _chunk7QVYU63Ejs.__name.call(void 0, AnalyticsTracker, "AnalyticsTracker");
197
+
198
+ // src/features/analytics/contexts/AnalyticsAdminContext.tsx
199
+ var _nextintl = require('next-intl');
200
+
201
+
202
+ // src/features/analytics/components/AnalyticsAdminFilterBar.tsx
203
+
204
+
205
+ // src/features/analytics/data/analytics.types.ts
206
+ var ANALYTICS_SECTIONS = ["all", "public", "app"];
207
+ var ANALYTICS_GRANULARITIES = ["day", "week", "month"];
208
+ var ANALYTICS_DIMENSIONS = ["source", "medium", "campaign", "referrer", "route", "landing"];
209
+
210
+ // src/features/analytics/components/AnalyticsAdminFilterBar.tsx
211
+ var _jsxruntime = require('react/jsx-runtime');
212
+ function AnalyticsAdminFilterBar({ section, granularity, onChange }) {
213
+ const t = _nextintl.useTranslations.call(void 0, );
214
+ const sectionLabels = {
215
+ all: t("analytics.admin.filter.section_all"),
216
+ public: t("analytics.admin.filter.section_public"),
217
+ app: t("analytics.admin.filter.section_app")
218
+ };
219
+ const granularityLabels = {
220
+ day: t("analytics.admin.filter.granularity_day"),
221
+ week: t("analytics.admin.filter.granularity_week"),
222
+ month: t("analytics.admin.filter.granularity_month")
223
+ };
224
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-wrap items-center gap-2", children: [
225
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
226
+ _chunkY3OKEQGLjs.DateRangeSelector,
227
+ {
228
+ onDateChange: (range) => {
229
+ if (!_optionalChain([range, 'optionalAccess', _ => _.from]) || !_optionalChain([range, 'optionalAccess', _2 => _2.to])) return;
230
+ onChange({ from: range.from.toISOString(), to: range.to.toISOString() });
231
+ }
232
+ }
233
+ ),
234
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
235
+ Segmented,
236
+ {
237
+ ariaLabel: t("analytics.admin.filter.section"),
238
+ value: section,
239
+ options: ANALYTICS_SECTIONS.map((value) => ({ value, label: sectionLabels[value] })),
240
+ onSelect: (value) => onChange({ section: value })
241
+ }
242
+ ),
243
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
244
+ Segmented,
245
+ {
246
+ ariaLabel: t("analytics.admin.filter.granularity"),
247
+ value: granularity,
248
+ options: ANALYTICS_GRANULARITIES.map((value) => ({ value, label: granularityLabels[value] })),
249
+ onSelect: (value) => onChange({ granularity: value })
250
+ }
251
+ )
252
+ ] });
253
+ }
254
+ _chunk7QVYU63Ejs.__name.call(void 0, AnalyticsAdminFilterBar, "AnalyticsAdminFilterBar");
255
+ function Segmented({
256
+ ariaLabel,
257
+ value,
258
+ options,
259
+ onSelect
260
+ }) {
261
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
262
+ "div",
263
+ {
264
+ role: "group",
265
+ "aria-label": ariaLabel,
266
+ className: "border-border inline-flex items-center gap-0.5 rounded-md border p-0.5",
267
+ children: options.map((option) => {
268
+ const selected = option.value === value;
269
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
270
+ _chunkY3OKEQGLjs.Button,
271
+ {
272
+ type: "button",
273
+ size: "sm",
274
+ variant: selected ? "default" : "ghost",
275
+ "aria-pressed": selected,
276
+ className: _chunkCAKOFJZDjs.cn.call(void 0, !selected && "text-muted-foreground"),
277
+ onClick: () => onSelect(option.value),
278
+ children: option.label
279
+ },
280
+ option.value
281
+ );
282
+ })
283
+ }
284
+ );
285
+ }
286
+ _chunk7QVYU63Ejs.__name.call(void 0, Segmented, "Segmented");
287
+
288
+ // src/features/analytics/data/AnalyticsAdminService.ts
289
+ function withFilters(endpoint, filters) {
290
+ endpoint.addAdditionalParam("from", filters.from);
291
+ endpoint.addAdditionalParam("to", filters.to);
292
+ endpoint.addAdditionalParam("section", filters.section);
293
+ return endpoint;
294
+ }
295
+ _chunk7QVYU63Ejs.__name.call(void 0, withFilters, "withFilters");
296
+ var AnalyticsAdminService = class extends _chunkCAKOFJZDjs.AbstractService {
297
+ static {
298
+ _chunk7QVYU63Ejs.__name.call(void 0, this, "AnalyticsAdminService");
299
+ }
300
+ /** Headline tiles: one row per window (current, previous). */
301
+ static async getSummary(filters) {
302
+ const endpoint = withFilters(new (0, _chunkCAKOFJZDjs.EndpointCreator)({ endpoint: _chunkCAKOFJZDjs.Modules.AnalyticsSummary }), filters);
303
+ return this.callApi({
304
+ type: _chunkCAKOFJZDjs.Modules.AnalyticsSummary,
305
+ method: "GET" /* GET */,
306
+ endpoint: endpoint.generate()
307
+ });
308
+ }
309
+ static async getTimeline(params) {
310
+ const endpoint = withFilters(new (0, _chunkCAKOFJZDjs.EndpointCreator)({ endpoint: _chunkCAKOFJZDjs.Modules.AnalyticsTimeline }), params);
311
+ endpoint.addAdditionalParam("granularity", params.granularity);
312
+ return this.callApi({
313
+ type: _chunkCAKOFJZDjs.Modules.AnalyticsTimeline,
314
+ method: "GET" /* GET */,
315
+ endpoint: endpoint.generate()
316
+ });
317
+ }
318
+ static async getBreakdown(params) {
319
+ const endpoint = withFilters(new (0, _chunkCAKOFJZDjs.EndpointCreator)({ endpoint: _chunkCAKOFJZDjs.Modules.AnalyticsBreakdown }), params);
320
+ endpoint.addAdditionalParam("dimension", params.dimension);
321
+ if (params.limit !== void 0) endpoint.addAdditionalParam("limit", String(params.limit));
322
+ return this.callApi({
323
+ type: _chunkCAKOFJZDjs.Modules.AnalyticsBreakdown,
324
+ method: "GET" /* GET */,
325
+ endpoint: endpoint.generate()
326
+ });
327
+ }
328
+ /** Newest sessions first, cursor-paginated through `next`. */
329
+ static async getSessions(params) {
330
+ const endpoint = withFilters(new (0, _chunkCAKOFJZDjs.EndpointCreator)({ endpoint: _chunkCAKOFJZDjs.Modules.AnalyticsSession }), params);
331
+ if (params.visitorId) endpoint.addAdditionalParam("visitorId", params.visitorId);
332
+ if (params.userId) endpoint.addAdditionalParam("userId", params.userId);
333
+ return this.callApi({
334
+ type: _chunkCAKOFJZDjs.Modules.AnalyticsSession,
335
+ method: "GET" /* GET */,
336
+ endpoint: endpoint.generate(),
337
+ next: params.next
338
+ });
339
+ }
340
+ static async getSession(params) {
341
+ return this.callApi({
342
+ type: _chunkCAKOFJZDjs.Modules.AnalyticsSession,
343
+ method: "GET" /* GET */,
344
+ endpoint: new (0, _chunkCAKOFJZDjs.EndpointCreator)({ endpoint: _chunkCAKOFJZDjs.Modules.AnalyticsSession, id: params.id }).generate()
345
+ });
346
+ }
347
+ /** The journey: every page view of one session, oldest first. */
348
+ static async getSessionPageViews(params) {
349
+ return this.callApi({
350
+ type: _chunkCAKOFJZDjs.Modules.AnalyticsPageView,
351
+ method: "GET" /* GET */,
352
+ endpoint: new (0, _chunkCAKOFJZDjs.EndpointCreator)({
353
+ endpoint: _chunkCAKOFJZDjs.Modules.AnalyticsSession,
354
+ id: params.sessionId,
355
+ childEndpoint: _chunkCAKOFJZDjs.Modules.AnalyticsPageView
356
+ }).generate()
357
+ });
358
+ }
359
+ };
360
+
361
+ // src/features/analytics/contexts/AnalyticsAdminContext.tsx
362
+
363
+ var ANALYTICS_ADMIN_PAGE_URL = "/administration/analytics";
364
+ var ANALYTICS_SESSION_PAGE_URL = "/administration/analytics/sessions";
365
+ var BREAKDOWN_LIMIT = 20;
366
+ var DEFAULT_RANGE_DAYS = 30;
367
+ var EMPTY_BREAKDOWNS = {
368
+ source: [],
369
+ medium: [],
370
+ campaign: [],
371
+ referrer: [],
372
+ route: [],
373
+ landing: []
374
+ };
375
+ var AnalyticsAdminContext = _react.createContext.call(void 0, void 0);
376
+ function defaultRange() {
377
+ const now = /* @__PURE__ */ new Date();
378
+ const start = new Date(now.getTime() - DEFAULT_RANGE_DAYS * 24 * 60 * 60 * 1e3);
379
+ return { from: start.toISOString(), to: now.toISOString() };
380
+ }
381
+ _chunk7QVYU63Ejs.__name.call(void 0, defaultRange, "defaultRange");
382
+ var AnalyticsAdminProvider = /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, ({
383
+ children,
384
+ initialFrom,
385
+ initialTo,
386
+ pageUrl = ANALYTICS_ADMIN_PAGE_URL,
387
+ sessionPageUrl = ANALYTICS_SESSION_PAGE_URL
388
+ }) => {
389
+ const t = _nextintl.useTranslations.call(void 0, );
390
+ const generateUrl = _chunkY3OKEQGLjs.usePageUrlGenerator.call(void 0, );
391
+ const [filters, setFilterState] = _react.useState.call(void 0, () => {
392
+ const range = defaultRange();
393
+ return {
394
+ from: _nullishCoalesce(initialFrom, () => ( range.from)),
395
+ to: _nullishCoalesce(initialTo, () => ( range.to)),
396
+ section: "all",
397
+ granularity: "day"
398
+ };
399
+ });
400
+ const [summary, setSummary] = _react.useState.call(void 0, []);
401
+ const [timeline, setTimeline] = _react.useState.call(void 0, []);
402
+ const [breakdowns, setBreakdowns] = _react.useState.call(void 0, EMPTY_BREAKDOWNS);
403
+ const [sessions, setSessions] = _react.useState.call(void 0, []);
404
+ const [sessionsNextPage, setSessionsNextPage] = _react.useState.call(void 0, void 0);
405
+ const [isLoading, setIsLoading] = _react.useState.call(void 0, true);
406
+ const [error, setError] = _react.useState.call(void 0, null);
407
+ const { from, to, section, granularity } = filters;
408
+ _react.useEffect.call(void 0, () => {
409
+ let cancelled = false;
410
+ setIsLoading(true);
411
+ setError(null);
412
+ const base = { from, to, section };
413
+ const sessionsNext = {};
414
+ Promise.all([
415
+ AnalyticsAdminService.getSummary(base),
416
+ AnalyticsAdminService.getTimeline({ ...base, granularity }),
417
+ Promise.all(
418
+ ANALYTICS_DIMENSIONS.map(
419
+ (dimension) => AnalyticsAdminService.getBreakdown({ ...base, dimension, limit: BREAKDOWN_LIMIT })
420
+ )
421
+ ),
422
+ AnalyticsAdminService.getSessions({ ...base, next: sessionsNext })
423
+ ]).then(([nextSummary, nextTimeline, nextBreakdowns, nextSessions]) => {
424
+ if (cancelled) return;
425
+ setSummary(_nullishCoalesce(nextSummary, () => ( [])));
426
+ setTimeline(_nullishCoalesce(nextTimeline, () => ( [])));
427
+ setBreakdowns(
428
+ Object.fromEntries(
429
+ ANALYTICS_DIMENSIONS.map((dimension, index) => [dimension, _nullishCoalesce(nextBreakdowns[index], () => ( []))])
430
+ )
431
+ );
432
+ setSessions(_nullishCoalesce(nextSessions, () => ( [])));
433
+ setSessionsNextPage(sessionsNext.next);
434
+ }).catch((err) => {
435
+ if (cancelled) return;
436
+ console.error("Failed to load analytics:", err);
437
+ setError(err instanceof Error ? err.message : String(err));
438
+ }).finally(() => {
439
+ if (cancelled) return;
440
+ setIsLoading(false);
441
+ });
442
+ return () => {
443
+ cancelled = true;
444
+ };
445
+ }, [from, to, section, granularity]);
446
+ const setFilters = _react.useCallback.call(void 0, (next) => {
447
+ setFilterState((prev) => ({ ...prev, ...next }));
448
+ }, []);
449
+ const loadMoreSessions = _react.useCallback.call(void 0, async () => {
450
+ if (!sessionsNextPage) return;
451
+ const sessionsNext = {};
452
+ try {
453
+ const nextSessions = await AnalyticsAdminService.next({
454
+ type: _chunkCAKOFJZDjs.Modules.AnalyticsSession,
455
+ endpoint: sessionsNextPage,
456
+ next: sessionsNext
457
+ });
458
+ setSessions((prev) => [...prev, ..._nullishCoalesce(nextSessions, () => ( []))]);
459
+ setSessionsNextPage(sessionsNext.next);
460
+ } catch (err) {
461
+ console.error("Failed to load more analytics sessions:", err);
462
+ setError(err instanceof Error ? err.message : String(err));
463
+ }
464
+ }, [sessionsNextPage]);
465
+ const breadcrumb = /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, () => [
466
+ {
467
+ name: t("analytics.admin.title"),
468
+ href: generateUrl({ page: pageUrl })
469
+ }
470
+ ], "breadcrumb");
471
+ const title = /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, () => ({
472
+ type: t("analytics.admin.title"),
473
+ functions: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
474
+ AnalyticsAdminFilterBar,
475
+ {
476
+ from,
477
+ to,
478
+ section,
479
+ granularity,
480
+ onChange: setFilters
481
+ },
482
+ "analyticsAdminFilterBar"
483
+ )
484
+ }), "title");
485
+ const hasMoreSessions = Boolean(sessionsNextPage);
486
+ const contextValue = _react.useMemo.call(void 0,
487
+ () => ({
488
+ summary,
489
+ timeline,
490
+ breakdowns,
491
+ sessions,
492
+ filters,
493
+ setFilters,
494
+ loadMoreSessions,
495
+ hasMoreSessions,
496
+ sessionPageUrl,
497
+ isLoading,
498
+ error
499
+ }),
500
+ [
501
+ summary,
502
+ timeline,
503
+ breakdowns,
504
+ sessions,
505
+ filters,
506
+ setFilters,
507
+ loadMoreSessions,
508
+ hasMoreSessions,
509
+ sessionPageUrl,
510
+ isLoading,
511
+ error
512
+ ]
513
+ );
514
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.SharedProvider, { value: { breadcrumbs: breadcrumb(), title: title() }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, AnalyticsAdminContext.Provider, { value: contextValue, children }) });
515
+ }, "AnalyticsAdminProvider");
516
+ var useAnalyticsAdmin = /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, () => {
517
+ const ctx = _react.useContext.call(void 0, AnalyticsAdminContext);
518
+ if (!ctx) {
519
+ throw new Error("useAnalyticsAdmin() called outside <AnalyticsAdminProvider>.");
520
+ }
521
+ return ctx;
522
+ }, "useAnalyticsAdmin");
523
+
524
+ // src/features/analytics/components/AnalyticsAdminContainer.tsx
525
+
526
+
527
+ // src/features/analytics/components/AnalyticsAdminTiles.tsx
528
+ var _lucidereact = require('lucide-react');
529
+
530
+
531
+ var ZERO = { visitors: 0, sessions: 0, pageViews: 0, pagesPerSession: 0, consentShare: 0 };
532
+ function AnalyticsAdminTiles({ summary }) {
533
+ const t = _nextintl.useTranslations.call(void 0, );
534
+ const { decimal } = _chunkKLV6RLDEjs.useUsageFormatters.call(void 0, );
535
+ const rowFor = /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, (window2) => _nullishCoalesce(summary.find((r) => r.section === "total" && r.window === window2), () => ( ZERO)), "rowFor");
536
+ const current = rowFor("current");
537
+ const previous = rowFor("previous");
538
+ const previousLabel = t("analytics.admin.tiles.vs_previous");
539
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "grid gap-3", children: [
540
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "grid gap-3 sm:grid-cols-3", children: [
541
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
542
+ LeadTile,
543
+ {
544
+ testId: "analytics-tile-visitors",
545
+ label: t("analytics.admin.tiles.visitors"),
546
+ value: decimal(current.visitors, 0),
547
+ delta: _chunkKLV6RLDEjs.percentageDelta.call(void 0, current.visitors, previous.visitors),
548
+ previousLabel,
549
+ decimal
550
+ }
551
+ ),
552
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
553
+ LeadTile,
554
+ {
555
+ testId: "analytics-tile-sessions",
556
+ label: t("analytics.admin.tiles.sessions"),
557
+ value: decimal(current.sessions, 0),
558
+ delta: _chunkKLV6RLDEjs.percentageDelta.call(void 0, current.sessions, previous.sessions),
559
+ previousLabel,
560
+ decimal
561
+ }
562
+ ),
563
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
564
+ LeadTile,
565
+ {
566
+ testId: "analytics-tile-page-views",
567
+ label: t("analytics.admin.tiles.page_views"),
568
+ value: decimal(current.pageViews, 0),
569
+ delta: _chunkKLV6RLDEjs.percentageDelta.call(void 0, current.pageViews, previous.pageViews),
570
+ previousLabel,
571
+ decimal
572
+ }
573
+ )
574
+ ] }),
575
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "grid gap-3 sm:grid-cols-2", children: [
576
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
577
+ SupportingTile,
578
+ {
579
+ testId: "analytics-tile-pages-per-session",
580
+ label: t("analytics.admin.tiles.pages_per_session"),
581
+ value: decimal(current.pagesPerSession, 1),
582
+ delta: _chunkKLV6RLDEjs.percentageDelta.call(void 0, current.pagesPerSession, previous.pagesPerSession),
583
+ decimal
584
+ }
585
+ ),
586
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
587
+ SupportingTile,
588
+ {
589
+ testId: "analytics-tile-consent-share",
590
+ label: t("analytics.admin.tiles.consent_share"),
591
+ value: `${decimal(current.consentShare * 100, 0)}%`,
592
+ decimal
593
+ }
594
+ )
595
+ ] })
596
+ ] });
597
+ }
598
+ _chunk7QVYU63Ejs.__name.call(void 0, AnalyticsAdminTiles, "AnalyticsAdminTiles");
599
+ function LeadTile({
600
+ testId,
601
+ label,
602
+ value,
603
+ delta,
604
+ previousLabel,
605
+ decimal
606
+ }) {
607
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.Card, { "data-testid": testId, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkY3OKEQGLjs.CardContent, { className: "grid gap-1", children: [
608
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.MicroLabel, { children: label }),
609
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-primary text-xl font-semibold tabular-nums", children: value }),
610
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "flex items-center gap-1", children: [
611
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Delta, { testId: `${testId}-delta`, delta, decimal }),
612
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-muted-foreground text-xs", children: previousLabel })
613
+ ] })
614
+ ] }) });
615
+ }
616
+ _chunk7QVYU63Ejs.__name.call(void 0, LeadTile, "LeadTile");
617
+ function SupportingTile({
618
+ testId,
619
+ label,
620
+ value,
621
+ delta,
622
+ decimal
623
+ }) {
624
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.Card, { "data-testid": testId, size: "sm", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkY3OKEQGLjs.CardContent, { className: "grid gap-1", children: [
625
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.MicroLabel, { children: label }),
626
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "flex items-center gap-2", children: [
627
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-sm font-medium tabular-nums", children: value }),
628
+ delta !== void 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Delta, { testId: `${testId}-delta`, delta, decimal })
629
+ ] })
630
+ ] }) });
631
+ }
632
+ _chunk7QVYU63Ejs.__name.call(void 0, SupportingTile, "SupportingTile");
633
+ function Delta({
634
+ testId,
635
+ delta,
636
+ decimal
637
+ }) {
638
+ if (delta === void 0) {
639
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { "data-testid": testId, className: "text-muted-foreground text-xs", children: "\u2014" });
640
+ }
641
+ const increased = delta >= 0;
642
+ const Icon = increased ? _lucidereact.ArrowUpIcon : _lucidereact.ArrowDownIcon;
643
+ const sign = delta > 0 ? "+" : delta < 0 ? "-" : "";
644
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
645
+ "span",
646
+ {
647
+ "data-testid": testId,
648
+ className: _chunkCAKOFJZDjs.cn.call(void 0,
649
+ "inline-flex items-center gap-0.5 text-xs tabular-nums",
650
+ increased ? "text-success" : "text-destructive"
651
+ ),
652
+ children: [
653
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, Icon, { "aria-hidden": true, className: "size-3" }),
654
+ `${sign}${decimal(Math.abs(delta), 0)}%`
655
+ ]
656
+ }
657
+ );
658
+ }
659
+ _chunk7QVYU63Ejs.__name.call(void 0, Delta, "Delta");
660
+
661
+ // src/features/analytics/components/AnalyticsBreakdownTable.tsx
662
+
663
+
664
+
665
+ var OTHER_KEY = "other";
666
+ function AnalyticsBreakdownTable({ breakdowns }) {
667
+ const t = _nextintl.useTranslations.call(void 0, );
668
+ const labels = {
669
+ source: t("analytics.admin.dimensions.source"),
670
+ medium: t("analytics.admin.dimensions.medium"),
671
+ campaign: t("analytics.admin.dimensions.campaign"),
672
+ referrer: t("analytics.admin.dimensions.referrer"),
673
+ route: t("analytics.admin.dimensions.route"),
674
+ landing: t("analytics.admin.dimensions.landing")
675
+ };
676
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkY3OKEQGLjs.Tabs, { defaultValue: ANALYTICS_DIMENSIONS[0], children: [
677
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TabsList, { children: ANALYTICS_DIMENSIONS.map((dimension) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TabsTrigger, { value: dimension, children: labels[dimension] }, dimension)) }),
678
+ ANALYTICS_DIMENSIONS.map((dimension) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TabsContent, { value: dimension, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, BreakdownRows, { rows: _nullishCoalesce(breakdowns[dimension], () => ( [])) }) }, dimension))
679
+ ] });
680
+ }
681
+ _chunk7QVYU63Ejs.__name.call(void 0, AnalyticsBreakdownTable, "AnalyticsBreakdownTable");
682
+ function BreakdownRows({ rows }) {
683
+ const t = _nextintl.useTranslations.call(void 0, );
684
+ const { decimal } = _chunkKLV6RLDEjs.useUsageFormatters.call(void 0, );
685
+ const sortedRows = _react.useMemo.call(void 0, () => [...rows].sort((a, b) => b.visitors - a.visitors), [rows]);
686
+ if (sortedRows.length === 0) {
687
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-muted-foreground text-sm", children: t("analytics.admin.no_data") });
688
+ }
689
+ return (
690
+ // The package's <Table> wraps itself in an `overflow-x-clip` container, which
691
+ // would swallow the overflow before this scroller ever saw it — hence the
692
+ // child override. Wide tables must scroll, never widen the page.
693
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "overflow-x-auto [&_[data-slot=table-container]]:overflow-x-visible", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkY3OKEQGLjs.Table, { children: [
694
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TableHeader, { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkY3OKEQGLjs.TableRow, { children: [
695
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TableHead, { className: "text-xs font-medium", children: t("analytics.admin.columns.key") }),
696
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TableHead, { className: "text-end text-xs font-medium", children: t("analytics.admin.columns.visitors") }),
697
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TableHead, { className: "text-end text-xs font-medium", children: t("analytics.admin.columns.sessions") }),
698
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TableHead, { className: "text-end text-xs font-medium", children: t("analytics.admin.columns.page_views") })
699
+ ] }) }),
700
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TableBody, { children: sortedRows.map((row) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkY3OKEQGLjs.TableRow, { "data-testid": `analytics-breakdown-row-${row.id}`, children: [
701
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TableCell, { className: "text-xs", children: row.key === OTHER_KEY ? t("analytics.admin.other") : row.key }),
702
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TableCell, { className: "text-end text-xs tabular-nums", children: decimal(row.visitors, 0) }),
703
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TableCell, { className: "text-end text-xs tabular-nums", children: decimal(row.sessions, 0) }),
704
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TableCell, { className: "text-end text-xs tabular-nums", children: decimal(row.pageViews, 0) })
705
+ ] }, row.id)) })
706
+ ] }) })
707
+ );
708
+ }
709
+ _chunk7QVYU63Ejs.__name.call(void 0, BreakdownRows, "BreakdownRows");
710
+
711
+ // src/features/analytics/components/AnalyticsSessionsTable.tsx
712
+
713
+
714
+
715
+ var VISITOR_SUFFIX_LENGTH = 6;
716
+ function AnalyticsSessionsTable({ rows, sessionPageUrl, onLoadMore, hasMore }) {
717
+ const t = _nextintl.useTranslations.call(void 0, );
718
+ const locale = _nextintl.useLocale.call(void 0, );
719
+ const generateUrl = _chunkY3OKEQGLjs.usePageUrlGenerator.call(void 0, );
720
+ const { decimal } = _chunkKLV6RLDEjs.useUsageFormatters.call(void 0, );
721
+ const dateTime = _react.useMemo.call(void 0, () => new Intl.DateTimeFormat(locale, { dateStyle: "short", timeStyle: "short" }), [locale]);
722
+ if (rows.length === 0) {
723
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-muted-foreground text-sm", children: t("analytics.admin.no_data") });
724
+ }
725
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-3", children: [
726
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "overflow-x-auto [&_[data-slot=table-container]]:overflow-x-visible", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkY3OKEQGLjs.Table, { children: [
727
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TableHeader, { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkY3OKEQGLjs.TableRow, { children: [
728
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TableHead, { className: "text-xs font-medium", children: t("analytics.admin.columns.started") }),
729
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TableHead, { className: "text-xs font-medium", children: t("analytics.admin.columns.visitor") }),
730
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TableHead, { className: "text-xs font-medium", children: t("analytics.admin.columns.source") }),
731
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TableHead, { className: "text-xs font-medium", children: t("analytics.admin.columns.landing") }),
732
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TableHead, { className: "text-end text-xs font-medium", children: t("analytics.admin.columns.pages") }),
733
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TableHead, { className: "text-xs font-medium", children: t("analytics.admin.columns.device") })
734
+ ] }) }),
735
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TableBody, { children: rows.map((row) => {
736
+ const source = [_nullishCoalesce(row.utmSource, () => ( row.referrerHost)), row.utmMedium].filter(Boolean).join(" / ");
737
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkY3OKEQGLjs.TableRow, { "data-testid": `analytics-session-row-${row.id}`, children: [
738
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TableCell, { className: "text-xs tabular-nums", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
739
+ _chunkY3OKEQGLjs.Link,
740
+ {
741
+ href: generateUrl({ page: sessionPageUrl, id: row.id }),
742
+ "data-testid": `analytics-session-link-${row.id}`,
743
+ children: dateTime.format(row.startedAt)
744
+ }
745
+ ) }),
746
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TableCell, { className: "text-xs", children: row.user ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "flex flex-col", children: [
747
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: row.user.name }),
748
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-muted-foreground text-xs", children: row.user.email })
749
+ ] }) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "flex items-center gap-2", children: [
750
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.Badge, { variant: "softGray", children: t("analytics.admin.anonymous") }),
751
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-muted-foreground text-xs tabular-nums", children: row.visitorId.slice(-VISITOR_SUFFIX_LENGTH) })
752
+ ] }) }),
753
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TableCell, { className: "text-xs", children: source }),
754
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TableCell, { className: "text-xs", children: row.landingRoute }),
755
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TableCell, { className: "text-end text-xs tabular-nums", children: decimal(row.pageViews, 0) }),
756
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TableCell, { className: "text-muted-foreground text-xs", children: row.deviceType })
757
+ ] }, row.id);
758
+ }) })
759
+ ] }) }),
760
+ hasMore && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex justify-center", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.Button, { type: "button", variant: "outline", size: "sm", onClick: onLoadMore, children: t("analytics.admin.load_more") }) })
761
+ ] });
762
+ }
763
+ _chunk7QVYU63Ejs.__name.call(void 0, AnalyticsSessionsTable, "AnalyticsSessionsTable");
764
+
765
+ // src/features/analytics/components/AnalyticsTimelineChart.tsx
766
+
767
+ var _nextthemes = require('next-themes');
768
+
769
+ var _recharts = require('recharts');
770
+
771
+ var SERIES = ["visitors", "pageViews"];
772
+ var bucketKey = /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, (date) => {
773
+ const y = date.getUTCFullYear();
774
+ const m = `${date.getUTCMonth() + 1}`.padStart(2, "0");
775
+ const d = `${date.getUTCDate()}`.padStart(2, "0");
776
+ return `${y}-${m}-${d}`;
777
+ }, "bucketKey");
778
+ var inferGranularity = /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, (buckets) => {
779
+ if (buckets.length < 2) return "day";
780
+ const dayMs = 24 * 60 * 60 * 1e3;
781
+ let smallestGap = Number.POSITIVE_INFINITY;
782
+ for (let i = 1; i < buckets.length; i += 1) {
783
+ const gap = (Date.parse(buckets[i]) - Date.parse(buckets[i - 1])) / dayMs;
784
+ if (gap > 0 && gap < smallestGap) smallestGap = gap;
785
+ }
786
+ if (smallestGap >= 28) return "month";
787
+ if (smallestGap >= 7) return "week";
788
+ return "day";
789
+ }, "inferGranularity");
790
+ function AnalyticsTimelineChart({ rows, className }) {
791
+ const t = _nextintl.useTranslations.call(void 0, );
792
+ const { compact, bucketDate, decimal } = _chunkKLV6RLDEjs.useUsageFormatters.call(void 0, );
793
+ const { resolvedTheme } = _nextthemes.useTheme.call(void 0, );
794
+ const mode = resolvedTheme === "dark" ? "dark" : "light";
795
+ const chartData = _react.useMemo.call(void 0, () => {
796
+ const byBucket = /* @__PURE__ */ new Map();
797
+ for (const row of rows) {
798
+ const key = bucketKey(row.bucket);
799
+ let entry = byBucket.get(key);
800
+ if (!entry) {
801
+ entry = { bucket: key, visitors: 0, pageViews: 0 };
802
+ byBucket.set(key, entry);
803
+ }
804
+ entry.visitors += row.visitors;
805
+ entry.pageViews += row.pageViews;
806
+ }
807
+ return [...byBucket.values()].sort((a, b) => a.bucket.localeCompare(b.bucket));
808
+ }, [rows]);
809
+ const chartConfig = _react.useMemo.call(void 0,
810
+ () => ({
811
+ visitors: { label: t("analytics.admin.series.visitors") },
812
+ pageViews: { label: t("analytics.admin.series.page_views") }
813
+ }),
814
+ [t]
815
+ );
816
+ if (chartData.length === 0) {
817
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: className ? `text-muted-foreground text-sm ${className}` : "text-muted-foreground text-sm", children: t("analytics.admin.no_data") });
818
+ }
819
+ const granularity = inferGranularity(chartData.map((entry) => entry.bucket));
820
+ return (
821
+ // The chart is a coordinate system, not prose: recharts lays the axes and the
822
+ // bars out left-to-right, so the whole chart stays an LTR island even under
823
+ // dir="rtl". Only the labels inside it are translated.
824
+ // rtl-ok: deliberate LTR island (chart)
825
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className, dir: "ltr", children: [
826
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "sr-only", "data-testid": "analytics-timeline-data", children: JSON.stringify(chartData) }),
827
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.ChartContainer, { config: chartConfig, className: "aspect-auto h-72 w-full", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _recharts.BarChart, { accessibilityLayer: true, data: chartData, margin: { top: 8, right: 8, bottom: 0, left: 0 }, children: [
828
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _recharts.CartesianGrid, { vertical: false }),
829
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
830
+ _recharts.XAxis,
831
+ {
832
+ dataKey: "bucket",
833
+ tickLine: false,
834
+ axisLine: false,
835
+ tickMargin: 8,
836
+ minTickGap: 16,
837
+ tickFormatter: (value) => bucketDate(value, granularity)
838
+ }
839
+ ),
840
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
841
+ _recharts.YAxis,
842
+ {
843
+ tickLine: false,
844
+ axisLine: false,
845
+ tickMargin: 8,
846
+ width: 48,
847
+ tickFormatter: (value) => compact(value)
848
+ }
849
+ ),
850
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
851
+ _chunkY3OKEQGLjs.ChartTooltip,
852
+ {
853
+ content: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
854
+ _chunkY3OKEQGLjs.ChartTooltipContent,
855
+ {
856
+ labelFormatter: (value) => bucketDate(String(value), granularity),
857
+ valueFormatter: (value) => decimal(Number(value), 0)
858
+ }
859
+ )
860
+ }
861
+ ),
862
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.ChartLegend, { content: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.ChartLegendContent, {}) }),
863
+ SERIES.map((series, index) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
864
+ _recharts.Bar,
865
+ {
866
+ dataKey: series,
867
+ maxBarSize: 28,
868
+ fill: _chunkKLV6RLDEjs.seriesColor.call(void 0, index, mode),
869
+ stroke: "var(--background)",
870
+ strokeWidth: 2,
871
+ radius: [4, 4, 0, 0]
872
+ },
873
+ series
874
+ ))
875
+ ] }) })
876
+ ] })
877
+ );
878
+ }
879
+ _chunk7QVYU63Ejs.__name.call(void 0, AnalyticsTimelineChart, "AnalyticsTimelineChart");
880
+
881
+ // src/features/analytics/components/AnalyticsAdminContainer.tsx
882
+
883
+ function AnalyticsAdminContainer() {
884
+ const t = _nextintl.useTranslations.call(void 0, );
885
+ const {
886
+ summary,
887
+ timeline,
888
+ breakdowns,
889
+ sessions,
890
+ loadMoreSessions,
891
+ hasMoreSessions,
892
+ sessionPageUrl,
893
+ isLoading,
894
+ error
895
+ } = useAnalyticsAdmin();
896
+ if (error) {
897
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.RoundPageContainer, { fullWidth: true, forceHeader: true, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "p-4", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.Card, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.CardContent, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-destructive text-xs/relaxed", children: error }) }) }) }) });
898
+ }
899
+ if (isLoading) return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.RoundPageContainer, { fullWidth: true, forceHeader: true });
900
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.RoundPageContainer, { fullWidth: true, forceHeader: true, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex w-full flex-col gap-4 p-4", children: [
901
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col gap-2", children: [
902
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, AnalyticsAdminTiles, { summary }),
903
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-muted-foreground text-xs", children: t("analytics.admin.tiles.summarised_note") })
904
+ ] }),
905
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkY3OKEQGLjs.Card, { children: [
906
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.CardHeader, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.CardTitle, { children: t("analytics.admin.panels.over_time") }) }),
907
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.CardContent, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, AnalyticsTimelineChart, { rows: timeline }) })
908
+ ] }),
909
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkY3OKEQGLjs.Card, { children: [
910
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.CardHeader, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.CardTitle, { children: t("analytics.admin.panels.breakdown") }) }),
911
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.CardContent, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, AnalyticsBreakdownTable, { breakdowns }) })
912
+ ] }),
913
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkY3OKEQGLjs.Card, { children: [
914
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.CardHeader, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.CardTitle, { children: t("analytics.admin.panels.sessions") }) }),
915
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.CardContent, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
916
+ AnalyticsSessionsTable,
917
+ {
918
+ rows: sessions,
919
+ sessionPageUrl,
920
+ onLoadMore: loadMoreSessions,
921
+ hasMore: hasMoreSessions
922
+ }
923
+ ) })
924
+ ] })
925
+ ] }) });
926
+ }
927
+ _chunk7QVYU63Ejs.__name.call(void 0, AnalyticsAdminContainer, "AnalyticsAdminContainer");
928
+
929
+ // src/features/analytics/components/AnalyticsJourneyContainer.tsx
930
+
931
+
932
+
933
+ var ANALYTICS_ADMIN_PAGE_URL2 = "/administration/analytics";
934
+ var OTHER_SESSIONS_WINDOW_DAYS = 395;
935
+ function AnalyticsJourneyContainer({ sessionId, pageUrl = ANALYTICS_ADMIN_PAGE_URL2 }) {
936
+ const t = _nextintl.useTranslations.call(void 0, );
937
+ const locale = _nextintl.useLocale.call(void 0, );
938
+ const generateUrl = _chunkY3OKEQGLjs.usePageUrlGenerator.call(void 0, );
939
+ const [session, setSession] = _react.useState.call(void 0, void 0);
940
+ const [pageViews, setPageViews] = _react.useState.call(void 0, []);
941
+ const [otherSessions, setOtherSessions] = _react.useState.call(void 0, []);
942
+ const [isLoading, setIsLoading] = _react.useState.call(void 0, true);
943
+ const [error, setError] = _react.useState.call(void 0, null);
944
+ _react.useEffect.call(void 0, () => {
945
+ let cancelled = false;
946
+ setIsLoading(true);
947
+ setError(null);
948
+ Promise.all([
949
+ AnalyticsAdminService.getSession({ id: sessionId }),
950
+ AnalyticsAdminService.getSessionPageViews({ sessionId })
951
+ ]).then(async ([nextSession, nextPageViews]) => {
952
+ if (cancelled) return;
953
+ setSession(nextSession);
954
+ setPageViews(_nullishCoalesce(nextPageViews, () => ( [])));
955
+ const to = /* @__PURE__ */ new Date();
956
+ const from = new Date(to.getTime() - OTHER_SESSIONS_WINDOW_DAYS * 24 * 60 * 60 * 1e3);
957
+ const visitorSessions = await AnalyticsAdminService.getSessions({
958
+ from: from.toISOString(),
959
+ to: to.toISOString(),
960
+ section: "all",
961
+ visitorId: nextSession.visitorId
962
+ });
963
+ if (cancelled) return;
964
+ setOtherSessions((_nullishCoalesce(visitorSessions, () => ( []))).filter((other) => other.id !== sessionId));
965
+ }).catch((err) => {
966
+ if (cancelled) return;
967
+ console.error("Failed to load the analytics journey:", err);
968
+ setError(err instanceof Error ? err.message : String(err));
969
+ }).finally(() => {
970
+ if (cancelled) return;
971
+ setIsLoading(false);
972
+ });
973
+ return () => {
974
+ cancelled = true;
975
+ };
976
+ }, [sessionId]);
977
+ const dateTime = _react.useMemo.call(void 0,
978
+ () => new Intl.DateTimeFormat(locale, { dateStyle: "short", timeStyle: "medium" }),
979
+ [locale]
980
+ );
981
+ const formatGap = /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, (milliseconds) => {
982
+ const seconds = Math.max(0, Math.round(milliseconds / 1e3));
983
+ if (seconds < 60) return unit(locale, "second", seconds);
984
+ if (seconds < 3600) return unit(locale, "minute", Math.round(seconds / 60));
985
+ return unit(locale, "hour", Math.round(seconds / 3600));
986
+ }, "formatGap");
987
+ const breadcrumb = [
988
+ { name: t("analytics.admin.title"), href: generateUrl({ page: pageUrl }) },
989
+ { name: t("analytics.admin.panels.journey") }
990
+ ];
991
+ const title = { type: t("analytics.admin.panels.journey") };
992
+ const renderBody = /* @__PURE__ */ _chunk7QVYU63Ejs.__name.call(void 0, () => {
993
+ if (error) {
994
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.RoundPageContainer, { fullWidth: true, forceHeader: true, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "p-4", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.Card, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.CardContent, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-destructive text-xs/relaxed", children: error }) }) }) }) });
995
+ }
996
+ if (isLoading || !session) return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.RoundPageContainer, { fullWidth: true, forceHeader: true });
997
+ const source = [_nullishCoalesce(session.utmSource, () => ( session.referrerHost)), session.utmMedium, session.utmCampaign].filter(Boolean).join(" / ");
998
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.RoundPageContainer, { fullWidth: true, forceHeader: true, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex w-full flex-col gap-4 p-4", children: [
999
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.Card, { "data-testid": "analytics-journey-attribution", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkY3OKEQGLjs.CardContent, { className: "flex flex-col gap-3", children: [
1000
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-wrap items-center gap-2", children: [
1001
+ session.user ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "flex flex-col", children: [
1002
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-sm", children: session.user.name }),
1003
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-muted-foreground text-xs", children: session.user.email })
1004
+ ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.Badge, { variant: "softGray", children: t("analytics.admin.anonymous") }),
1005
+ session.consented ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.Badge, { variant: "softGreen", children: t("analytics.admin.consented") }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.Badge, { variant: "softGray", children: t("analytics.admin.not_consented") })
1006
+ ] }),
1007
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "grid gap-3 sm:grid-cols-3", children: [
1008
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.DetailField, { label: t("analytics.admin.columns.started"), value: dateTime.format(session.startedAt) }),
1009
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.DetailField, { label: t("analytics.admin.columns.source"), value: source }),
1010
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.DetailField, { label: t("analytics.admin.columns.landing"), value: session.landingRoute }),
1011
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.DetailField, { label: t("analytics.admin.columns.device"), value: session.deviceType }),
1012
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1013
+ _chunkY3OKEQGLjs.DetailField,
1014
+ {
1015
+ label: t("analytics.admin.columns.visitor"),
1016
+ value: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "tabular-nums", children: session.visitorId })
1017
+ }
1018
+ )
1019
+ ] })
1020
+ ] }) }),
1021
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkY3OKEQGLjs.Card, { children: [
1022
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.CardHeader, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.CardTitle, { children: t("analytics.admin.columns.pages") }) }),
1023
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.CardContent, { children: pageViews.length === 0 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-muted-foreground text-sm", children: t("analytics.admin.no_data") }) : (
1024
+ // The package's <Table> wraps itself in an `overflow-x-clip`
1025
+ // container — hence the child override, so wide rows scroll.
1026
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "overflow-x-auto [&_[data-slot=table-container]]:overflow-x-visible", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkY3OKEQGLjs.Table, { children: [
1027
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TableHeader, { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkY3OKEQGLjs.TableRow, { children: [
1028
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TableHead, { className: "text-xs font-medium", children: t("analytics.admin.columns.time") }),
1029
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TableHead, { className: "text-end text-xs font-medium", children: t("analytics.admin.columns.gap") }),
1030
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TableHead, { className: "text-xs font-medium", children: t("analytics.admin.columns.path") })
1031
+ ] }) }),
1032
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TableBody, { children: pageViews.map((pageView, index) => {
1033
+ const previous = index > 0 ? pageViews[index - 1] : void 0;
1034
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkY3OKEQGLjs.TableRow, { "data-testid": `analytics-pageview-row-${pageView.id}`, children: [
1035
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TableCell, { className: "text-xs tabular-nums", children: dateTime.format(pageView.createdAt) }),
1036
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TableCell, { className: "text-end text-xs tabular-nums", children: previous ? formatGap(pageView.createdAt.getTime() - previous.createdAt.getTime()) : "\u2014" }),
1037
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.TableCell, { className: "text-xs", children: pageView.path })
1038
+ ] }, pageView.id);
1039
+ }) })
1040
+ ] }) })
1041
+ ) })
1042
+ ] }),
1043
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkY3OKEQGLjs.Card, { children: [
1044
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.CardHeader, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.CardTitle, { children: t("analytics.admin.panels.other_sessions") }) }),
1045
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.CardContent, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1046
+ AnalyticsSessionsTable,
1047
+ {
1048
+ rows: otherSessions,
1049
+ sessionPageUrl: `${pageUrl}/sessions`,
1050
+ onLoadMore: () => void 0,
1051
+ hasMore: false
1052
+ }
1053
+ ) })
1054
+ ] })
1055
+ ] }) });
1056
+ }, "renderBody");
1057
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkY3OKEQGLjs.SharedProvider, { value: { breadcrumbs: breadcrumb, title }, children: renderBody() });
1058
+ }
1059
+ _chunk7QVYU63Ejs.__name.call(void 0, AnalyticsJourneyContainer, "AnalyticsJourneyContainer");
1060
+ function unit(locale, name, value) {
1061
+ return new Intl.NumberFormat(locale, { style: "unit", unit: name, unitDisplay: "short" }).format(value);
1062
+ }
1063
+ _chunk7QVYU63Ejs.__name.call(void 0, unit, "unit");
1064
+
1065
+ // src/features/analytics/components/AnalyticsAdminPageContainer.tsx
1066
+
1067
+ function AnalyticsAdminPageContainer({ pageUrl, sessionPageUrl }) {
1068
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, AnalyticsAdminProvider, { pageUrl, sessionPageUrl, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, AnalyticsAdminContainer, {}) });
1069
+ }
1070
+ _chunk7QVYU63Ejs.__name.call(void 0, AnalyticsAdminPageContainer, "AnalyticsAdminPageContainer");
1071
+
1072
+ // src/features/analytics/components/AnalyticsJourneyPageContainer.tsx
1073
+
1074
+ function AnalyticsJourneyPageContainer({ sessionId, pageUrl }) {
1075
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, AnalyticsJourneyContainer, { sessionId, pageUrl });
1076
+ }
1077
+ _chunk7QVYU63Ejs.__name.call(void 0, AnalyticsJourneyPageContainer, "AnalyticsJourneyPageContainer");
1078
+
1079
+ // src/features/analytics/i18n-keys.ts
1080
+ var ANALYTICS_ADMIN_I18N_KEYS = [
1081
+ // Page
1082
+ "analytics.admin.title",
1083
+ "analytics.admin.description",
1084
+ // KPI tiles
1085
+ "analytics.admin.tiles.visitors",
1086
+ "analytics.admin.tiles.sessions",
1087
+ "analytics.admin.tiles.page_views",
1088
+ "analytics.admin.tiles.pages_per_session",
1089
+ "analytics.admin.tiles.consent_share",
1090
+ "analytics.admin.tiles.vs_previous",
1091
+ "analytics.admin.tiles.summarised_note",
1092
+ // Filter bar
1093
+ "analytics.admin.filter.section",
1094
+ "analytics.admin.filter.section_all",
1095
+ "analytics.admin.filter.section_public",
1096
+ "analytics.admin.filter.section_app",
1097
+ "analytics.admin.filter.granularity",
1098
+ "analytics.admin.filter.granularity_day",
1099
+ "analytics.admin.filter.granularity_week",
1100
+ "analytics.admin.filter.granularity_month",
1101
+ // Panel titles
1102
+ "analytics.admin.panels.over_time",
1103
+ "analytics.admin.panels.breakdown",
1104
+ "analytics.admin.panels.sessions",
1105
+ "analytics.admin.panels.journey",
1106
+ "analytics.admin.panels.other_sessions",
1107
+ // Breakdown tabs
1108
+ "analytics.admin.dimensions.source",
1109
+ "analytics.admin.dimensions.medium",
1110
+ "analytics.admin.dimensions.campaign",
1111
+ "analytics.admin.dimensions.referrer",
1112
+ "analytics.admin.dimensions.route",
1113
+ "analytics.admin.dimensions.landing",
1114
+ // Table columns
1115
+ "analytics.admin.columns.key",
1116
+ "analytics.admin.columns.visitors",
1117
+ "analytics.admin.columns.sessions",
1118
+ "analytics.admin.columns.page_views",
1119
+ "analytics.admin.columns.started",
1120
+ "analytics.admin.columns.visitor",
1121
+ "analytics.admin.columns.source",
1122
+ "analytics.admin.columns.landing",
1123
+ "analytics.admin.columns.pages",
1124
+ "analytics.admin.columns.device",
1125
+ "analytics.admin.columns.time",
1126
+ "analytics.admin.columns.gap",
1127
+ "analytics.admin.columns.path",
1128
+ // Shared states and markers
1129
+ "analytics.admin.anonymous",
1130
+ "analytics.admin.consented",
1131
+ "analytics.admin.not_consented",
1132
+ "analytics.admin.load_more",
1133
+ "analytics.admin.no_data",
1134
+ "analytics.admin.other",
1135
+ // Timeline chart series
1136
+ "analytics.admin.series.visitors",
1137
+ "analytics.admin.series.page_views"
1138
+ ];
1139
+
1140
+
1141
+
1142
+
1143
+
1144
+
1145
+
1146
+
1147
+
1148
+
1149
+
1150
+
1151
+
1152
+
1153
+
1154
+
1155
+
1156
+
1157
+
1158
+
1159
+
1160
+
1161
+
1162
+
1163
+
1164
+
1165
+ exports.ANALYTICS_ADMIN_I18N_KEYS = ANALYTICS_ADMIN_I18N_KEYS; exports.ANALYTICS_DIMENSIONS = ANALYTICS_DIMENSIONS; exports.ANALYTICS_GRANULARITIES = ANALYTICS_GRANULARITIES; exports.ANALYTICS_SECTIONS = ANALYTICS_SECTIONS; exports.AnalyticsAdminContainer = AnalyticsAdminContainer; exports.AnalyticsAdminFilterBar = AnalyticsAdminFilterBar; exports.AnalyticsAdminPageContainer = AnalyticsAdminPageContainer; exports.AnalyticsAdminProvider = AnalyticsAdminProvider; exports.AnalyticsAdminService = AnalyticsAdminService; exports.AnalyticsAdminTiles = AnalyticsAdminTiles; exports.AnalyticsBreakdown = _chunkCAKOFJZDjs.AnalyticsBreakdown; exports.AnalyticsBreakdownTable = AnalyticsBreakdownTable; exports.AnalyticsEvent = _chunkCAKOFJZDjs.AnalyticsEvent; exports.AnalyticsJourneyContainer = AnalyticsJourneyContainer; exports.AnalyticsJourneyPageContainer = AnalyticsJourneyPageContainer; exports.AnalyticsPageView = _chunkCAKOFJZDjs.AnalyticsPageView; exports.AnalyticsService = AnalyticsService; exports.AnalyticsSession = _chunkCAKOFJZDjs.AnalyticsSession; exports.AnalyticsSessionsTable = AnalyticsSessionsTable; exports.AnalyticsSummary = _chunkCAKOFJZDjs.AnalyticsSummary; exports.AnalyticsTimeline = _chunkCAKOFJZDjs.AnalyticsTimeline; exports.AnalyticsTimelineChart = AnalyticsTimelineChart; exports.AnalyticsTracker = AnalyticsTracker; exports.analyticsModules = _chunkCAKOFJZDjs.analyticsModules; exports.useAnalyticsAdmin = useAnalyticsAdmin;
1166
+ //# sourceMappingURL=index.js.map