strapi-plugin-magic-sessionmanager 1.0.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.
@@ -0,0 +1,600 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const jsxRuntime = require("react/jsx-runtime");
4
+ const react = require("react");
5
+ const admin = require("@strapi/strapi/admin");
6
+ const styled = require("styled-components");
7
+ const designSystem = require("@strapi/design-system");
8
+ const icons = require("@strapi/icons");
9
+ const index = require("./index-Dd_SkI79.js");
10
+ const useLicense = require("./useLicense-Bw66_4CW.js");
11
+ const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
12
+ const styled__default = /* @__PURE__ */ _interopDefault(styled);
13
+ const theme = {
14
+ colors: {
15
+ primary: { 100: "#E0F2FE", 500: "#0EA5E9", 600: "#0284C7" },
16
+ secondary: { 100: "#EDE9FE", 500: "#A855F7", 600: "#9333EA" },
17
+ success: { 100: "#DCFCE7", 500: "#22C55E", 600: "#16A34A" },
18
+ warning: { 100: "#FEF3C7", 500: "#F59E0B", 600: "#D97706" },
19
+ neutral: { 0: "#FFFFFF", 100: "#F3F4F6", 200: "#E5E7EB", 600: "#4B5563", 700: "#374151", 800: "#1F2937" }
20
+ },
21
+ shadows: {
22
+ sm: "0 1px 3px 0 rgba(0, 0, 0, 0.1)",
23
+ md: "0 4px 6px -1px rgba(0, 0, 0, 0.1)",
24
+ lg: "0 10px 15px -3px rgba(0, 0, 0, 0.1)",
25
+ xl: "0 20px 25px -5px rgba(0, 0, 0, 0.1)"
26
+ },
27
+ transitions: {
28
+ normal: "300ms cubic-bezier(0.4, 0, 0.2, 1)",
29
+ slow: "500ms cubic-bezier(0.4, 0, 0.2, 1)"
30
+ },
31
+ spacing: { xl: "32px", "2xl": "48px" },
32
+ borderRadius: { lg: "12px", xl: "16px" }
33
+ };
34
+ const fadeIn = styled.keyframes`
35
+ from { opacity: 0; transform: translateY(20px); }
36
+ to { opacity: 1; transform: translateY(0); }
37
+ `;
38
+ const slideIn = styled.keyframes`
39
+ from { opacity: 0; transform: translateX(-20px); }
40
+ to { opacity: 1; transform: translateX(0); }
41
+ `;
42
+ const shimmer = styled.keyframes`
43
+ 0% { background-position: -200% 0; }
44
+ 100% { background-position: 200% 0; }
45
+ `;
46
+ const float = styled.keyframes`
47
+ 0%, 100% { transform: translateY(0px); }
48
+ 50% { transform: translateY(-8px); }
49
+ `;
50
+ const pulse = styled.keyframes`
51
+ 0%, 100% { opacity: 1; }
52
+ 50% { opacity: 0.8; }
53
+ `;
54
+ const growBar = styled.keyframes`
55
+ from { width: 0; }
56
+ to { width: var(--bar-width); }
57
+ `;
58
+ const Container = styled__default.default(designSystem.Box)`
59
+ animation: ${fadeIn} 0.6s;
60
+ min-height: 100vh;
61
+ max-width: 1440px;
62
+ margin: 0 auto;
63
+ padding: ${theme.spacing.xl} 24px 0;
64
+ `;
65
+ const Header = styled__default.default(designSystem.Box)`
66
+ background: linear-gradient(135deg, ${theme.colors.primary[600]} 0%, ${theme.colors.secondary[600]} 100%);
67
+ border-radius: ${theme.borderRadius.xl};
68
+ padding: ${theme.spacing.xl} ${theme.spacing["2xl"]};
69
+ margin-bottom: ${theme.spacing.xl};
70
+ position: relative;
71
+ overflow: hidden;
72
+ box-shadow: ${theme.shadows.xl};
73
+
74
+ &::before {
75
+ content: '';
76
+ position: absolute;
77
+ top: 0;
78
+ left: -100%;
79
+ width: 200%;
80
+ height: 100%;
81
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.15), transparent);
82
+ animation: ${shimmer} 3s infinite;
83
+ }
84
+
85
+ &::after {
86
+ content: '';
87
+ position: absolute;
88
+ top: 0;
89
+ right: 0;
90
+ width: 100%;
91
+ height: 100%;
92
+ background-image: radial-gradient(circle at 20% 80%, transparent 50%, rgba(255, 255, 255, 0.1) 50%);
93
+ background-size: 15px 15px;
94
+ opacity: 0.3;
95
+ }
96
+ `;
97
+ const HeaderContent = styled__default.default(designSystem.Flex)`
98
+ position: relative;
99
+ z-index: 1;
100
+ `;
101
+ const Title = styled__default.default(designSystem.Typography)`
102
+ color: ${theme.colors.neutral[0]};
103
+ font-size: 2.25rem;
104
+ font-weight: 700;
105
+ letter-spacing: -0.025em;
106
+ text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
107
+ display: flex;
108
+ align-items: center;
109
+ gap: 16px;
110
+ margin-bottom: 8px;
111
+
112
+ svg {
113
+ width: 32px;
114
+ height: 32px;
115
+ animation: ${float} 3s ease-in-out infinite;
116
+ }
117
+ `;
118
+ const Subtitle = styled__default.default(designSystem.Typography)`
119
+ color: rgba(255, 255, 255, 0.95);
120
+ font-size: 1rem;
121
+ font-weight: 400;
122
+ letter-spacing: 0.01em;
123
+ `;
124
+ const StatsGrid = styled__default.default.div`
125
+ display: grid;
126
+ grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
127
+ gap: 24px;
128
+ margin-bottom: 40px;
129
+ `;
130
+ const StatCard = styled__default.default(designSystem.Box)`
131
+ background: ${theme.colors.neutral[0]};
132
+ border-radius: ${theme.borderRadius.lg};
133
+ padding: 32px;
134
+ position: relative;
135
+ overflow: hidden;
136
+ transition: all ${theme.transitions.normal};
137
+ animation: ${fadeIn} ${theme.transitions.slow} backwards;
138
+ animation-delay: ${(props) => props.$delay || "0s"};
139
+ box-shadow: ${theme.shadows.sm};
140
+ border: 1px solid ${theme.colors.neutral[200]};
141
+ text-align: center;
142
+ display: flex;
143
+ flex-direction: column;
144
+ align-items: center;
145
+ justify-content: center;
146
+
147
+ &:hover {
148
+ transform: translateY(-6px);
149
+ box-shadow: ${theme.shadows.xl};
150
+ border-color: ${(props) => props.$borderColor || theme.colors.primary[500]};
151
+
152
+ .stat-icon {
153
+ transform: scale(1.15) rotate(5deg);
154
+ }
155
+
156
+ .stat-value {
157
+ transform: scale(1.08);
158
+ color: ${(props) => props.$accentColor || theme.colors.primary[600]};
159
+ }
160
+ }
161
+ `;
162
+ const StatIcon = styled__default.default(designSystem.Box)`
163
+ width: 80px;
164
+ height: 80px;
165
+ border-radius: ${theme.borderRadius.lg};
166
+ display: flex;
167
+ align-items: center;
168
+ justify-content: center;
169
+ background: ${(props) => props.$bg || theme.colors.primary[100]};
170
+ transition: all ${theme.transitions.normal};
171
+ margin: 0 auto 24px;
172
+ box-shadow: ${theme.shadows.sm};
173
+
174
+ svg {
175
+ width: 40px;
176
+ height: 40px;
177
+ color: ${(props) => props.$color || theme.colors.primary[600]};
178
+ }
179
+ `;
180
+ const StatValue = styled__default.default(designSystem.Typography)`
181
+ font-size: 3.5rem;
182
+ font-weight: 700;
183
+ color: ${theme.colors.neutral[800]};
184
+ line-height: 1;
185
+ margin-bottom: 12px;
186
+ transition: all ${theme.transitions.normal};
187
+ text-align: center;
188
+ `;
189
+ const StatLabel = styled__default.default(designSystem.Typography)`
190
+ font-size: 1rem;
191
+ color: ${theme.colors.neutral[600]};
192
+ font-weight: 500;
193
+ text-align: center;
194
+ `;
195
+ const ChartCard = styled__default.default(designSystem.Box)`
196
+ background: ${theme.colors.neutral[0]};
197
+ border-radius: ${theme.borderRadius.lg};
198
+ padding: 36px;
199
+ box-shadow: ${theme.shadows.md};
200
+ border: 1px solid ${theme.colors.neutral[200]};
201
+ margin-bottom: 28px;
202
+ animation: ${slideIn} ${theme.transitions.slow};
203
+ transition: all ${theme.transitions.normal};
204
+
205
+ &:hover {
206
+ box-shadow: ${theme.shadows.lg};
207
+ border-color: ${theme.colors.primary[200]};
208
+ }
209
+ `;
210
+ const ChartTitle = styled__default.default(designSystem.Typography)`
211
+ font-size: 1.25rem;
212
+ font-weight: 700;
213
+ color: ${theme.colors.neutral[800]};
214
+ margin-bottom: 24px;
215
+ display: flex;
216
+ align-items: center;
217
+ gap: 12px;
218
+
219
+ svg {
220
+ width: 24px;
221
+ height: 24px;
222
+ color: ${theme.colors.primary[600]};
223
+ }
224
+ `;
225
+ const BarChart = styled__default.default.div`
226
+ display: flex;
227
+ flex-direction: column;
228
+ gap: 20px;
229
+ `;
230
+ const BarRow = styled__default.default.div`
231
+ display: flex;
232
+ align-items: center;
233
+ gap: 20px;
234
+ animation: ${fadeIn} 0.6s backwards;
235
+ animation-delay: ${(props) => props.$delay || "0s"};
236
+ `;
237
+ const BarLabel = styled__default.default(designSystem.Typography)`
238
+ min-width: 110px;
239
+ font-size: 15px;
240
+ font-weight: 600;
241
+ color: ${theme.colors.neutral[700]};
242
+ `;
243
+ const BarContainer = styled__default.default.div`
244
+ flex: 1;
245
+ height: 40px;
246
+ background: ${theme.colors.neutral[100]};
247
+ border-radius: 10px;
248
+ overflow: hidden;
249
+ position: relative;
250
+ box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.06);
251
+ `;
252
+ const BarFill = styled__default.default.div`
253
+ height: 100%;
254
+ background: linear-gradient(90deg, ${(props) => props.$color1 || theme.colors.primary[500]}, ${(props) => props.$color2 || theme.colors.primary[600]});
255
+ border-radius: 10px;
256
+ --bar-width: ${(props) => props.$percentage || 0}%;
257
+ animation: ${growBar} 1s cubic-bezier(0.4, 0, 0.2, 1) forwards;
258
+ animation-delay: ${(props) => props.$delay || "0s"};
259
+ display: flex;
260
+ align-items: center;
261
+ justify-content: flex-end;
262
+ padding-right: 16px;
263
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
264
+ `;
265
+ const BarValue = styled__default.default(designSystem.Typography)`
266
+ color: white;
267
+ font-size: 15px;
268
+ font-weight: 700;
269
+ text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
270
+ `;
271
+ const LoadingOverlay = styled__default.default.div`
272
+ display: flex;
273
+ flex-direction: column;
274
+ align-items: center;
275
+ justify-content: center;
276
+ min-height: 400px;
277
+ gap: 24px;
278
+
279
+ .loader-icon {
280
+ animation: ${pulse} 2s ease-in-out infinite;
281
+ }
282
+ `;
283
+ const AnalyticsPage = () => {
284
+ const { get } = admin.useFetchClient();
285
+ const { isPremium, loading: licenseLoading } = useLicense.useLicense();
286
+ const [loading, setLoading] = react.useState(true);
287
+ const [analytics, setAnalytics] = react.useState(null);
288
+ react.useEffect(() => {
289
+ if (!licenseLoading) {
290
+ fetchAnalytics();
291
+ }
292
+ }, [licenseLoading]);
293
+ const fetchAnalytics = async () => {
294
+ setLoading(true);
295
+ try {
296
+ const { data } = await get(`/${index.pluginId}/sessions`);
297
+ const sessions = data.data || [];
298
+ const now = Date.now();
299
+ const dayAgo = now - 24 * 60 * 60 * 1e3;
300
+ const weekAgo = now - 7 * 24 * 60 * 60 * 1e3;
301
+ const todayLogins = sessions.filter((s) => new Date(s.loginTime).getTime() > dayAgo);
302
+ const weekLogins = sessions.filter((s) => new Date(s.loginTime).getTime() > weekAgo);
303
+ const devices = {};
304
+ const browsers = {};
305
+ const operatingSystems = {};
306
+ const countries = {};
307
+ const loginHours = Array(24).fill(0);
308
+ const uniqueUsers = /* @__PURE__ */ new Set();
309
+ const uniqueIPs = /* @__PURE__ */ new Set();
310
+ sessions.forEach((session) => {
311
+ const ua = session.userAgent.toLowerCase();
312
+ if (ua.includes("mobile") || ua.includes("android") || ua.includes("iphone")) {
313
+ devices["Mobile"] = (devices["Mobile"] || 0) + 1;
314
+ } else if (ua.includes("tablet") || ua.includes("ipad")) {
315
+ devices["Tablet"] = (devices["Tablet"] || 0) + 1;
316
+ } else {
317
+ devices["Desktop"] = (devices["Desktop"] || 0) + 1;
318
+ }
319
+ if (ua.includes("chrome") && !ua.includes("edg")) browsers["Chrome"] = (browsers["Chrome"] || 0) + 1;
320
+ else if (ua.includes("firefox")) browsers["Firefox"] = (browsers["Firefox"] || 0) + 1;
321
+ else if (ua.includes("safari") && !ua.includes("chrome")) browsers["Safari"] = (browsers["Safari"] || 0) + 1;
322
+ else if (ua.includes("edg")) browsers["Edge"] = (browsers["Edge"] || 0) + 1;
323
+ else if (ua.includes("postman") || ua.includes("curl")) browsers["API Client"] = (browsers["API Client"] || 0) + 1;
324
+ else browsers["Other"] = (browsers["Other"] || 0) + 1;
325
+ if (ua.includes("windows") || ua.includes("win32") || ua.includes("win64")) {
326
+ operatingSystems["Windows"] = (operatingSystems["Windows"] || 0) + 1;
327
+ } else if (ua.includes("mac") || ua.includes("darwin")) {
328
+ operatingSystems["macOS"] = (operatingSystems["macOS"] || 0) + 1;
329
+ } else if (ua.includes("linux")) {
330
+ operatingSystems["Linux"] = (operatingSystems["Linux"] || 0) + 1;
331
+ } else if (ua.includes("android")) {
332
+ operatingSystems["Android"] = (operatingSystems["Android"] || 0) + 1;
333
+ } else if (ua.includes("ios") || ua.includes("iphone") || ua.includes("ipad")) {
334
+ operatingSystems["iOS"] = (operatingSystems["iOS"] || 0) + 1;
335
+ } else {
336
+ operatingSystems["Other"] = (operatingSystems["Other"] || 0) + 1;
337
+ }
338
+ const loginHour = new Date(session.loginTime).getHours();
339
+ loginHours[loginHour]++;
340
+ if (session.user?.id) uniqueUsers.add(session.user.id);
341
+ if (session.ipAddress) uniqueIPs.add(session.ipAddress);
342
+ });
343
+ const peakHour = loginHours.indexOf(Math.max(...loginHours));
344
+ const loggedOut = sessions.filter((s) => !s.isActive && s.logoutTime).length;
345
+ const terminated = sessions.filter((s) => !s.isActive && !s.logoutTime).length;
346
+ const mobileCount = (devices["Mobile"] || 0) + (devices["Tablet"] || 0);
347
+ const desktopCount = devices["Desktop"] || 0;
348
+ const mobileRatio = sessions.length > 0 ? Math.round(mobileCount / sessions.length * 100) : 0;
349
+ setAnalytics({
350
+ totalSessions: sessions.length,
351
+ activeSessions: sessions.filter((s) => s.isActive && s.isTrulyActive).length,
352
+ todayLogins: todayLogins.length,
353
+ weekLogins: weekLogins.length,
354
+ devices,
355
+ browsers,
356
+ operatingSystems,
357
+ loginHours,
358
+ peakHour,
359
+ uniqueUsers: uniqueUsers.size,
360
+ uniqueIPs: uniqueIPs.size,
361
+ loggedOut,
362
+ terminated,
363
+ mobileRatio,
364
+ avgSessionDuration: sessions.length > 0 ? Math.floor(sessions.reduce((sum, s) => sum + (s.minutesSinceActive || 0), 0) / sessions.length) : 0
365
+ });
366
+ } catch (err) {
367
+ console.error("[Analytics] Error:", err);
368
+ } finally {
369
+ setLoading(false);
370
+ }
371
+ };
372
+ if (licenseLoading) {
373
+ return /* @__PURE__ */ jsxRuntime.jsx(Container, { children: /* @__PURE__ */ jsxRuntime.jsxs(LoadingOverlay, { children: [
374
+ /* @__PURE__ */ jsxRuntime.jsx(icons.ChartBubble, { className: "loader-icon", style: { width: "64px", height: "64px", color: theme.colors.primary[600] } }),
375
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Loader, { children: "Checking license..." }),
376
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: "Please wait while we verify your premium access" })
377
+ ] }) });
378
+ }
379
+ if (!isPremium) {
380
+ return /* @__PURE__ */ jsxRuntime.jsx(Container, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 8, children: /* @__PURE__ */ jsxRuntime.jsxs(
381
+ designSystem.Box,
382
+ {
383
+ padding: 10,
384
+ style: {
385
+ background: "linear-gradient(135deg, #fef3c7 0%, #fed7aa 100%)",
386
+ borderRadius: "20px",
387
+ border: "3px solid #fbbf24",
388
+ textAlign: "center",
389
+ boxShadow: "0 20px 40px rgba(245, 158, 11, 0.2)",
390
+ maxWidth: "800px",
391
+ margin: "60px auto",
392
+ position: "relative",
393
+ overflow: "hidden"
394
+ },
395
+ children: [
396
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
397
+ position: "absolute",
398
+ top: 0,
399
+ left: 0,
400
+ right: 0,
401
+ bottom: 0,
402
+ backgroundImage: "radial-gradient(circle at 20% 80%, transparent 50%, rgba(255, 255, 255, 0.1) 50%)",
403
+ backgroundSize: "20px 20px",
404
+ opacity: 0.5,
405
+ zIndex: 0
406
+ } }),
407
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative", zIndex: 1 }, children: [
408
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Crown, { style: {
409
+ width: "96px",
410
+ height: "96px",
411
+ color: "#d97706",
412
+ margin: "0 auto 32px",
413
+ display: "block",
414
+ animation: `${float} 3s ease-in-out infinite`
415
+ } }),
416
+ /* @__PURE__ */ jsxRuntime.jsx(
417
+ designSystem.Typography,
418
+ {
419
+ variant: "alpha",
420
+ style: {
421
+ color: "#92400e",
422
+ fontWeight: "700",
423
+ marginBottom: "24px",
424
+ fontSize: "36px",
425
+ display: "block",
426
+ textShadow: "0 2px 4px rgba(0, 0, 0, 0.1)"
427
+ },
428
+ children: "📊 Analytics Dashboard"
429
+ }
430
+ ),
431
+ /* @__PURE__ */ jsxRuntime.jsx(
432
+ designSystem.Typography,
433
+ {
434
+ variant: "omega",
435
+ style: {
436
+ color: "#78350f",
437
+ lineHeight: "1.9",
438
+ marginBottom: "44px",
439
+ fontSize: "17px",
440
+ display: "block",
441
+ maxWidth: "620px",
442
+ margin: "0 auto 44px"
443
+ },
444
+ children: "Unlock premium analytics to get powerful insights about your user sessions, device statistics, browser trends, and activity patterns"
445
+ }
446
+ ),
447
+ /* @__PURE__ */ jsxRuntime.jsx(
448
+ "button",
449
+ {
450
+ onClick: () => window.open("https://magicapi.fitlex.me", "_blank"),
451
+ style: {
452
+ background: "linear-gradient(135deg, #f59e0b 0%, #d97706 100%)",
453
+ color: "white",
454
+ border: "none",
455
+ padding: "16px 48px",
456
+ borderRadius: "12px",
457
+ fontSize: "17px",
458
+ fontWeight: "700",
459
+ cursor: "pointer",
460
+ boxShadow: "0 6px 16px rgba(245, 158, 11, 0.4)",
461
+ transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)"
462
+ },
463
+ onMouseEnter: (e) => {
464
+ e.currentTarget.style.transform = "translateY(-3px) scale(1.05)";
465
+ e.currentTarget.style.boxShadow = "0 12px 24px rgba(245, 158, 11, 0.5)";
466
+ },
467
+ onMouseLeave: (e) => {
468
+ e.currentTarget.style.transform = "translateY(0) scale(1)";
469
+ e.currentTarget.style.boxShadow = "0 6px 16px rgba(245, 158, 11, 0.4)";
470
+ },
471
+ children: "✨ Upgrade to Premium"
472
+ }
473
+ )
474
+ ] })
475
+ ]
476
+ }
477
+ ) }) });
478
+ }
479
+ if (loading) {
480
+ return /* @__PURE__ */ jsxRuntime.jsx(Container, { children: /* @__PURE__ */ jsxRuntime.jsxs(LoadingOverlay, { children: [
481
+ /* @__PURE__ */ jsxRuntime.jsx(icons.ChartBubble, { className: "loader-icon", style: { width: "64px", height: "64px", color: theme.colors.primary[600] } }),
482
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Loader, { children: "Loading analytics data..." })
483
+ ] }) });
484
+ }
485
+ const maxDevices = Math.max(...Object.values(analytics?.devices || {}), 1);
486
+ const maxBrowsers = Math.max(...Object.values(analytics?.browsers || {}), 1);
487
+ Math.max(...Object.values(analytics?.operatingSystems || {}), 1);
488
+ Math.max(...analytics?.loginHours || [], 1);
489
+ const deviceColors = {
490
+ "Desktop": [theme.colors.primary[500], theme.colors.primary[600]],
491
+ "Mobile": [theme.colors.success[500], theme.colors.success[600]],
492
+ "Tablet": [theme.colors.warning[500], theme.colors.warning[600]]
493
+ };
494
+ const browserColors = {
495
+ "Chrome": [theme.colors.success[500], theme.colors.success[600]],
496
+ "Firefox": [theme.colors.warning[500], theme.colors.warning[600]],
497
+ "Safari": [theme.colors.primary[500], theme.colors.primary[600]],
498
+ "Edge": [theme.colors.secondary[500], theme.colors.secondary[600]],
499
+ "API Client": [theme.colors.neutral[600], theme.colors.neutral[700]],
500
+ "Other": [theme.colors.neutral[500], theme.colors.neutral[600]]
501
+ };
502
+ return /* @__PURE__ */ jsxRuntime.jsxs(Container, { children: [
503
+ /* @__PURE__ */ jsxRuntime.jsx(Header, { children: /* @__PURE__ */ jsxRuntime.jsxs(HeaderContent, { direction: "column", alignItems: "flex-start", gap: 2, children: [
504
+ /* @__PURE__ */ jsxRuntime.jsxs(Title, { children: [
505
+ /* @__PURE__ */ jsxRuntime.jsx(icons.ChartBubble, {}),
506
+ " Session Analytics"
507
+ ] }),
508
+ /* @__PURE__ */ jsxRuntime.jsx(Subtitle, { children: "Comprehensive insights and statistics about user sessions" })
509
+ ] }) }),
510
+ /* @__PURE__ */ jsxRuntime.jsxs(StatsGrid, { children: [
511
+ /* @__PURE__ */ jsxRuntime.jsxs(StatCard, { $delay: "0.1s", $borderColor: theme.colors.primary[500], $accentColor: theme.colors.primary[600], children: [
512
+ /* @__PURE__ */ jsxRuntime.jsx(StatIcon, { className: "stat-icon", $bg: theme.colors.primary[100], $color: theme.colors.primary[600], children: /* @__PURE__ */ jsxRuntime.jsx(icons.ChartBubble, {}) }),
513
+ /* @__PURE__ */ jsxRuntime.jsx(StatValue, { className: "stat-value", children: analytics?.totalSessions || 0 }),
514
+ /* @__PURE__ */ jsxRuntime.jsx(StatLabel, { children: "Total Sessions" })
515
+ ] }),
516
+ /* @__PURE__ */ jsxRuntime.jsxs(StatCard, { $delay: "0.2s", $borderColor: theme.colors.success[500], $accentColor: theme.colors.success[600], children: [
517
+ /* @__PURE__ */ jsxRuntime.jsx(StatIcon, { className: "stat-icon", $bg: theme.colors.success[100], $color: theme.colors.success[600], children: /* @__PURE__ */ jsxRuntime.jsx(icons.User, {}) }),
518
+ /* @__PURE__ */ jsxRuntime.jsx(StatValue, { className: "stat-value", children: analytics?.activeSessions || 0 }),
519
+ /* @__PURE__ */ jsxRuntime.jsx(StatLabel, { children: "Active Now" })
520
+ ] }),
521
+ /* @__PURE__ */ jsxRuntime.jsxs(StatCard, { $delay: "0.3s", $borderColor: theme.colors.warning[500], $accentColor: theme.colors.warning[600], children: [
522
+ /* @__PURE__ */ jsxRuntime.jsx(StatIcon, { className: "stat-icon", $bg: theme.colors.warning[100], $color: theme.colors.warning[600], children: /* @__PURE__ */ jsxRuntime.jsx(icons.Clock, {}) }),
523
+ /* @__PURE__ */ jsxRuntime.jsx(StatValue, { className: "stat-value", children: analytics?.todayLogins || 0 }),
524
+ /* @__PURE__ */ jsxRuntime.jsx(StatLabel, { children: "Today's Logins" })
525
+ ] }),
526
+ /* @__PURE__ */ jsxRuntime.jsxs(StatCard, { $delay: "0.4s", $borderColor: theme.colors.secondary[500], $accentColor: theme.colors.secondary[600], children: [
527
+ /* @__PURE__ */ jsxRuntime.jsx(StatIcon, { className: "stat-icon", $bg: theme.colors.secondary[100], $color: theme.colors.secondary[600], children: /* @__PURE__ */ jsxRuntime.jsx(icons.Clock, {}) }),
528
+ /* @__PURE__ */ jsxRuntime.jsx(StatValue, { className: "stat-value", children: analytics?.weekLogins || 0 }),
529
+ /* @__PURE__ */ jsxRuntime.jsx(StatLabel, { children: "This Week" })
530
+ ] })
531
+ ] }),
532
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 4, wrap: "wrap", style: { marginBottom: "28px" }, children: [
533
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: 1, minWidth: "450px" }, children: /* @__PURE__ */ jsxRuntime.jsxs(ChartCard, { children: [
534
+ /* @__PURE__ */ jsxRuntime.jsxs(ChartTitle, { children: [
535
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Monitor, {}),
536
+ "Device Distribution"
537
+ ] }),
538
+ /* @__PURE__ */ jsxRuntime.jsx(BarChart, { children: analytics?.devices && Object.entries(analytics.devices).sort(([, a], [, b]) => b - a).map(([device, count], idx) => /* @__PURE__ */ jsxRuntime.jsxs(BarRow, { $delay: `${0.5 + idx * 0.1}s`, children: [
539
+ /* @__PURE__ */ jsxRuntime.jsx(BarLabel, { children: device }),
540
+ /* @__PURE__ */ jsxRuntime.jsx(BarContainer, { children: /* @__PURE__ */ jsxRuntime.jsx(
541
+ BarFill,
542
+ {
543
+ $percentage: count / maxDevices * 100,
544
+ $color1: deviceColors[device]?.[0] || theme.colors.neutral[500],
545
+ $color2: deviceColors[device]?.[1] || theme.colors.neutral[600],
546
+ $delay: `${0.5 + idx * 0.1}s`,
547
+ children: /* @__PURE__ */ jsxRuntime.jsx(BarValue, { children: count })
548
+ }
549
+ ) })
550
+ ] }, device)) })
551
+ ] }) }),
552
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { flex: 1, minWidth: "450px" }, children: /* @__PURE__ */ jsxRuntime.jsxs(ChartCard, { children: [
553
+ /* @__PURE__ */ jsxRuntime.jsxs(ChartTitle, { children: [
554
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Monitor, {}),
555
+ "Browser Usage"
556
+ ] }),
557
+ /* @__PURE__ */ jsxRuntime.jsx(BarChart, { children: analytics?.browsers && Object.entries(analytics.browsers).sort(([, a], [, b]) => b - a).map(([browser, count], idx) => /* @__PURE__ */ jsxRuntime.jsxs(BarRow, { $delay: `${0.5 + idx * 0.1}s`, children: [
558
+ /* @__PURE__ */ jsxRuntime.jsx(BarLabel, { children: browser }),
559
+ /* @__PURE__ */ jsxRuntime.jsx(BarContainer, { children: /* @__PURE__ */ jsxRuntime.jsx(
560
+ BarFill,
561
+ {
562
+ $percentage: count / maxBrowsers * 100,
563
+ $color1: browserColors[browser]?.[0] || theme.colors.neutral[500],
564
+ $color2: browserColors[browser]?.[1] || theme.colors.neutral[600],
565
+ $delay: `${0.5 + idx * 0.1}s`,
566
+ children: /* @__PURE__ */ jsxRuntime.jsx(BarValue, { children: count })
567
+ }
568
+ ) })
569
+ ] }, browser)) })
570
+ ] }) })
571
+ ] }),
572
+ /* @__PURE__ */ jsxRuntime.jsxs(ChartCard, { children: [
573
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "center", justifyContent: "space-between", children: [
574
+ /* @__PURE__ */ jsxRuntime.jsxs(ChartTitle, { style: { marginBottom: 0 }, children: [
575
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Clock, {}),
576
+ "Average Session Duration"
577
+ ] }),
578
+ /* @__PURE__ */ jsxRuntime.jsxs(
579
+ designSystem.Badge,
580
+ {
581
+ backgroundColor: "primary600",
582
+ textColor: "neutral0",
583
+ style: {
584
+ fontSize: "18px",
585
+ fontWeight: "700",
586
+ padding: "12px 24px",
587
+ boxShadow: theme.shadows.md
588
+ },
589
+ children: [
590
+ analytics?.avgSessionDuration || 0,
591
+ " minutes"
592
+ ]
593
+ }
594
+ )
595
+ ] }),
596
+ analytics?.avgSessionDuration > 0 && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 5, padding: 5, background: "primary50", hasRadius: true, style: { border: `1px solid ${theme.colors.primary[100]}` }, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", textColor: "primary700", style: { fontSize: "14px", lineHeight: "1.8", fontWeight: "500" }, children: "ℹ️ Average time between login and last activity across all sessions. Lower values indicate more frequent activity, higher values may indicate idle or abandoned sessions." }) })
597
+ ] })
598
+ ] });
599
+ };
600
+ exports.default = AnalyticsPage;