@carlonicora/nextjs-jsonapi 3.24.2 → 3.26.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 (220) 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-35D4R7HJ.js → BlockNoteEditor-4EIKMNY3.js} +31 -21
  4. package/dist/BlockNoteEditor-4EIKMNY3.js.map +1 -0
  5. package/dist/{BlockNoteEditor-65HR6ULV.mjs → BlockNoteEditor-AXYVDDXM.mjs} +16 -6
  6. package/dist/{BlockNoteEditor-65HR6ULV.mjs.map → BlockNoteEditor-AXYVDDXM.mjs.map} +1 -1
  7. package/dist/{BlockNoteViewer-QDXDVYEM.js → BlockNoteViewer-7BFNTN4E.js} +4 -4
  8. package/dist/{BlockNoteViewer-QDXDVYEM.js.map → BlockNoteViewer-7BFNTN4E.js.map} +1 -1
  9. package/dist/{BlockNoteViewer-KDKGUIG5.mjs → BlockNoteViewer-KRTAFTUX.mjs} +3 -3
  10. package/dist/{HandbookSectionInterface-OePKPbqN.d.ts → HandbookSectionInterface-Ck1wZJ81.d.ts} +1 -1
  11. package/dist/{HandbookSectionInterface-BYsmnPEz.d.mts → HandbookSectionInterface-DgYH--Ik.d.mts} +1 -1
  12. package/dist/JsonApiRequest-TE5WD3WS.js +26 -0
  13. package/dist/{JsonApiRequest-G625QAH5.js.map → JsonApiRequest-TE5WD3WS.js.map} +1 -1
  14. package/dist/{JsonApiRequest-RRMNV7YE.mjs → JsonApiRequest-UHOWNI3O.mjs} +2 -2
  15. package/dist/analytics.modules-CfczU12P.d.ts +25 -0
  16. package/dist/analytics.modules-pzGwMASI.d.mts +25 -0
  17. package/dist/{auth.interface-BC1jp_ni.d.ts → auth.interface-BzI4onI_.d.ts} +1 -1
  18. package/dist/{auth.interface-dR2-6gPM.d.mts → auth.interface-Df4vXbNz.d.mts} +1 -1
  19. package/dist/billing/index.js +402 -402
  20. package/dist/billing/index.mjs +4 -4
  21. package/dist/{chunk-YXRVPEEJ.js → chunk-26MQIJNB.js} +1 -1
  22. package/dist/{chunk-YXRVPEEJ.js.map → chunk-26MQIJNB.js.map} +1 -1
  23. package/dist/{chunk-T76WLDE5.mjs → chunk-37DMFVLN.mjs} +1 -1
  24. package/dist/{chunk-3AR4KA5D.js → chunk-4Z45NYPR.js} +13 -13
  25. package/dist/{chunk-3AR4KA5D.js.map → chunk-4Z45NYPR.js.map} +1 -1
  26. package/dist/chunk-7B4E42R5.mjs +280 -0
  27. package/dist/chunk-7B4E42R5.mjs.map +1 -0
  28. package/dist/{chunk-2XCUAHQT.js → chunk-ABVTYQIJ.js} +1563 -1336
  29. package/dist/chunk-ABVTYQIJ.js.map +1 -0
  30. package/dist/{chunk-U7QVISQS.js → chunk-CAKOFJZD.js} +450 -40
  31. package/dist/chunk-CAKOFJZD.js.map +1 -0
  32. package/dist/{chunk-IBVKPLHT.mjs → chunk-E3I4MT53.mjs} +422 -12
  33. package/dist/chunk-E3I4MT53.mjs.map +1 -0
  34. package/dist/chunk-GHFMKH3M.js +280 -0
  35. package/dist/chunk-GHFMKH3M.js.map +1 -0
  36. package/dist/chunk-GKDHYB2R.js +110 -0
  37. package/dist/chunk-GKDHYB2R.js.map +1 -0
  38. package/dist/{chunk-ZJI5ZZW5.mjs → chunk-Q6J2ICKO.mjs} +3 -3
  39. package/dist/{chunk-4O7R2Z2O.mjs → chunk-QWZAGQWJ.mjs} +2175 -1948
  40. package/dist/chunk-QWZAGQWJ.mjs.map +1 -0
  41. package/dist/chunk-U65JPKO3.mjs +110 -0
  42. package/dist/chunk-U65JPKO3.mjs.map +1 -0
  43. package/dist/client/index.d.mts +6 -5
  44. package/dist/client/index.d.ts +6 -5
  45. package/dist/client/index.js +5 -5
  46. package/dist/client/index.js.map +1 -1
  47. package/dist/client/index.mjs +4 -4
  48. package/dist/components/index.d.mts +33 -10
  49. package/dist/components/index.d.ts +33 -10
  50. package/dist/components/index.js +7 -5
  51. package/dist/components/index.js.map +1 -1
  52. package/dist/components/index.mjs +6 -4
  53. package/dist/{config-B6UB7j69.d.ts → config-3N1LSrcC.d.ts} +1 -1
  54. package/dist/{config-Cd5xTEfZ.d.ts → config-AVtuvfM1.d.ts} +1 -1
  55. package/dist/{config-n-ZpPmOL.d.mts → config-BSKTYDoh.d.mts} +1 -1
  56. package/dist/{config-YyhFHxkU.d.mts → config-BmufyEj6.d.mts} +1 -1
  57. package/dist/contexts/index.d.mts +5 -4
  58. package/dist/contexts/index.d.ts +5 -4
  59. package/dist/contexts/index.js +5 -5
  60. package/dist/contexts/index.mjs +4 -4
  61. package/dist/core/index.d.mts +31 -14
  62. package/dist/core/index.d.ts +31 -14
  63. package/dist/core/index.js +9 -5
  64. package/dist/core/index.js.map +1 -1
  65. package/dist/core/index.mjs +8 -4
  66. package/dist/features/analytics/index.css +30 -0
  67. package/dist/features/analytics/index.css.map +1 -0
  68. package/dist/features/analytics/index.d.mts +508 -0
  69. package/dist/features/analytics/index.d.ts +508 -0
  70. package/dist/features/analytics/index.js +1166 -0
  71. package/dist/features/analytics/index.js.map +1 -0
  72. package/dist/features/analytics/index.mjs +1166 -0
  73. package/dist/features/analytics/index.mjs.map +1 -0
  74. package/dist/features/analytics/server.d.mts +28 -0
  75. package/dist/features/analytics/server.d.ts +28 -0
  76. package/dist/features/analytics/server.js +41 -0
  77. package/dist/features/analytics/server.js.map +1 -0
  78. package/dist/features/analytics/server.mjs +41 -0
  79. package/dist/features/analytics/server.mjs.map +1 -0
  80. package/dist/features/help/index.d.mts +2 -2
  81. package/dist/features/help/index.d.ts +2 -2
  82. package/dist/features/help/index.js +43 -43
  83. package/dist/features/help/index.js.map +1 -1
  84. package/dist/features/help/index.mjs +9 -9
  85. package/dist/features/help/index.mjs.map +1 -1
  86. package/dist/features/tokenusage/index.d.mts +2 -2
  87. package/dist/features/tokenusage/index.d.ts +2 -2
  88. package/dist/features/tokenusage/index.js +141 -223
  89. package/dist/features/tokenusage/index.js.map +1 -1
  90. package/dist/features/tokenusage/index.mjs +28 -110
  91. package/dist/features/tokenusage/index.mjs.map +1 -1
  92. package/dist/index.d.mts +11 -9
  93. package/dist/index.d.ts +11 -9
  94. package/dist/index.js +10 -6
  95. package/dist/index.js.map +1 -1
  96. package/dist/index.mjs +9 -5
  97. package/dist/notification.interface-BNCvnVCW.d.ts +34 -0
  98. package/dist/notification.interface-P_pNfzZQ.d.mts +34 -0
  99. package/dist/{s3.service-Bqr-fQmi.d.ts → s3.service-CbUa6a-8.d.ts} +3 -2
  100. package/dist/{s3.service-Buiy1ncj.d.mts → s3.service-DAp8FbuG.d.mts} +3 -2
  101. package/dist/server/index.d.mts +5 -4
  102. package/dist/server/index.d.ts +5 -4
  103. package/dist/server/index.js +39 -279
  104. package/dist/server/index.js.map +1 -1
  105. package/dist/server/index.mjs +20 -260
  106. package/dist/server/index.mjs.map +1 -1
  107. package/dist/{types-bsm8Fp55.d.ts → types-Cn153-mH.d.ts} +1 -1
  108. package/dist/{types-Bq_UA8Lg.d.mts → types-D0uLYV2P.d.mts} +1 -1
  109. package/dist/{usePageUrlGenerator-J_ECv-oQ.d.ts → usePageUrlGenerator-B-3FRKBD.d.ts} +1 -1
  110. package/dist/{usePageUrlGenerator-uKBjAKqC.d.mts → usePageUrlGenerator-CCJ_cdQy.d.mts} +1 -1
  111. package/dist/{useSocket-BcH7l7B8.d.mts → useSocket-B9gTbuCj.d.mts} +1 -1
  112. package/dist/{useSocket-DCZd_eJk.d.ts → useSocket-BHVIyigI.d.ts} +1 -1
  113. package/dist/{notification.interface-MnRt1Tjm.d.mts → user.interface-CSaGWFbg.d.mts} +1 -31
  114. package/dist/{notification.interface-CjzV_KII.d.ts → user.interface-CrmwJLYW.d.ts} +1 -31
  115. package/package.json +11 -1
  116. package/src/client/index.ts +2 -0
  117. package/src/components/containers/PageContainer.tsx +1 -1
  118. package/src/components/containers/RoundPageContainer.tsx +60 -16
  119. package/src/components/containers/RoundPageContainerTitle.tsx +75 -35
  120. package/src/components/editors/BlockNoteEditor.tsx +13 -1
  121. package/src/components/forms/EntityMultiSelector.tsx +4 -4
  122. package/src/components/forms/EntitySelector.tsx +4 -4
  123. package/src/components/forms/FormBlockNote.tsx +21 -1
  124. package/src/components/forms/FormCheckbox.tsx +6 -2
  125. package/src/components/forms/__tests__/useEditorDialog.test.ts +47 -0
  126. package/src/components/forms/useEditorDialog.ts +22 -0
  127. package/src/components/navigations/Breadcrumb.tsx +45 -16
  128. package/src/components/navigations/Header.tsx +16 -3
  129. package/src/components/navigations/MobileNavigationBar.tsx +12 -0
  130. package/src/components/navigations/__tests__/MobileNavigationBar.spec.tsx +17 -0
  131. package/src/components/tables/ContentListTable.tsx +52 -32
  132. package/src/core/index.ts +4 -0
  133. package/src/core/registry/ModuleRegistry.ts +7 -0
  134. package/src/features/__tests__/i18n-keys.contract.spec.ts +1 -0
  135. package/src/features/analytics/__tests__/server-entry.spec.tsx +64 -0
  136. package/src/features/analytics/analytics.modules.ts +30 -0
  137. package/src/features/analytics/components/AnalyticsAdminContainer.tsx +97 -0
  138. package/src/features/analytics/components/AnalyticsAdminFilterBar.tsx +120 -0
  139. package/src/features/analytics/components/AnalyticsAdminPageContainer.tsx +25 -0
  140. package/src/features/analytics/components/AnalyticsAdminTiles.tsx +191 -0
  141. package/src/features/analytics/components/AnalyticsBreakdownTable.tsx +105 -0
  142. package/src/features/analytics/components/AnalyticsJourneyContainer.tsx +246 -0
  143. package/src/features/analytics/components/AnalyticsJourneyPageContainer.tsx +14 -0
  144. package/src/features/analytics/components/AnalyticsSessionsTable.tsx +107 -0
  145. package/src/features/analytics/components/AnalyticsTimelineChart.tsx +175 -0
  146. package/src/features/analytics/components/AnalyticsTracker.tsx +112 -0
  147. package/src/features/analytics/components/__tests__/AnalyticsAdminTiles.spec.tsx +39 -0
  148. package/src/features/analytics/components/__tests__/AnalyticsBreakdownTable.spec.tsx +39 -0
  149. package/src/features/analytics/components/__tests__/AnalyticsJourneyContainer.spec.tsx +124 -0
  150. package/src/features/analytics/components/__tests__/AnalyticsPageContainers.spec.tsx +117 -0
  151. package/src/features/analytics/components/__tests__/AnalyticsSessionsTable.spec.tsx +121 -0
  152. package/src/features/analytics/components/__tests__/AnalyticsTimelineChart.spec.tsx +35 -0
  153. package/src/features/analytics/components/__tests__/AnalyticsTracker.spec.tsx +248 -0
  154. package/src/features/analytics/components/server/AnalyticsAdminPage.tsx +28 -0
  155. package/src/features/analytics/components/server/AnalyticsJourneyPage.tsx +25 -0
  156. package/src/features/analytics/contexts/AnalyticsAdminContext.tsx +273 -0
  157. package/src/features/analytics/contexts/__tests__/AnalyticsAdminContext.spec.tsx +140 -0
  158. package/src/features/analytics/data/AnalyticsAdminService.ts +91 -0
  159. package/src/features/analytics/data/AnalyticsService.ts +23 -0
  160. package/src/features/analytics/data/__tests__/AnalyticsAdminService.spec.ts +117 -0
  161. package/src/features/analytics/data/__tests__/AnalyticsService.spec.ts +56 -0
  162. package/src/features/analytics/data/__tests__/models.spec.ts +300 -0
  163. package/src/features/analytics/data/analytics-breakdown.interface.ts +9 -0
  164. package/src/features/analytics/data/analytics-breakdown.ts +65 -0
  165. package/src/features/analytics/data/analytics-event.interface.ts +7 -0
  166. package/src/features/analytics/data/analytics-event.ts +63 -0
  167. package/src/features/analytics/data/analytics-page-view.interface.ts +9 -0
  168. package/src/features/analytics/data/analytics-page-view.ts +57 -0
  169. package/src/features/analytics/data/analytics-session.interface.ts +23 -0
  170. package/src/features/analytics/data/analytics-session.ts +144 -0
  171. package/src/features/analytics/data/analytics-summary.interface.ts +11 -0
  172. package/src/features/analytics/data/analytics-summary.ts +79 -0
  173. package/src/features/analytics/data/analytics-timeline.interface.ts +10 -0
  174. package/src/features/analytics/data/analytics-timeline.ts +67 -0
  175. package/src/features/analytics/data/analytics.types.ts +97 -0
  176. package/src/features/analytics/data/index.ts +15 -0
  177. package/src/features/analytics/i18n-keys.ts +76 -0
  178. package/src/features/analytics/index.ts +31 -0
  179. package/src/features/analytics/lib/__tests__/utm.spec.ts +20 -0
  180. package/src/features/analytics/lib/__tests__/visitorCookie.spec.ts +63 -0
  181. package/src/features/analytics/lib/utm.ts +29 -0
  182. package/src/features/analytics/lib/visitorCookie.ts +32 -0
  183. package/src/features/analytics/server-entry.ts +8 -0
  184. package/src/features/assistant/components/parts/AssistantBlockNoteComposer.tsx +1 -1
  185. package/src/features/assistant/components/parts/AssistantComposer.tsx +1 -1
  186. package/src/features/assistant-message/components/MessageItem.tsx +2 -2
  187. package/src/features/assistant-message/components/parts/tabs/CitationsTab.tsx +23 -5
  188. package/src/features/auth/components/containers/AuthContainer.tsx +8 -1
  189. package/src/features/company/components/details/CompanyContent.tsx +3 -1
  190. package/src/features/company/components/details/CompanyDetails.tsx +9 -1
  191. package/src/features/company/components/details/TokenStatusIndicator.tsx +42 -13
  192. package/src/features/help/components/HelpHeader.tsx +7 -5
  193. package/src/features/tokenusage/components/TokenUsageAdminFilterBar.tsx +9 -6
  194. package/src/features/tokenusage/lib/__tests__/formatters.spec.ts +21 -0
  195. package/src/features/tokenusage/lib/formatters.ts +5 -1
  196. package/src/features/waitlist/components/lists/WaitlistList.tsx +68 -121
  197. package/src/features/waitlist/data/WaitlistService.ts +2 -2
  198. package/src/features/waitlist/data/index.ts +1 -0
  199. package/src/features/waitlist/data/waitlist.fields.ts +8 -0
  200. package/src/features/waitlist/hooks/useWaitlistTableStructure.tsx +69 -30
  201. package/src/shadcnui/ui/button.tsx +1 -1
  202. package/src/shadcnui/ui/checkbox.tsx +1 -1
  203. package/src/shadcnui/ui/command.tsx +4 -4
  204. package/src/shadcnui/ui/dialog.tsx +2 -0
  205. package/src/shadcnui/ui/input.tsx +1 -1
  206. package/src/shadcnui/ui/popover.tsx +9 -0
  207. package/src/shadcnui/ui/select.tsx +1 -1
  208. package/src/shadcnui/ui/sheet.tsx +8 -1
  209. package/src/shadcnui/ui/table.tsx +2 -2
  210. package/src/shadcnui/ui/textarea.tsx +1 -1
  211. package/dist/BlockNoteEditor-35D4R7HJ.js.map +0 -1
  212. package/dist/JsonApiRequest-G625QAH5.js +0 -26
  213. package/dist/chunk-2XCUAHQT.js.map +0 -1
  214. package/dist/chunk-4O7R2Z2O.mjs.map +0 -1
  215. package/dist/chunk-IBVKPLHT.mjs.map +0 -1
  216. package/dist/chunk-U7QVISQS.js.map +0 -1
  217. /package/dist/{BlockNoteViewer-KDKGUIG5.mjs.map → BlockNoteViewer-KRTAFTUX.mjs.map} +0 -0
  218. /package/dist/{JsonApiRequest-RRMNV7YE.mjs.map → JsonApiRequest-UHOWNI3O.mjs.map} +0 -0
  219. /package/dist/{chunk-T76WLDE5.mjs.map → chunk-37DMFVLN.mjs.map} +0 -0
  220. /package/dist/{chunk-ZJI5ZZW5.mjs.map → chunk-Q6J2ICKO.mjs.map} +0 -0
@@ -0,0 +1,1166 @@
1
+ "use client";
2
+ import {
3
+ percentageDelta,
4
+ seriesColor,
5
+ useUsageFormatters
6
+ } from "../../chunk-U65JPKO3.mjs";
7
+ import {
8
+ Badge,
9
+ Button,
10
+ Card,
11
+ CardContent,
12
+ CardHeader,
13
+ CardTitle,
14
+ ChartContainer,
15
+ ChartLegend,
16
+ ChartLegendContent,
17
+ ChartTooltip,
18
+ ChartTooltipContent,
19
+ DateRangeSelector,
20
+ DetailField,
21
+ Link,
22
+ MicroLabel,
23
+ RoundPageContainer,
24
+ SharedProvider,
25
+ Table,
26
+ TableBody,
27
+ TableCell,
28
+ TableHead,
29
+ TableHeader,
30
+ TableRow,
31
+ Tabs,
32
+ TabsContent,
33
+ TabsList,
34
+ TabsTrigger,
35
+ usePageUrlGenerator
36
+ } from "../../chunk-QWZAGQWJ.mjs";
37
+ import "../../chunk-Q6J2ICKO.mjs";
38
+ import {
39
+ AbstractService,
40
+ AnalyticsBreakdown,
41
+ AnalyticsEvent,
42
+ AnalyticsPageView,
43
+ AnalyticsSession,
44
+ AnalyticsSummary,
45
+ AnalyticsTimeline,
46
+ EndpointCreator,
47
+ Modules,
48
+ analyticsModules,
49
+ cn
50
+ } from "../../chunk-E3I4MT53.mjs";
51
+ import "../../chunk-37DMFVLN.mjs";
52
+ import "../../chunk-AUXK7QSA.mjs";
53
+ import "../../chunk-PI56A4DG.mjs";
54
+ import "../../chunk-VOXD3ZLY.mjs";
55
+ import {
56
+ __name
57
+ } from "../../chunk-PAWJFY3S.mjs";
58
+
59
+ // src/features/analytics/components/AnalyticsTracker.tsx
60
+ import { usePathname } from "next/navigation";
61
+ import { useEffect, useRef } from "react";
62
+ import { v4 as v42 } from "uuid";
63
+
64
+ // src/features/analytics/data/AnalyticsService.ts
65
+ var AnalyticsService = class extends AbstractService {
66
+ static {
67
+ __name(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: Modules.AnalyticsEvent,
78
+ method: "POST" /* POST */,
79
+ endpoint: new EndpointCreator({ endpoint: 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
+ __name(readUtm, "readUtm");
108
+
109
+ // src/features/analytics/lib/visitorCookie.ts
110
+ import { deleteCookie, getCookie, setCookie } from "cookies-next";
111
+ import { v4 } from "uuid";
112
+ var ANALYTICS_VISITOR_COOKIE = "analytics_visitor";
113
+ var MAX_AGE_SECONDS = 395 * 24 * 3600;
114
+ function readVisitorCookie() {
115
+ const value = getCookie(ANALYTICS_VISITOR_COOKIE);
116
+ return typeof value === "string" && value !== "" ? value : void 0;
117
+ }
118
+ __name(readVisitorCookie, "readVisitorCookie");
119
+ function ensureVisitorCookie() {
120
+ const existing = readVisitorCookie();
121
+ if (existing) return existing;
122
+ const id = v4();
123
+ setCookie(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
+ __name(ensureVisitorCookie, "ensureVisitorCookie");
132
+ function clearVisitorCookie() {
133
+ deleteCookie(ANALYTICS_VISITOR_COOKIE, { path: "/" });
134
+ }
135
+ __name(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 {
145
+ return void 0;
146
+ }
147
+ return document.referrer.slice(0, MAX_REFERRER_LENGTH);
148
+ }
149
+ __name(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
+ __name(maskSensitivePath, "maskSensitivePath");
162
+ function AnalyticsTracker({ hasConsent, resolveSection, sensitivePrefixes }) {
163
+ const pathname = usePathname();
164
+ const lastPath = useRef(null);
165
+ const lastConsent = useRef(false);
166
+ const attribution = useRef(null);
167
+ useEffect(() => {
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: v42(),
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
+ __name(AnalyticsTracker, "AnalyticsTracker");
197
+
198
+ // src/features/analytics/contexts/AnalyticsAdminContext.tsx
199
+ import { useTranslations as useTranslations2 } from "next-intl";
200
+ import { createContext, useCallback, useContext, useEffect as useEffect2, useMemo, useState } from "react";
201
+
202
+ // src/features/analytics/components/AnalyticsAdminFilterBar.tsx
203
+ import { useTranslations } from "next-intl";
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
+ import { jsx, jsxs } from "react/jsx-runtime";
212
+ function AnalyticsAdminFilterBar({ section, granularity, onChange }) {
213
+ const t = useTranslations();
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__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
225
+ /* @__PURE__ */ jsx("div", { className: "max-md:w-full max-md:[&_#date]:w-full", children: /* @__PURE__ */ jsx(
226
+ DateRangeSelector,
227
+ {
228
+ onDateChange: (range) => {
229
+ if (!range?.from || !range?.to) return;
230
+ onChange({ from: range.from.toISOString(), to: range.to.toISOString() });
231
+ }
232
+ }
233
+ ) }),
234
+ /* @__PURE__ */ jsx(
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__ */ jsx(
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
+ __name(AnalyticsAdminFilterBar, "AnalyticsAdminFilterBar");
255
+ function Segmented({
256
+ ariaLabel,
257
+ value,
258
+ options,
259
+ onSelect
260
+ }) {
261
+ return /* @__PURE__ */ jsx(
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__ */ jsx(
270
+ Button,
271
+ {
272
+ type: "button",
273
+ size: "sm",
274
+ variant: selected ? "default" : "ghost",
275
+ "aria-pressed": selected,
276
+ className: cn(!selected && "text-muted-foreground"),
277
+ onClick: () => onSelect(option.value),
278
+ children: option.label
279
+ },
280
+ option.value
281
+ );
282
+ })
283
+ }
284
+ );
285
+ }
286
+ __name(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
+ __name(withFilters, "withFilters");
296
+ var AnalyticsAdminService = class extends AbstractService {
297
+ static {
298
+ __name(this, "AnalyticsAdminService");
299
+ }
300
+ /** Headline tiles: one row per window (current, previous). */
301
+ static async getSummary(filters) {
302
+ const endpoint = withFilters(new EndpointCreator({ endpoint: Modules.AnalyticsSummary }), filters);
303
+ return this.callApi({
304
+ type: Modules.AnalyticsSummary,
305
+ method: "GET" /* GET */,
306
+ endpoint: endpoint.generate()
307
+ });
308
+ }
309
+ static async getTimeline(params) {
310
+ const endpoint = withFilters(new EndpointCreator({ endpoint: Modules.AnalyticsTimeline }), params);
311
+ endpoint.addAdditionalParam("granularity", params.granularity);
312
+ return this.callApi({
313
+ type: Modules.AnalyticsTimeline,
314
+ method: "GET" /* GET */,
315
+ endpoint: endpoint.generate()
316
+ });
317
+ }
318
+ static async getBreakdown(params) {
319
+ const endpoint = withFilters(new EndpointCreator({ endpoint: 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: 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 EndpointCreator({ endpoint: 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: 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: Modules.AnalyticsSession,
343
+ method: "GET" /* GET */,
344
+ endpoint: new EndpointCreator({ endpoint: 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: Modules.AnalyticsPageView,
351
+ method: "GET" /* GET */,
352
+ endpoint: new EndpointCreator({
353
+ endpoint: Modules.AnalyticsSession,
354
+ id: params.sessionId,
355
+ childEndpoint: Modules.AnalyticsPageView
356
+ }).generate()
357
+ });
358
+ }
359
+ };
360
+
361
+ // src/features/analytics/contexts/AnalyticsAdminContext.tsx
362
+ import { jsx as jsx2 } from "react/jsx-runtime";
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 = createContext(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
+ __name(defaultRange, "defaultRange");
382
+ var AnalyticsAdminProvider = /* @__PURE__ */ __name(({
383
+ children,
384
+ initialFrom,
385
+ initialTo,
386
+ pageUrl = ANALYTICS_ADMIN_PAGE_URL,
387
+ sessionPageUrl = ANALYTICS_SESSION_PAGE_URL
388
+ }) => {
389
+ const t = useTranslations2();
390
+ const generateUrl = usePageUrlGenerator();
391
+ const [filters, setFilterState] = useState(() => {
392
+ const range = defaultRange();
393
+ return {
394
+ from: initialFrom ?? range.from,
395
+ to: initialTo ?? range.to,
396
+ section: "all",
397
+ granularity: "day"
398
+ };
399
+ });
400
+ const [summary, setSummary] = useState([]);
401
+ const [timeline, setTimeline] = useState([]);
402
+ const [breakdowns, setBreakdowns] = useState(EMPTY_BREAKDOWNS);
403
+ const [sessions, setSessions] = useState([]);
404
+ const [sessionsNextPage, setSessionsNextPage] = useState(void 0);
405
+ const [isLoading, setIsLoading] = useState(true);
406
+ const [error, setError] = useState(null);
407
+ const { from, to, section, granularity } = filters;
408
+ useEffect2(() => {
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(nextSummary ?? []);
426
+ setTimeline(nextTimeline ?? []);
427
+ setBreakdowns(
428
+ Object.fromEntries(
429
+ ANALYTICS_DIMENSIONS.map((dimension, index) => [dimension, nextBreakdowns[index] ?? []])
430
+ )
431
+ );
432
+ setSessions(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 = useCallback((next) => {
447
+ setFilterState((prev) => ({ ...prev, ...next }));
448
+ }, []);
449
+ const loadMoreSessions = useCallback(async () => {
450
+ if (!sessionsNextPage) return;
451
+ const sessionsNext = {};
452
+ try {
453
+ const nextSessions = await AnalyticsAdminService.next({
454
+ type: Modules.AnalyticsSession,
455
+ endpoint: sessionsNextPage,
456
+ next: sessionsNext
457
+ });
458
+ setSessions((prev) => [...prev, ...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__ */ __name(() => [
466
+ {
467
+ name: t("analytics.admin.title"),
468
+ href: generateUrl({ page: pageUrl })
469
+ }
470
+ ], "breadcrumb");
471
+ const title = /* @__PURE__ */ __name(() => ({
472
+ type: t("analytics.admin.title"),
473
+ functions: /* @__PURE__ */ jsx2(
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 = useMemo(
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__ */ jsx2(SharedProvider, { value: { breadcrumbs: breadcrumb(), title: title() }, children: /* @__PURE__ */ jsx2(AnalyticsAdminContext.Provider, { value: contextValue, children }) });
515
+ }, "AnalyticsAdminProvider");
516
+ var useAnalyticsAdmin = /* @__PURE__ */ __name(() => {
517
+ const ctx = useContext(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
+ import { useTranslations as useTranslations7 } from "next-intl";
526
+
527
+ // src/features/analytics/components/AnalyticsAdminTiles.tsx
528
+ import { ArrowDownIcon, ArrowUpIcon } from "lucide-react";
529
+ import { useTranslations as useTranslations3 } from "next-intl";
530
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
531
+ var ZERO = { visitors: 0, sessions: 0, pageViews: 0, pagesPerSession: 0, consentShare: 0 };
532
+ function AnalyticsAdminTiles({ summary }) {
533
+ const t = useTranslations3();
534
+ const { decimal } = useUsageFormatters();
535
+ const rowFor = /* @__PURE__ */ __name((window2) => 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__ */ jsxs2("div", { className: "grid gap-3", children: [
540
+ /* @__PURE__ */ jsxs2("div", { className: "grid gap-3 sm:grid-cols-3", children: [
541
+ /* @__PURE__ */ jsx3(
542
+ LeadTile,
543
+ {
544
+ testId: "analytics-tile-visitors",
545
+ label: t("analytics.admin.tiles.visitors"),
546
+ value: decimal(current.visitors, 0),
547
+ delta: percentageDelta(current.visitors, previous.visitors),
548
+ previousLabel,
549
+ decimal
550
+ }
551
+ ),
552
+ /* @__PURE__ */ jsx3(
553
+ LeadTile,
554
+ {
555
+ testId: "analytics-tile-sessions",
556
+ label: t("analytics.admin.tiles.sessions"),
557
+ value: decimal(current.sessions, 0),
558
+ delta: percentageDelta(current.sessions, previous.sessions),
559
+ previousLabel,
560
+ decimal
561
+ }
562
+ ),
563
+ /* @__PURE__ */ jsx3(
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: percentageDelta(current.pageViews, previous.pageViews),
570
+ previousLabel,
571
+ decimal
572
+ }
573
+ )
574
+ ] }),
575
+ /* @__PURE__ */ jsxs2("div", { className: "grid gap-3 sm:grid-cols-2", children: [
576
+ /* @__PURE__ */ jsx3(
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: percentageDelta(current.pagesPerSession, previous.pagesPerSession),
583
+ decimal
584
+ }
585
+ ),
586
+ /* @__PURE__ */ jsx3(
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
+ __name(AnalyticsAdminTiles, "AnalyticsAdminTiles");
599
+ function LeadTile({
600
+ testId,
601
+ label,
602
+ value,
603
+ delta,
604
+ previousLabel,
605
+ decimal
606
+ }) {
607
+ return /* @__PURE__ */ jsx3(Card, { "data-testid": testId, children: /* @__PURE__ */ jsxs2(CardContent, { className: "grid gap-1", children: [
608
+ /* @__PURE__ */ jsx3(MicroLabel, { children: label }),
609
+ /* @__PURE__ */ jsx3("span", { className: "text-primary text-xl font-semibold tabular-nums", children: value }),
610
+ /* @__PURE__ */ jsxs2("span", { className: "flex items-center gap-1", children: [
611
+ /* @__PURE__ */ jsx3(Delta, { testId: `${testId}-delta`, delta, decimal }),
612
+ /* @__PURE__ */ jsx3("span", { className: "text-muted-foreground text-xs", children: previousLabel })
613
+ ] })
614
+ ] }) });
615
+ }
616
+ __name(LeadTile, "LeadTile");
617
+ function SupportingTile({
618
+ testId,
619
+ label,
620
+ value,
621
+ delta,
622
+ decimal
623
+ }) {
624
+ return /* @__PURE__ */ jsx3(Card, { "data-testid": testId, size: "sm", children: /* @__PURE__ */ jsxs2(CardContent, { className: "grid gap-1", children: [
625
+ /* @__PURE__ */ jsx3(MicroLabel, { children: label }),
626
+ /* @__PURE__ */ jsxs2("span", { className: "flex items-center gap-2", children: [
627
+ /* @__PURE__ */ jsx3("span", { className: "text-sm font-medium tabular-nums", children: value }),
628
+ delta !== void 0 && /* @__PURE__ */ jsx3(Delta, { testId: `${testId}-delta`, delta, decimal })
629
+ ] })
630
+ ] }) });
631
+ }
632
+ __name(SupportingTile, "SupportingTile");
633
+ function Delta({
634
+ testId,
635
+ delta,
636
+ decimal
637
+ }) {
638
+ if (delta === void 0) {
639
+ return /* @__PURE__ */ jsx3("span", { "data-testid": testId, className: "text-muted-foreground text-xs", children: "\u2014" });
640
+ }
641
+ const increased = delta >= 0;
642
+ const Icon = increased ? ArrowUpIcon : ArrowDownIcon;
643
+ const sign = delta > 0 ? "+" : delta < 0 ? "-" : "";
644
+ return /* @__PURE__ */ jsxs2(
645
+ "span",
646
+ {
647
+ "data-testid": testId,
648
+ className: cn(
649
+ "inline-flex items-center gap-0.5 text-xs tabular-nums",
650
+ increased ? "text-success" : "text-destructive"
651
+ ),
652
+ children: [
653
+ /* @__PURE__ */ jsx3(Icon, { "aria-hidden": true, className: "size-3" }),
654
+ `${sign}${decimal(Math.abs(delta), 0)}%`
655
+ ]
656
+ }
657
+ );
658
+ }
659
+ __name(Delta, "Delta");
660
+
661
+ // src/features/analytics/components/AnalyticsBreakdownTable.tsx
662
+ import { useTranslations as useTranslations4 } from "next-intl";
663
+ import { useMemo as useMemo2 } from "react";
664
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
665
+ var OTHER_KEY = "other";
666
+ function AnalyticsBreakdownTable({ breakdowns }) {
667
+ const t = useTranslations4();
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__ */ jsxs3(Tabs, { defaultValue: ANALYTICS_DIMENSIONS[0], children: [
677
+ /* @__PURE__ */ jsx4(TabsList, { className: "max-md:w-full max-md:justify-start max-md:overflow-x-auto", children: ANALYTICS_DIMENSIONS.map((dimension) => /* @__PURE__ */ jsx4(TabsTrigger, { value: dimension, children: labels[dimension] }, dimension)) }),
678
+ ANALYTICS_DIMENSIONS.map((dimension) => /* @__PURE__ */ jsx4(TabsContent, { value: dimension, children: /* @__PURE__ */ jsx4(BreakdownRows, { rows: breakdowns[dimension] ?? [] }) }, dimension))
679
+ ] });
680
+ }
681
+ __name(AnalyticsBreakdownTable, "AnalyticsBreakdownTable");
682
+ function BreakdownRows({ rows }) {
683
+ const t = useTranslations4();
684
+ const { decimal } = useUsageFormatters();
685
+ const sortedRows = useMemo2(() => [...rows].sort((a, b) => b.visitors - a.visitors), [rows]);
686
+ if (sortedRows.length === 0) {
687
+ return /* @__PURE__ */ jsx4("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__ */ jsx4("div", { className: "overflow-x-auto [&_[data-slot=table-container]]:overflow-x-visible", children: /* @__PURE__ */ jsxs3(Table, { children: [
694
+ /* @__PURE__ */ jsx4(TableHeader, { children: /* @__PURE__ */ jsxs3(TableRow, { children: [
695
+ /* @__PURE__ */ jsx4(TableHead, { className: "text-xs font-medium", children: t("analytics.admin.columns.key") }),
696
+ /* @__PURE__ */ jsx4(TableHead, { className: "text-end text-xs font-medium", children: t("analytics.admin.columns.visitors") }),
697
+ /* @__PURE__ */ jsx4(TableHead, { className: "text-end text-xs font-medium", children: t("analytics.admin.columns.sessions") }),
698
+ /* @__PURE__ */ jsx4(TableHead, { className: "text-end text-xs font-medium", children: t("analytics.admin.columns.page_views") })
699
+ ] }) }),
700
+ /* @__PURE__ */ jsx4(TableBody, { children: sortedRows.map((row) => /* @__PURE__ */ jsxs3(TableRow, { "data-testid": `analytics-breakdown-row-${row.id}`, children: [
701
+ /* @__PURE__ */ jsx4(TableCell, { className: "text-xs", children: row.key === OTHER_KEY ? t("analytics.admin.other") : row.key }),
702
+ /* @__PURE__ */ jsx4(TableCell, { className: "text-end text-xs tabular-nums", children: decimal(row.visitors, 0) }),
703
+ /* @__PURE__ */ jsx4(TableCell, { className: "text-end text-xs tabular-nums", children: decimal(row.sessions, 0) }),
704
+ /* @__PURE__ */ jsx4(TableCell, { className: "text-end text-xs tabular-nums", children: decimal(row.pageViews, 0) })
705
+ ] }, row.id)) })
706
+ ] }) })
707
+ );
708
+ }
709
+ __name(BreakdownRows, "BreakdownRows");
710
+
711
+ // src/features/analytics/components/AnalyticsSessionsTable.tsx
712
+ import { useLocale, useTranslations as useTranslations5 } from "next-intl";
713
+ import { useMemo as useMemo3 } from "react";
714
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
715
+ var VISITOR_SUFFIX_LENGTH = 6;
716
+ function AnalyticsSessionsTable({ rows, sessionPageUrl, onLoadMore, hasMore }) {
717
+ const t = useTranslations5();
718
+ const locale = useLocale();
719
+ const generateUrl = usePageUrlGenerator();
720
+ const { decimal } = useUsageFormatters();
721
+ const dateTime = useMemo3(() => new Intl.DateTimeFormat(locale, { dateStyle: "short", timeStyle: "short" }), [locale]);
722
+ if (rows.length === 0) {
723
+ return /* @__PURE__ */ jsx5("p", { className: "text-muted-foreground text-sm", children: t("analytics.admin.no_data") });
724
+ }
725
+ return /* @__PURE__ */ jsxs4("div", { className: "flex flex-col gap-3", children: [
726
+ /* @__PURE__ */ jsx5("div", { className: "overflow-x-auto [&_[data-slot=table-container]]:overflow-x-visible", children: /* @__PURE__ */ jsxs4(Table, { children: [
727
+ /* @__PURE__ */ jsx5(TableHeader, { children: /* @__PURE__ */ jsxs4(TableRow, { children: [
728
+ /* @__PURE__ */ jsx5(TableHead, { className: "text-xs font-medium", children: t("analytics.admin.columns.started") }),
729
+ /* @__PURE__ */ jsx5(TableHead, { className: "text-xs font-medium", children: t("analytics.admin.columns.visitor") }),
730
+ /* @__PURE__ */ jsx5(TableHead, { className: "text-xs font-medium", children: t("analytics.admin.columns.source") }),
731
+ /* @__PURE__ */ jsx5(TableHead, { className: "text-xs font-medium", children: t("analytics.admin.columns.landing") }),
732
+ /* @__PURE__ */ jsx5(TableHead, { className: "text-end text-xs font-medium", children: t("analytics.admin.columns.pages") }),
733
+ /* @__PURE__ */ jsx5(TableHead, { className: "text-xs font-medium", children: t("analytics.admin.columns.device") })
734
+ ] }) }),
735
+ /* @__PURE__ */ jsx5(TableBody, { children: rows.map((row) => {
736
+ const source = [row.utmSource ?? row.referrerHost, row.utmMedium].filter(Boolean).join(" / ");
737
+ return /* @__PURE__ */ jsxs4(TableRow, { "data-testid": `analytics-session-row-${row.id}`, children: [
738
+ /* @__PURE__ */ jsx5(TableCell, { className: "text-xs tabular-nums", children: /* @__PURE__ */ jsx5(
739
+ 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__ */ jsx5(TableCell, { className: "text-xs", children: row.user ? /* @__PURE__ */ jsxs4("span", { className: "flex flex-col", children: [
747
+ /* @__PURE__ */ jsx5("span", { children: row.user.name }),
748
+ /* @__PURE__ */ jsx5("span", { className: "text-muted-foreground text-xs", children: row.user.email })
749
+ ] }) : /* @__PURE__ */ jsxs4("span", { className: "flex items-center gap-2", children: [
750
+ /* @__PURE__ */ jsx5(Badge, { variant: "softGray", children: t("analytics.admin.anonymous") }),
751
+ /* @__PURE__ */ jsx5("span", { className: "text-muted-foreground text-xs tabular-nums", children: row.visitorId.slice(-VISITOR_SUFFIX_LENGTH) })
752
+ ] }) }),
753
+ /* @__PURE__ */ jsx5(TableCell, { className: "text-xs", children: source }),
754
+ /* @__PURE__ */ jsx5(TableCell, { className: "text-xs", children: row.landingRoute }),
755
+ /* @__PURE__ */ jsx5(TableCell, { className: "text-end text-xs tabular-nums", children: decimal(row.pageViews, 0) }),
756
+ /* @__PURE__ */ jsx5(TableCell, { className: "text-muted-foreground text-xs", children: row.deviceType })
757
+ ] }, row.id);
758
+ }) })
759
+ ] }) }),
760
+ hasMore && /* @__PURE__ */ jsx5("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx5(Button, { type: "button", variant: "outline", size: "sm", onClick: onLoadMore, children: t("analytics.admin.load_more") }) })
761
+ ] });
762
+ }
763
+ __name(AnalyticsSessionsTable, "AnalyticsSessionsTable");
764
+
765
+ // src/features/analytics/components/AnalyticsTimelineChart.tsx
766
+ import { useTranslations as useTranslations6 } from "next-intl";
767
+ import { useTheme } from "next-themes";
768
+ import { useMemo as useMemo4 } from "react";
769
+ import { Bar, BarChart, CartesianGrid, XAxis, YAxis } from "recharts";
770
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
771
+ var SERIES = ["visitors", "pageViews"];
772
+ var bucketKey = /* @__PURE__ */ __name((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__ */ __name((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 = useTranslations6();
792
+ const { compact, bucketDate, decimal } = useUsageFormatters();
793
+ const { resolvedTheme } = useTheme();
794
+ const mode = resolvedTheme === "dark" ? "dark" : "light";
795
+ const chartData = useMemo4(() => {
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 = useMemo4(
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__ */ jsx6("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__ */ jsxs5("div", { className, dir: "ltr", children: [
826
+ /* @__PURE__ */ jsx6("span", { className: "sr-only", "data-testid": "analytics-timeline-data", children: JSON.stringify(chartData) }),
827
+ /* @__PURE__ */ jsx6(ChartContainer, { config: chartConfig, className: "aspect-auto h-72 w-full", children: /* @__PURE__ */ jsxs5(BarChart, { accessibilityLayer: true, data: chartData, margin: { top: 8, right: 8, bottom: 0, left: 0 }, children: [
828
+ /* @__PURE__ */ jsx6(CartesianGrid, { vertical: false }),
829
+ /* @__PURE__ */ jsx6(
830
+ 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__ */ jsx6(
841
+ YAxis,
842
+ {
843
+ tickLine: false,
844
+ axisLine: false,
845
+ tickMargin: 8,
846
+ width: 48,
847
+ tickFormatter: (value) => compact(value)
848
+ }
849
+ ),
850
+ /* @__PURE__ */ jsx6(
851
+ ChartTooltip,
852
+ {
853
+ content: /* @__PURE__ */ jsx6(
854
+ ChartTooltipContent,
855
+ {
856
+ labelFormatter: (value) => bucketDate(String(value), granularity),
857
+ valueFormatter: (value) => decimal(Number(value), 0)
858
+ }
859
+ )
860
+ }
861
+ ),
862
+ /* @__PURE__ */ jsx6(ChartLegend, { content: /* @__PURE__ */ jsx6(ChartLegendContent, {}) }),
863
+ SERIES.map((series, index) => /* @__PURE__ */ jsx6(
864
+ Bar,
865
+ {
866
+ dataKey: series,
867
+ maxBarSize: 28,
868
+ fill: seriesColor(index, mode),
869
+ stroke: "var(--background)",
870
+ strokeWidth: 2,
871
+ radius: [4, 4, 0, 0]
872
+ },
873
+ series
874
+ ))
875
+ ] }) })
876
+ ] })
877
+ );
878
+ }
879
+ __name(AnalyticsTimelineChart, "AnalyticsTimelineChart");
880
+
881
+ // src/features/analytics/components/AnalyticsAdminContainer.tsx
882
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
883
+ function AnalyticsAdminContainer() {
884
+ const t = useTranslations7();
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__ */ jsx7(RoundPageContainer, { fullWidth: true, forceHeader: true, children: /* @__PURE__ */ jsx7("div", { className: "p-4", children: /* @__PURE__ */ jsx7(Card, { children: /* @__PURE__ */ jsx7(CardContent, { children: /* @__PURE__ */ jsx7("p", { className: "text-destructive text-xs/relaxed", children: error }) }) }) }) });
898
+ }
899
+ if (isLoading) return /* @__PURE__ */ jsx7(RoundPageContainer, { fullWidth: true, forceHeader: true });
900
+ return /* @__PURE__ */ jsx7(RoundPageContainer, { fullWidth: true, forceHeader: true, children: /* @__PURE__ */ jsxs6("div", { className: "flex w-full flex-col gap-4 p-4", children: [
901
+ /* @__PURE__ */ jsxs6("div", { className: "flex flex-col gap-2", children: [
902
+ /* @__PURE__ */ jsx7(AnalyticsAdminTiles, { summary }),
903
+ /* @__PURE__ */ jsx7("p", { className: "text-muted-foreground text-xs", children: t("analytics.admin.tiles.summarised_note") })
904
+ ] }),
905
+ /* @__PURE__ */ jsxs6(Card, { children: [
906
+ /* @__PURE__ */ jsx7(CardHeader, { children: /* @__PURE__ */ jsx7(CardTitle, { children: t("analytics.admin.panels.over_time") }) }),
907
+ /* @__PURE__ */ jsx7(CardContent, { children: /* @__PURE__ */ jsx7(AnalyticsTimelineChart, { rows: timeline }) })
908
+ ] }),
909
+ /* @__PURE__ */ jsxs6(Card, { children: [
910
+ /* @__PURE__ */ jsx7(CardHeader, { children: /* @__PURE__ */ jsx7(CardTitle, { children: t("analytics.admin.panels.breakdown") }) }),
911
+ /* @__PURE__ */ jsx7(CardContent, { children: /* @__PURE__ */ jsx7(AnalyticsBreakdownTable, { breakdowns }) })
912
+ ] }),
913
+ /* @__PURE__ */ jsxs6(Card, { children: [
914
+ /* @__PURE__ */ jsx7(CardHeader, { children: /* @__PURE__ */ jsx7(CardTitle, { children: t("analytics.admin.panels.sessions") }) }),
915
+ /* @__PURE__ */ jsx7(CardContent, { children: /* @__PURE__ */ jsx7(
916
+ AnalyticsSessionsTable,
917
+ {
918
+ rows: sessions,
919
+ sessionPageUrl,
920
+ onLoadMore: loadMoreSessions,
921
+ hasMore: hasMoreSessions
922
+ }
923
+ ) })
924
+ ] })
925
+ ] }) });
926
+ }
927
+ __name(AnalyticsAdminContainer, "AnalyticsAdminContainer");
928
+
929
+ // src/features/analytics/components/AnalyticsJourneyContainer.tsx
930
+ import { useLocale as useLocale2, useTranslations as useTranslations8 } from "next-intl";
931
+ import { useEffect as useEffect3, useMemo as useMemo5, useState as useState2 } from "react";
932
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
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 = useTranslations8();
937
+ const locale = useLocale2();
938
+ const generateUrl = usePageUrlGenerator();
939
+ const [session, setSession] = useState2(void 0);
940
+ const [pageViews, setPageViews] = useState2([]);
941
+ const [otherSessions, setOtherSessions] = useState2([]);
942
+ const [isLoading, setIsLoading] = useState2(true);
943
+ const [error, setError] = useState2(null);
944
+ useEffect3(() => {
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(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((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 = useMemo5(
978
+ () => new Intl.DateTimeFormat(locale, { dateStyle: "short", timeStyle: "medium" }),
979
+ [locale]
980
+ );
981
+ const formatGap = /* @__PURE__ */ __name((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__ */ __name(() => {
993
+ if (error) {
994
+ return /* @__PURE__ */ jsx8(RoundPageContainer, { fullWidth: true, forceHeader: true, children: /* @__PURE__ */ jsx8("div", { className: "p-4", children: /* @__PURE__ */ jsx8(Card, { children: /* @__PURE__ */ jsx8(CardContent, { children: /* @__PURE__ */ jsx8("p", { className: "text-destructive text-xs/relaxed", children: error }) }) }) }) });
995
+ }
996
+ if (isLoading || !session) return /* @__PURE__ */ jsx8(RoundPageContainer, { fullWidth: true, forceHeader: true });
997
+ const source = [session.utmSource ?? session.referrerHost, session.utmMedium, session.utmCampaign].filter(Boolean).join(" / ");
998
+ return /* @__PURE__ */ jsx8(RoundPageContainer, { fullWidth: true, forceHeader: true, children: /* @__PURE__ */ jsxs7("div", { className: "flex w-full flex-col gap-4 p-4", children: [
999
+ /* @__PURE__ */ jsx8(Card, { "data-testid": "analytics-journey-attribution", children: /* @__PURE__ */ jsxs7(CardContent, { className: "flex flex-col gap-3", children: [
1000
+ /* @__PURE__ */ jsxs7("div", { className: "flex flex-wrap items-center gap-2", children: [
1001
+ session.user ? /* @__PURE__ */ jsxs7("span", { className: "flex flex-col", children: [
1002
+ /* @__PURE__ */ jsx8("span", { className: "text-sm", children: session.user.name }),
1003
+ /* @__PURE__ */ jsx8("span", { className: "text-muted-foreground text-xs", children: session.user.email })
1004
+ ] }) : /* @__PURE__ */ jsx8(Badge, { variant: "softGray", children: t("analytics.admin.anonymous") }),
1005
+ session.consented ? /* @__PURE__ */ jsx8(Badge, { variant: "softGreen", children: t("analytics.admin.consented") }) : /* @__PURE__ */ jsx8(Badge, { variant: "softGray", children: t("analytics.admin.not_consented") })
1006
+ ] }),
1007
+ /* @__PURE__ */ jsxs7("div", { className: "grid gap-3 sm:grid-cols-3", children: [
1008
+ /* @__PURE__ */ jsx8(DetailField, { label: t("analytics.admin.columns.started"), value: dateTime.format(session.startedAt) }),
1009
+ /* @__PURE__ */ jsx8(DetailField, { label: t("analytics.admin.columns.source"), value: source }),
1010
+ /* @__PURE__ */ jsx8(DetailField, { label: t("analytics.admin.columns.landing"), value: session.landingRoute }),
1011
+ /* @__PURE__ */ jsx8(DetailField, { label: t("analytics.admin.columns.device"), value: session.deviceType }),
1012
+ /* @__PURE__ */ jsx8(
1013
+ DetailField,
1014
+ {
1015
+ label: t("analytics.admin.columns.visitor"),
1016
+ value: /* @__PURE__ */ jsx8("span", { className: "tabular-nums", children: session.visitorId })
1017
+ }
1018
+ )
1019
+ ] })
1020
+ ] }) }),
1021
+ /* @__PURE__ */ jsxs7(Card, { children: [
1022
+ /* @__PURE__ */ jsx8(CardHeader, { children: /* @__PURE__ */ jsx8(CardTitle, { children: t("analytics.admin.columns.pages") }) }),
1023
+ /* @__PURE__ */ jsx8(CardContent, { children: pageViews.length === 0 ? /* @__PURE__ */ jsx8("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__ */ jsx8("div", { className: "overflow-x-auto [&_[data-slot=table-container]]:overflow-x-visible", children: /* @__PURE__ */ jsxs7(Table, { children: [
1027
+ /* @__PURE__ */ jsx8(TableHeader, { children: /* @__PURE__ */ jsxs7(TableRow, { children: [
1028
+ /* @__PURE__ */ jsx8(TableHead, { className: "text-xs font-medium", children: t("analytics.admin.columns.time") }),
1029
+ /* @__PURE__ */ jsx8(TableHead, { className: "text-end text-xs font-medium", children: t("analytics.admin.columns.gap") }),
1030
+ /* @__PURE__ */ jsx8(TableHead, { className: "text-xs font-medium", children: t("analytics.admin.columns.path") })
1031
+ ] }) }),
1032
+ /* @__PURE__ */ jsx8(TableBody, { children: pageViews.map((pageView, index) => {
1033
+ const previous = index > 0 ? pageViews[index - 1] : void 0;
1034
+ return /* @__PURE__ */ jsxs7(TableRow, { "data-testid": `analytics-pageview-row-${pageView.id}`, children: [
1035
+ /* @__PURE__ */ jsx8(TableCell, { className: "text-xs tabular-nums", children: dateTime.format(pageView.createdAt) }),
1036
+ /* @__PURE__ */ jsx8(TableCell, { className: "text-end text-xs tabular-nums", children: previous ? formatGap(pageView.createdAt.getTime() - previous.createdAt.getTime()) : "\u2014" }),
1037
+ /* @__PURE__ */ jsx8(TableCell, { className: "text-xs", children: pageView.path })
1038
+ ] }, pageView.id);
1039
+ }) })
1040
+ ] }) })
1041
+ ) })
1042
+ ] }),
1043
+ /* @__PURE__ */ jsxs7(Card, { children: [
1044
+ /* @__PURE__ */ jsx8(CardHeader, { children: /* @__PURE__ */ jsx8(CardTitle, { children: t("analytics.admin.panels.other_sessions") }) }),
1045
+ /* @__PURE__ */ jsx8(CardContent, { children: /* @__PURE__ */ jsx8(
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__ */ jsx8(SharedProvider, { value: { breadcrumbs: breadcrumb, title }, children: renderBody() });
1058
+ }
1059
+ __name(AnalyticsJourneyContainer, "AnalyticsJourneyContainer");
1060
+ function unit(locale, name, value) {
1061
+ return new Intl.NumberFormat(locale, { style: "unit", unit: name, unitDisplay: "short" }).format(value);
1062
+ }
1063
+ __name(unit, "unit");
1064
+
1065
+ // src/features/analytics/components/AnalyticsAdminPageContainer.tsx
1066
+ import { jsx as jsx9 } from "react/jsx-runtime";
1067
+ function AnalyticsAdminPageContainer({ pageUrl, sessionPageUrl }) {
1068
+ return /* @__PURE__ */ jsx9(AnalyticsAdminProvider, { pageUrl, sessionPageUrl, children: /* @__PURE__ */ jsx9(AnalyticsAdminContainer, {}) });
1069
+ }
1070
+ __name(AnalyticsAdminPageContainer, "AnalyticsAdminPageContainer");
1071
+
1072
+ // src/features/analytics/components/AnalyticsJourneyPageContainer.tsx
1073
+ import { jsx as jsx10 } from "react/jsx-runtime";
1074
+ function AnalyticsJourneyPageContainer({ sessionId, pageUrl }) {
1075
+ return /* @__PURE__ */ jsx10(AnalyticsJourneyContainer, { sessionId, pageUrl });
1076
+ }
1077
+ __name(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
+ export {
1140
+ ANALYTICS_ADMIN_I18N_KEYS,
1141
+ ANALYTICS_DIMENSIONS,
1142
+ ANALYTICS_GRANULARITIES,
1143
+ ANALYTICS_SECTIONS,
1144
+ AnalyticsAdminContainer,
1145
+ AnalyticsAdminFilterBar,
1146
+ AnalyticsAdminPageContainer,
1147
+ AnalyticsAdminProvider,
1148
+ AnalyticsAdminService,
1149
+ AnalyticsAdminTiles,
1150
+ AnalyticsBreakdown,
1151
+ AnalyticsBreakdownTable,
1152
+ AnalyticsEvent,
1153
+ AnalyticsJourneyContainer,
1154
+ AnalyticsJourneyPageContainer,
1155
+ AnalyticsPageView,
1156
+ AnalyticsService,
1157
+ AnalyticsSession,
1158
+ AnalyticsSessionsTable,
1159
+ AnalyticsSummary,
1160
+ AnalyticsTimeline,
1161
+ AnalyticsTimelineChart,
1162
+ AnalyticsTracker,
1163
+ analyticsModules,
1164
+ useAnalyticsAdmin
1165
+ };
1166
+ //# sourceMappingURL=index.mjs.map