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,1953 @@
1
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
+ import { useState, useEffect } from "react";
3
+ import { useFetchClient, useNotification } from "@strapi/strapi/admin";
4
+ import styled, { keyframes } from "styled-components";
5
+ import { Modal, Flex, Box, Typography, Badge, Divider, Button, Loader, SingleSelect, SingleSelectOption, Thead, Tr, Th, Tbody, Td, Table, TextInput } from "@strapi/design-system";
6
+ import { Check, Information, Monitor, Server, Clock, Cross, Earth, Shield, Crown, Phone, Download, User, Eye, Trash, Search, Key } from "@strapi/icons";
7
+ import { p as parseUserAgent, a as pluginId } from "./index-BGCs2pNv.mjs";
8
+ import { u as useLicense } from "./useLicense-Dw_-SJHP.mjs";
9
+ import { useNavigate } from "react-router-dom";
10
+ const TwoColumnGrid = styled.div`
11
+ display: grid;
12
+ grid-template-columns: 1fr 1fr;
13
+ gap: 24px;
14
+
15
+ @media (max-width: 768px) {
16
+ grid-template-columns: 1fr;
17
+ }
18
+ `;
19
+ const SectionTitle = styled(Typography)`
20
+ text-transform: uppercase;
21
+ letter-spacing: 0.5px;
22
+ font-size: 11px;
23
+ font-weight: 700;
24
+ color: #374151;
25
+ margin-bottom: 16px;
26
+ padding-bottom: 8px;
27
+ border-bottom: 2px solid #e5e7eb;
28
+ display: block;
29
+ `;
30
+ const Section = styled(Box)`
31
+ margin-bottom: 24px;
32
+ `;
33
+ const SessionDetailModal = ({ session, onClose, onSessionTerminated }) => {
34
+ const { get, post } = useFetchClient();
35
+ const { toggleNotification } = useNotification();
36
+ const { isPremium } = useLicense();
37
+ const [terminating, setTerminating] = useState(false);
38
+ const [showUserAgent, setShowUserAgent] = useState(false);
39
+ const [geoData, setGeoData] = useState(null);
40
+ const [geoLoading, setGeoLoading] = useState(false);
41
+ if (!session) return null;
42
+ const deviceInfo = parseUserAgent(session.userAgent);
43
+ const isOnline = session.isTrulyActive;
44
+ useEffect(() => {
45
+ if (isPremium && session.ipAddress && !geoData) {
46
+ fetchGeolocationData();
47
+ }
48
+ }, [isPremium, session.ipAddress]);
49
+ const fetchGeolocationData = async () => {
50
+ setGeoLoading(true);
51
+ try {
52
+ const { data } = await get(`/${pluginId}/geolocation/${session.ipAddress}`);
53
+ setGeoData(data.data);
54
+ } catch (err) {
55
+ console.error("[SessionDetailModal] Error fetching geolocation:", err);
56
+ setGeoData({
57
+ country_flag: "🌍",
58
+ country: "Unknown",
59
+ city: "Unknown",
60
+ timezone: "Unknown",
61
+ securityScore: 50,
62
+ riskLevel: "Unknown",
63
+ isVpn: false,
64
+ isProxy: false
65
+ });
66
+ } finally {
67
+ setGeoLoading(false);
68
+ }
69
+ };
70
+ const premiumData = geoData || {
71
+ country_flag: "🌍",
72
+ country: "Loading...",
73
+ city: "Loading...",
74
+ timezone: "Loading...",
75
+ securityScore: 0,
76
+ riskLevel: "Unknown",
77
+ isVpn: false,
78
+ isProxy: false
79
+ };
80
+ const getDeviceIcon = (deviceType) => {
81
+ if (deviceType === "Mobile" || deviceType === "Tablet") return Phone;
82
+ if (deviceType === "Desktop" || deviceType === "Laptop") return Monitor;
83
+ return Server;
84
+ };
85
+ const DeviceIcon = getDeviceIcon(deviceInfo.device);
86
+ const handleTerminate = async () => {
87
+ if (!confirm("Are you sure you want to terminate this session?")) {
88
+ return;
89
+ }
90
+ setTerminating(true);
91
+ try {
92
+ await post(`/${pluginId}/sessions/${session.id}/terminate`);
93
+ toggleNotification({
94
+ type: "success",
95
+ message: "Session terminated successfully"
96
+ });
97
+ onSessionTerminated();
98
+ onClose();
99
+ } catch (err) {
100
+ console.error("[SessionDetailModal] Error:", err);
101
+ toggleNotification({
102
+ type: "danger",
103
+ message: "Failed to terminate session"
104
+ });
105
+ } finally {
106
+ setTerminating(false);
107
+ }
108
+ };
109
+ const DetailRow = ({ label, value, icon: Icon, compact }) => /* @__PURE__ */ jsxs(Flex, { gap: 3, alignItems: "flex-start", style: { marginBottom: compact ? "12px" : "16px" }, children: [
110
+ Icon && /* @__PURE__ */ jsx(Box, { style: {
111
+ width: "36px",
112
+ height: "36px",
113
+ display: "flex",
114
+ alignItems: "center",
115
+ justifyContent: "center",
116
+ background: "#f3f4f6",
117
+ borderRadius: "8px",
118
+ flexShrink: 0
119
+ }, children: /* @__PURE__ */ jsx(Icon, { width: "18px", height: "18px" }) }),
120
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", style: { flex: 1, minWidth: 0 }, children: [
121
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "11px", fontWeight: "600", marginBottom: "4px" }, children: label }),
122
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", textColor: "neutral800", style: { fontSize: "14px", fontWeight: "500" }, children: value })
123
+ ] })
124
+ ] });
125
+ return /* @__PURE__ */ jsx(Modal.Root, { open: true, onOpenChange: onClose, children: /* @__PURE__ */ jsxs(Modal.Content, { style: { maxWidth: "900px" }, children: [
126
+ /* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsxs(Flex, { gap: 3, alignItems: "center", children: [
127
+ /* @__PURE__ */ jsx(Box, { style: {
128
+ width: "48px",
129
+ height: "48px",
130
+ borderRadius: "12px",
131
+ background: isOnline ? "#dcfce7" : "#f3f4f6",
132
+ display: "flex",
133
+ alignItems: "center",
134
+ justifyContent: "center"
135
+ }, children: /* @__PURE__ */ jsx(DeviceIcon, { width: "24px", height: "24px" }) }),
136
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", children: [
137
+ /* @__PURE__ */ jsx(Typography, { variant: "beta", fontWeight: "bold", children: "Session Details" }),
138
+ /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", children: [
139
+ "ID: ",
140
+ session.id
141
+ ] })
142
+ ] })
143
+ ] }) }),
144
+ /* @__PURE__ */ jsx(Modal.Body, { children: /* @__PURE__ */ jsxs(Box, { padding: 6, children: [
145
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "center", style: { marginBottom: "24px" }, children: /* @__PURE__ */ jsx(
146
+ Badge,
147
+ {
148
+ backgroundColor: isOnline ? "success600" : "neutral600",
149
+ textColor: "neutral0",
150
+ size: "M",
151
+ style: { fontSize: "14px", padding: "8px 20px", fontWeight: "600" },
152
+ children: isOnline ? "🟢 ONLINE" : "⚫ OFFLINE"
153
+ }
154
+ ) }),
155
+ /* @__PURE__ */ jsx(Divider, { style: { marginBottom: "24px" } }),
156
+ /* @__PURE__ */ jsxs(TwoColumnGrid, { children: [
157
+ /* @__PURE__ */ jsxs(Box, { children: [
158
+ /* @__PURE__ */ jsxs(Section, { children: [
159
+ /* @__PURE__ */ jsx(SectionTitle, { children: "👤 User" }),
160
+ /* @__PURE__ */ jsx(DetailRow, { compact: true, icon: Check, label: "Username", value: session.user?.username || "N/A" }),
161
+ /* @__PURE__ */ jsx(DetailRow, { compact: true, icon: Information, label: "Email", value: session.user?.email || "N/A" }),
162
+ /* @__PURE__ */ jsx(DetailRow, { compact: true, icon: Information, label: "User ID", value: session.user?.id || "N/A" })
163
+ ] }),
164
+ /* @__PURE__ */ jsxs(Section, { children: [
165
+ /* @__PURE__ */ jsx(SectionTitle, { children: "💻 Device" }),
166
+ /* @__PURE__ */ jsx(DetailRow, { compact: true, icon: DeviceIcon, label: "Device", value: deviceInfo.device }),
167
+ /* @__PURE__ */ jsx(DetailRow, { compact: true, icon: Monitor, label: "Browser", value: `${deviceInfo.browser} ${deviceInfo.browserVersion || ""}` }),
168
+ /* @__PURE__ */ jsx(DetailRow, { compact: true, icon: Server, label: "OS", value: deviceInfo.os }),
169
+ /* @__PURE__ */ jsx(DetailRow, { compact: true, icon: Information, label: "IP", value: session.ipAddress })
170
+ ] })
171
+ ] }),
172
+ /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Section, { children: [
173
+ /* @__PURE__ */ jsx(SectionTitle, { children: "⏱️ Timeline" }),
174
+ /* @__PURE__ */ jsx(
175
+ DetailRow,
176
+ {
177
+ compact: true,
178
+ icon: Clock,
179
+ label: "Login",
180
+ value: new Date(session.loginTime).toLocaleString("de-DE", {
181
+ day: "2-digit",
182
+ month: "short",
183
+ hour: "2-digit",
184
+ minute: "2-digit"
185
+ })
186
+ }
187
+ ),
188
+ /* @__PURE__ */ jsx(
189
+ DetailRow,
190
+ {
191
+ compact: true,
192
+ icon: Clock,
193
+ label: "Last Active",
194
+ value: new Date(session.lastActive || session.loginTime).toLocaleString("de-DE", {
195
+ day: "2-digit",
196
+ month: "short",
197
+ hour: "2-digit",
198
+ minute: "2-digit"
199
+ })
200
+ }
201
+ ),
202
+ /* @__PURE__ */ jsx(
203
+ DetailRow,
204
+ {
205
+ compact: true,
206
+ icon: Clock,
207
+ label: "Idle Time",
208
+ value: `${session.minutesSinceActive} min`
209
+ }
210
+ ),
211
+ session.logoutTime && /* @__PURE__ */ jsx(
212
+ DetailRow,
213
+ {
214
+ compact: true,
215
+ icon: Cross,
216
+ label: "Logout",
217
+ value: new Date(session.logoutTime).toLocaleString("de-DE", {
218
+ day: "2-digit",
219
+ month: "short",
220
+ hour: "2-digit",
221
+ minute: "2-digit"
222
+ })
223
+ }
224
+ )
225
+ ] }) })
226
+ ] }),
227
+ isPremium ? /* @__PURE__ */ jsxs(Section, { children: [
228
+ /* @__PURE__ */ jsx(SectionTitle, { children: "🌍 Location & Security" }),
229
+ geoLoading ? /* @__PURE__ */ jsx(Box, { padding: 4, style: { textAlign: "center" }, children: /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: "Loading location data..." }) }) : /* @__PURE__ */ jsxs(TwoColumnGrid, { children: [
230
+ /* @__PURE__ */ jsxs(Box, { children: [
231
+ /* @__PURE__ */ jsx(
232
+ DetailRow,
233
+ {
234
+ compact: true,
235
+ icon: Earth,
236
+ label: "Country",
237
+ value: `${premiumData.country_flag || "🌍"} ${premiumData.country}`
238
+ }
239
+ ),
240
+ /* @__PURE__ */ jsx(DetailRow, { compact: true, icon: Earth, label: "City", value: premiumData.city }),
241
+ /* @__PURE__ */ jsx(DetailRow, { compact: true, icon: Clock, label: "Timezone", value: premiumData.timezone })
242
+ ] }),
243
+ /* @__PURE__ */ jsxs(Box, { children: [
244
+ /* @__PURE__ */ jsx(
245
+ DetailRow,
246
+ {
247
+ compact: true,
248
+ icon: Shield,
249
+ label: "Security",
250
+ value: `${premiumData.securityScore}/100 (${premiumData.riskLevel})`
251
+ }
252
+ ),
253
+ /* @__PURE__ */ jsx(
254
+ DetailRow,
255
+ {
256
+ compact: true,
257
+ icon: Shield,
258
+ label: "VPN",
259
+ value: premiumData.isVpn ? "⚠️ Yes" : "✅ No"
260
+ }
261
+ ),
262
+ /* @__PURE__ */ jsx(
263
+ DetailRow,
264
+ {
265
+ compact: true,
266
+ icon: Shield,
267
+ label: "Proxy",
268
+ value: premiumData.isProxy ? "⚠️ Yes" : "✅ No"
269
+ }
270
+ )
271
+ ] })
272
+ ] })
273
+ ] }) : /* @__PURE__ */ jsx(Section, { children: /* @__PURE__ */ jsx(
274
+ Box,
275
+ {
276
+ padding: 5,
277
+ style: {
278
+ background: "linear-gradient(135deg, #fef3c7 0%, #fed7aa 100%)",
279
+ borderRadius: "12px",
280
+ border: "2px solid #fbbf24",
281
+ textAlign: "center"
282
+ },
283
+ children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "center", gap: 3, children: [
284
+ /* @__PURE__ */ jsx(Crown, { style: { width: "40px", height: "40px", color: "#d97706" } }),
285
+ /* @__PURE__ */ jsx(Typography, { variant: "beta", style: { color: "#92400e", fontWeight: "700" }, children: "🌍 Location & Security Analysis" }),
286
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", style: { color: "#78350f", fontSize: "14px", lineHeight: "1.6" }, children: "Unlock premium features to get IP geolocation, security scoring, and VPN/Proxy detection for every session" }),
287
+ /* @__PURE__ */ jsx(
288
+ Button,
289
+ {
290
+ variant: "secondary",
291
+ size: "M",
292
+ onClick: () => window.open("https://magicapi.fitlex.me", "_blank"),
293
+ style: {
294
+ background: "linear-gradient(135deg, #f59e0b 0%, #d97706 100%)",
295
+ color: "white",
296
+ border: "none",
297
+ fontWeight: "600",
298
+ marginTop: "8px",
299
+ boxShadow: "0 4px 12px rgba(245, 158, 11, 0.3)"
300
+ },
301
+ children: "Upgrade to Premium"
302
+ }
303
+ )
304
+ ] })
305
+ }
306
+ ) }),
307
+ /* @__PURE__ */ jsxs(Section, { children: [
308
+ /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", style: { marginBottom: "12px" }, children: [
309
+ /* @__PURE__ */ jsx(SectionTitle, { style: { marginBottom: 0, paddingBottom: 0, border: "none" }, children: "🔧 Technical Details" }),
310
+ /* @__PURE__ */ jsx(
311
+ Button,
312
+ {
313
+ variant: "tertiary",
314
+ size: "S",
315
+ onClick: () => setShowUserAgent(!showUserAgent),
316
+ style: { fontSize: "12px" },
317
+ children: showUserAgent ? "▲ Hide Details" : "▼ Show Details"
318
+ }
319
+ )
320
+ ] }),
321
+ showUserAgent && /* @__PURE__ */ jsx(
322
+ Box,
323
+ {
324
+ padding: 3,
325
+ background: "neutral100",
326
+ hasRadius: true,
327
+ style: {
328
+ fontFamily: "monospace",
329
+ fontSize: "10px",
330
+ wordBreak: "break-all",
331
+ maxHeight: "80px",
332
+ overflow: "auto",
333
+ marginTop: "8px",
334
+ animation: "fadeIn 0.3s ease-in-out"
335
+ },
336
+ children: /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { lineHeight: "1.6" }, children: session.userAgent })
337
+ }
338
+ )
339
+ ] })
340
+ ] }) }),
341
+ /* @__PURE__ */ jsx(Modal.Footer, { children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", style: { width: "100%" }, children: [
342
+ /* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: "Close" }),
343
+ /* @__PURE__ */ jsx(
344
+ Button,
345
+ {
346
+ onClick: handleTerminate,
347
+ variant: "danger",
348
+ disabled: !session.isActive || terminating,
349
+ loading: terminating,
350
+ startIcon: /* @__PURE__ */ jsx(Cross, {}),
351
+ children: "Terminate Session"
352
+ }
353
+ )
354
+ ] }) })
355
+ ] }) });
356
+ };
357
+ const theme = {
358
+ colors: {
359
+ primary: {
360
+ 50: "#F0F9FF",
361
+ 100: "#E0F2FE",
362
+ 500: "#0EA5E9",
363
+ 600: "#0284C7"
364
+ },
365
+ secondary: {
366
+ 500: "#A855F7",
367
+ 600: "#9333EA"
368
+ },
369
+ success: {
370
+ 100: "#DCFCE7",
371
+ 500: "#22C55E",
372
+ 600: "#16A34A"
373
+ },
374
+ warning: {
375
+ 100: "#FEF3C7",
376
+ 500: "#F59E0B",
377
+ 600: "#D97706"
378
+ },
379
+ danger: {
380
+ 100: "#FEE2E2",
381
+ 500: "#EF4444",
382
+ 600: "#DC2626"
383
+ },
384
+ neutral: {
385
+ 0: "#FFFFFF",
386
+ 50: "#F9FAFB",
387
+ 100: "#F3F4F6",
388
+ 200: "#E5E7EB",
389
+ 600: "#4B5563",
390
+ 700: "#374151",
391
+ 800: "#1F2937"
392
+ }
393
+ },
394
+ shadows: {
395
+ sm: "0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1)",
396
+ xl: "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)"
397
+ },
398
+ transitions: {
399
+ fast: "150ms cubic-bezier(0.4, 0, 0.2, 1)",
400
+ normal: "300ms cubic-bezier(0.4, 0, 0.2, 1)",
401
+ slow: "500ms cubic-bezier(0.4, 0, 0.2, 1)"
402
+ },
403
+ spacing: {
404
+ xs: "4px",
405
+ sm: "8px",
406
+ md: "16px",
407
+ lg: "24px",
408
+ xl: "32px",
409
+ "2xl": "48px"
410
+ },
411
+ borderRadius: {
412
+ md: "8px",
413
+ lg: "12px",
414
+ xl: "16px"
415
+ }
416
+ };
417
+ const fadeIn$1 = keyframes`
418
+ from { opacity: 0; transform: translateY(10px); }
419
+ to { opacity: 1; transform: translateY(0); }
420
+ `;
421
+ const shimmer = keyframes`
422
+ 0% { background-position: -200% 0; }
423
+ 100% { background-position: 200% 0; }
424
+ `;
425
+ const float = keyframes`
426
+ 0%, 100% { transform: translateY(0px); }
427
+ 50% { transform: translateY(-5px); }
428
+ `;
429
+ const pulse = keyframes`
430
+ 0%, 100% { opacity: 1; }
431
+ 50% { opacity: 0.5; }
432
+ `;
433
+ const FloatingEmoji = styled.div`
434
+ position: absolute;
435
+ bottom: 40px;
436
+ right: 40px;
437
+ font-size: 72px;
438
+ opacity: 0.08;
439
+ animation: ${float} 4s ease-in-out infinite;
440
+ `;
441
+ const breakpoints = {
442
+ mobile: "768px"
443
+ };
444
+ const Container = styled(Box)`
445
+ animation: ${fadeIn$1} ${theme.transitions.slow};
446
+ min-height: 100vh;
447
+ max-width: 1440px;
448
+ margin: 0 auto;
449
+ padding: ${theme.spacing.xl} ${theme.spacing.lg} 0;
450
+
451
+ @media screen and (max-width: ${breakpoints.mobile}) {
452
+ padding: 16px 12px 0;
453
+ }
454
+ `;
455
+ const Header = styled(Box)`
456
+ background: linear-gradient(135deg,
457
+ ${theme.colors.primary[600]} 0%,
458
+ ${theme.colors.secondary[600]} 100%
459
+ );
460
+ border-radius: ${theme.borderRadius.xl};
461
+ padding: ${theme.spacing.xl} ${theme.spacing["2xl"]};
462
+ margin-bottom: ${theme.spacing.xl};
463
+ position: relative;
464
+ overflow: hidden;
465
+ box-shadow: ${theme.shadows.xl};
466
+
467
+ @media screen and (max-width: ${breakpoints.mobile}) {
468
+ padding: 24px 20px;
469
+ border-radius: 12px;
470
+ }
471
+
472
+ &::before {
473
+ content: '';
474
+ position: absolute;
475
+ top: 0;
476
+ left: -100%;
477
+ width: 200%;
478
+ height: 100%;
479
+ background: linear-gradient(
480
+ 90deg,
481
+ transparent,
482
+ rgba(255, 255, 255, 0.15),
483
+ transparent
484
+ );
485
+ animation: ${shimmer} 3s infinite;
486
+ }
487
+
488
+ &::after {
489
+ content: '';
490
+ position: absolute;
491
+ top: 0;
492
+ right: 0;
493
+ width: 100%;
494
+ height: 100%;
495
+ background-image: radial-gradient(circle at 20% 80%, transparent 50%, rgba(255, 255, 255, 0.1) 50%);
496
+ background-size: 15px 15px;
497
+ opacity: 0.3;
498
+ }
499
+ `;
500
+ const HeaderContent = styled(Flex)`
501
+ position: relative;
502
+ z-index: 1;
503
+ `;
504
+ const Title = styled(Typography)`
505
+ color: ${theme.colors.neutral[0]};
506
+ font-size: 2rem;
507
+ font-weight: 700;
508
+ letter-spacing: -0.025em;
509
+ text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
510
+ display: flex;
511
+ align-items: center;
512
+ gap: ${theme.spacing.sm};
513
+
514
+ svg {
515
+ width: 28px;
516
+ height: 28px;
517
+ animation: ${float} 3s ease-in-out infinite;
518
+ }
519
+
520
+ @media screen and (max-width: ${breakpoints.mobile}) {
521
+ font-size: 1.5rem;
522
+
523
+ svg {
524
+ width: 22px;
525
+ height: 22px;
526
+ }
527
+ }
528
+ `;
529
+ const Subtitle = styled(Typography)`
530
+ color: rgba(255, 255, 255, 0.95);
531
+ font-size: 0.95rem;
532
+ font-weight: 400;
533
+ margin-top: ${theme.spacing.xs};
534
+ letter-spacing: 0.01em;
535
+
536
+ @media screen and (max-width: ${breakpoints.mobile}) {
537
+ font-size: 0.85rem;
538
+ }
539
+ `;
540
+ const StatsGrid = styled.div`
541
+ margin-bottom: ${theme.spacing.xl};
542
+ display: grid;
543
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
544
+ gap: ${theme.spacing.lg};
545
+ justify-content: center;
546
+ max-width: 1200px;
547
+ margin-left: auto;
548
+ margin-right: auto;
549
+
550
+ @media screen and (max-width: ${breakpoints.mobile}) {
551
+ grid-template-columns: repeat(2, 1fr);
552
+ gap: 12px;
553
+ margin-bottom: 24px;
554
+ }
555
+ `;
556
+ const StatCard = styled(Box)`
557
+ background: ${theme.colors.neutral[0]};
558
+ border-radius: ${theme.borderRadius.lg};
559
+ padding: 28px ${theme.spacing.lg};
560
+ position: relative;
561
+ overflow: hidden;
562
+ transition: all ${theme.transitions.normal};
563
+ animation: ${fadeIn$1} ${theme.transitions.slow} backwards;
564
+ animation-delay: ${(props) => props.$delay || "0s"};
565
+ box-shadow: ${theme.shadows.sm};
566
+ border: 1px solid ${theme.colors.neutral[200]};
567
+ min-width: 200px;
568
+ flex: 1;
569
+ text-align: center;
570
+ display: flex;
571
+ flex-direction: column;
572
+ align-items: center;
573
+ justify-content: center;
574
+
575
+ @media screen and (max-width: ${breakpoints.mobile}) {
576
+ min-width: unset;
577
+ padding: 20px 12px;
578
+
579
+ &:hover {
580
+ transform: none;
581
+ }
582
+ }
583
+
584
+ &:hover {
585
+ transform: translateY(-6px);
586
+ box-shadow: ${theme.shadows.xl};
587
+ border-color: ${(props) => props.$color || theme.colors.primary[500]};
588
+
589
+ .stat-icon {
590
+ transform: scale(1.15) rotate(5deg);
591
+ }
592
+
593
+ .stat-value {
594
+ transform: scale(1.08);
595
+ color: ${(props) => props.$color || theme.colors.primary[600]};
596
+ }
597
+ }
598
+ `;
599
+ const StatIcon = styled(Box)`
600
+ width: 68px;
601
+ height: 68px;
602
+ border-radius: ${theme.borderRadius.lg};
603
+ display: flex;
604
+ align-items: center;
605
+ justify-content: center;
606
+ background: ${(props) => props.$bg || theme.colors.primary[100]};
607
+ transition: all ${theme.transitions.normal};
608
+ margin: 0 auto 20px;
609
+ box-shadow: ${theme.shadows.sm};
610
+
611
+ svg {
612
+ width: 34px;
613
+ height: 34px;
614
+ color: ${(props) => props.$color || theme.colors.primary[600]};
615
+ }
616
+
617
+ @media screen and (max-width: ${breakpoints.mobile}) {
618
+ width: 48px;
619
+ height: 48px;
620
+ margin-bottom: 12px;
621
+
622
+ svg {
623
+ width: 24px;
624
+ height: 24px;
625
+ }
626
+ }
627
+ `;
628
+ const StatValue = styled(Typography)`
629
+ font-size: 2.75rem;
630
+ font-weight: 700;
631
+ color: ${theme.colors.neutral[800]};
632
+ line-height: 1;
633
+ margin-bottom: 10px;
634
+ transition: all ${theme.transitions.normal};
635
+ text-align: center;
636
+
637
+ @media screen and (max-width: ${breakpoints.mobile}) {
638
+ font-size: 2rem;
639
+ margin-bottom: 6px;
640
+ }
641
+ `;
642
+ const StatLabel = styled(Typography)`
643
+ font-size: 0.95rem;
644
+ color: ${theme.colors.neutral[600]};
645
+ font-weight: 500;
646
+ letter-spacing: 0.025em;
647
+ text-align: center;
648
+
649
+ @media screen and (max-width: ${breakpoints.mobile}) {
650
+ font-size: 0.8rem;
651
+ }
652
+ `;
653
+ const DataTable = styled(Box)`
654
+ background: ${theme.colors.neutral[0]};
655
+ border-radius: ${theme.borderRadius.lg};
656
+ overflow: hidden;
657
+ box-shadow: ${theme.shadows.sm};
658
+ border: 1px solid ${theme.colors.neutral[200]};
659
+ margin-bottom: ${theme.spacing.xl};
660
+ `;
661
+ const StyledTable = styled(Table)`
662
+ thead {
663
+ background: ${theme.colors.neutral[50]};
664
+ border-bottom: 2px solid ${theme.colors.neutral[200]};
665
+
666
+ th {
667
+ font-weight: 600;
668
+ color: ${theme.colors.neutral[700]};
669
+ font-size: 0.875rem;
670
+ text-transform: uppercase;
671
+ letter-spacing: 0.025em;
672
+ padding: ${theme.spacing.lg} ${theme.spacing.lg};
673
+ }
674
+ }
675
+
676
+ tbody tr {
677
+ transition: all ${theme.transitions.fast};
678
+ border-bottom: 1px solid ${theme.colors.neutral[100]};
679
+
680
+ &:last-child {
681
+ border-bottom: none;
682
+ }
683
+
684
+ &:hover {
685
+ background: ${theme.colors.neutral[50]};
686
+
687
+ .action-buttons {
688
+ opacity: 1;
689
+ }
690
+ }
691
+
692
+ td {
693
+ padding: ${theme.spacing.lg} ${theme.spacing.lg};
694
+ color: ${theme.colors.neutral[700]};
695
+ vertical-align: middle;
696
+ }
697
+ }
698
+ `;
699
+ const OnlineIndicator = styled.div`
700
+ width: 10px;
701
+ height: 10px;
702
+ border-radius: 50%;
703
+ background: ${(props) => props.$online ? theme.colors.success[500] : theme.colors.neutral[400]};
704
+ display: inline-block;
705
+ margin-right: 8px;
706
+ animation: ${(props) => props.$online ? pulse : "none"} 2s ease-in-out infinite;
707
+ `;
708
+ const FilterBar = styled(Flex)`
709
+ background: ${theme.colors.neutral[0]};
710
+ padding: ${theme.spacing.md} ${theme.spacing.lg};
711
+ border-radius: ${theme.borderRadius.lg};
712
+ margin-bottom: ${theme.spacing.lg};
713
+ box-shadow: ${theme.shadows.sm};
714
+ border: 1px solid ${theme.colors.neutral[200]};
715
+ gap: ${theme.spacing.md};
716
+ align-items: center;
717
+ `;
718
+ const SearchInputWrapper = styled.div`
719
+ position: relative;
720
+ flex: 1;
721
+ display: flex;
722
+ align-items: center;
723
+ `;
724
+ const SearchIcon = styled(Search)`
725
+ position: absolute;
726
+ left: 12px;
727
+ width: 16px;
728
+ height: 16px;
729
+ color: ${theme.colors.neutral[600]};
730
+ pointer-events: none;
731
+ `;
732
+ const StyledSearchInput = styled.input`
733
+ width: 100%;
734
+ padding: ${theme.spacing.sm} ${theme.spacing.sm} ${theme.spacing.sm} 36px;
735
+ border: 1px solid ${theme.colors.neutral[200]};
736
+ border-radius: ${theme.borderRadius.md};
737
+ font-size: 0.875rem;
738
+ transition: all ${theme.transitions.fast};
739
+ background: ${theme.colors.neutral[0]};
740
+ color: ${theme.colors.neutral[800]};
741
+
742
+ &:focus {
743
+ outline: none;
744
+ border-color: ${theme.colors.primary[500]};
745
+ box-shadow: 0 0 0 3px ${theme.colors.primary[100]};
746
+ }
747
+
748
+ &::placeholder {
749
+ color: ${theme.colors.neutral[600]};
750
+ }
751
+ `;
752
+ const ActionButtons = styled(Flex)`
753
+ opacity: 0.7;
754
+ transition: all ${theme.transitions.fast};
755
+ gap: ${theme.spacing.xs};
756
+ justify-content: flex-end;
757
+ `;
758
+ const ClickableRow = styled(Tr)`
759
+ cursor: pointer;
760
+
761
+ &:hover {
762
+ background: ${theme.colors.primary[50]} !important;
763
+ }
764
+ `;
765
+ const HomePage = () => {
766
+ const { get, post, del } = useFetchClient();
767
+ const { toggleNotification } = useNotification();
768
+ const { isPremium } = useLicense();
769
+ const [sessions, setSessions] = useState([]);
770
+ const [loading, setLoading] = useState(true);
771
+ const [filterStatus, setFilterStatus] = useState("active");
772
+ const [entriesPerPage, setEntriesPerPage] = useState("25");
773
+ const [searchQuery, setSearchQuery] = useState("");
774
+ const [selectedSession, setSelectedSession] = useState(null);
775
+ const [showDetailModal, setShowDetailModal] = useState(false);
776
+ useEffect(() => {
777
+ fetchSessions();
778
+ const interval = setInterval(() => {
779
+ if (!showDetailModal) {
780
+ fetchSessions();
781
+ }
782
+ }, 10 * 60 * 1e3);
783
+ return () => clearInterval(interval);
784
+ }, [showDetailModal]);
785
+ const fetchSessions = async () => {
786
+ setLoading(true);
787
+ try {
788
+ const { data } = await get(`/${pluginId}/sessions`);
789
+ setSessions(data.data || []);
790
+ } catch (err) {
791
+ console.error("[SessionManager] Error fetching sessions:", err);
792
+ } finally {
793
+ setLoading(false);
794
+ }
795
+ };
796
+ const handleTerminateSession = async (sessionId) => {
797
+ if (!confirm("Are you sure you want to terminate this session?\n\nThis will set isActive to false (user will be logged out).")) {
798
+ return;
799
+ }
800
+ try {
801
+ await post(`/${pluginId}/sessions/${sessionId}/terminate`);
802
+ fetchSessions();
803
+ } catch (err) {
804
+ console.error("[SessionManager] Error terminating session:", err);
805
+ }
806
+ };
807
+ const handleDeleteSession = async (sessionId) => {
808
+ if (!confirm("⚠️ WARNING: This will PERMANENTLY delete this session from the database!\n\nThis action cannot be undone.\n\nAre you sure?")) {
809
+ return;
810
+ }
811
+ try {
812
+ await del(`/${pluginId}/sessions/${sessionId}`);
813
+ fetchSessions();
814
+ toggleNotification({
815
+ type: "success",
816
+ message: "Session permanently deleted"
817
+ });
818
+ } catch (err) {
819
+ console.error("[SessionManager] Error deleting session:", err);
820
+ toggleNotification({
821
+ type: "danger",
822
+ message: "Failed to delete session"
823
+ });
824
+ }
825
+ };
826
+ const handleExportCSV = () => {
827
+ if (!isPremium) {
828
+ toggleNotification({
829
+ type: "warning",
830
+ message: "Premium license required for export functionality"
831
+ });
832
+ return;
833
+ }
834
+ try {
835
+ const headers = ["ID", "Status", "User Email", "Username", "Device", "Browser", "OS", "IP Address", "Login Time", "Last Active", "Logout Time", "Minutes Idle"];
836
+ const rows = filteredSessions.map((session) => {
837
+ const deviceInfo = parseUserAgent(session.userAgent);
838
+ const status = getSessionStatus(session);
839
+ return [
840
+ session.id,
841
+ status,
842
+ session.user?.email || "",
843
+ session.user?.username || "",
844
+ deviceInfo.device,
845
+ deviceInfo.browser,
846
+ deviceInfo.os,
847
+ session.ipAddress,
848
+ new Date(session.loginTime).toISOString(),
849
+ new Date(session.lastActive || session.loginTime).toISOString(),
850
+ session.logoutTime ? new Date(session.logoutTime).toISOString() : "",
851
+ session.minutesSinceActive
852
+ ];
853
+ });
854
+ const csvContent = [
855
+ headers.join(","),
856
+ ...rows.map((row) => row.map((cell) => `"${cell}"`).join(","))
857
+ ].join("\n");
858
+ const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
859
+ const link = document.createElement("a");
860
+ link.href = URL.createObjectURL(blob);
861
+ link.download = `sessions-export-${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}.csv`;
862
+ link.click();
863
+ toggleNotification({
864
+ type: "success",
865
+ message: `Exported ${filteredSessions.length} sessions to CSV`
866
+ });
867
+ } catch (err) {
868
+ console.error("[SessionManager] Export error:", err);
869
+ toggleNotification({
870
+ type: "danger",
871
+ message: "Failed to export sessions"
872
+ });
873
+ }
874
+ };
875
+ const handleExportJSON = () => {
876
+ if (!isPremium) {
877
+ toggleNotification({
878
+ type: "warning",
879
+ message: "Premium license required for export functionality"
880
+ });
881
+ return;
882
+ }
883
+ try {
884
+ const exportData = {
885
+ exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
886
+ filter: filterStatus,
887
+ totalSessions: sessions.length,
888
+ exportedSessions: filteredSessions.length,
889
+ sessions: filteredSessions.map((session) => {
890
+ const deviceInfo = parseUserAgent(session.userAgent);
891
+ return {
892
+ id: session.id,
893
+ status: getSessionStatus(session),
894
+ user: {
895
+ id: session.user?.id,
896
+ email: session.user?.email,
897
+ username: session.user?.username
898
+ },
899
+ device: {
900
+ type: deviceInfo.device,
901
+ browser: deviceInfo.browser,
902
+ browserVersion: deviceInfo.browserVersion,
903
+ os: deviceInfo.os
904
+ },
905
+ ipAddress: session.ipAddress,
906
+ loginTime: session.loginTime,
907
+ lastActive: session.lastActive,
908
+ logoutTime: session.logoutTime,
909
+ minutesSinceActive: session.minutesSinceActive,
910
+ isActive: session.isActive,
911
+ isTrulyActive: session.isTrulyActive
912
+ };
913
+ })
914
+ };
915
+ const blob = new Blob([JSON.stringify(exportData, null, 2)], { type: "application/json" });
916
+ const link = document.createElement("a");
917
+ link.href = URL.createObjectURL(blob);
918
+ link.download = `sessions-export-${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}.json`;
919
+ link.click();
920
+ toggleNotification({
921
+ type: "success",
922
+ message: `Exported ${filteredSessions.length} sessions to JSON`
923
+ });
924
+ } catch (err) {
925
+ console.error("[SessionManager] Export error:", err);
926
+ toggleNotification({
927
+ type: "danger",
928
+ message: "Failed to export sessions"
929
+ });
930
+ }
931
+ };
932
+ const getDeviceIcon = (deviceType) => {
933
+ if (deviceType === "Mobile" || deviceType === "Tablet") return Phone;
934
+ if (deviceType === "Desktop" || deviceType === "Laptop") return Monitor;
935
+ return Server;
936
+ };
937
+ const activeSessions = sessions.filter((s) => s.isActive && s.isTrulyActive);
938
+ const idleSessions = sessions.filter((s) => s.isActive && !s.isTrulyActive);
939
+ const loggedOutSessions = sessions.filter((s) => !s.isActive && s.logoutTime);
940
+ const terminatedSessions = sessions.filter((s) => !s.isActive && !s.logoutTime);
941
+ const handleSessionClick = (session) => {
942
+ setSelectedSession(session);
943
+ setShowDetailModal(true);
944
+ };
945
+ const handleModalClose = () => {
946
+ setShowDetailModal(false);
947
+ setSelectedSession(null);
948
+ };
949
+ const handleSessionTerminated = () => {
950
+ fetchSessions();
951
+ };
952
+ const getSessionStatus = (session) => {
953
+ if (!session.isActive) {
954
+ return session.logoutTime ? "loggedout" : "terminated";
955
+ }
956
+ return session.isTrulyActive ? "active" : "idle";
957
+ };
958
+ const filteredSessions = sessions.filter((session) => {
959
+ const sessionStatus = getSessionStatus(session);
960
+ if (filterStatus === "active" && sessionStatus !== "active") return false;
961
+ if (filterStatus === "idle" && sessionStatus !== "idle") return false;
962
+ if (filterStatus === "loggedout" && sessionStatus !== "loggedout") return false;
963
+ if (filterStatus === "terminated" && sessionStatus !== "terminated") return false;
964
+ if (searchQuery) {
965
+ const query = searchQuery.toLowerCase();
966
+ const matchesUser = session.user?.email?.toLowerCase().includes(query) || session.user?.username?.toLowerCase().includes(query);
967
+ const matchesIp = session.ipAddress?.toLowerCase().includes(query);
968
+ const deviceInfo = parseUserAgent(session.userAgent);
969
+ const matchesDevice = deviceInfo.device?.toLowerCase().includes(query) || deviceInfo.browser?.toLowerCase().includes(query) || deviceInfo.os?.toLowerCase().includes(query);
970
+ return matchesUser || matchesIp || matchesDevice;
971
+ }
972
+ return true;
973
+ }).slice(0, parseInt(entriesPerPage));
974
+ return /* @__PURE__ */ jsxs(Container, { padding: 8, children: [
975
+ /* @__PURE__ */ jsx(Header, { children: /* @__PURE__ */ jsxs(HeaderContent, { justifyContent: "space-between", alignItems: "center", children: [
976
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", gap: 2, children: [
977
+ /* @__PURE__ */ jsxs(Title, { children: [
978
+ /* @__PURE__ */ jsx(Monitor, {}),
979
+ " Session Manager"
980
+ ] }),
981
+ /* @__PURE__ */ jsx(Subtitle, { children: "Monitor and manage user sessions in real-time" })
982
+ ] }),
983
+ isPremium && filteredSessions.length > 0 && /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
984
+ /* @__PURE__ */ jsx(
985
+ Button,
986
+ {
987
+ onClick: handleExportCSV,
988
+ startIcon: /* @__PURE__ */ jsx(Download, {}),
989
+ size: "M",
990
+ variant: "secondary",
991
+ style: {
992
+ backgroundColor: "rgba(255,255,255,0.2)",
993
+ color: "white",
994
+ border: "1px solid rgba(255,255,255,0.3)",
995
+ fontWeight: "600"
996
+ },
997
+ children: "Export CSV"
998
+ }
999
+ ),
1000
+ /* @__PURE__ */ jsx(
1001
+ Button,
1002
+ {
1003
+ onClick: handleExportJSON,
1004
+ startIcon: /* @__PURE__ */ jsx(Download, {}),
1005
+ size: "M",
1006
+ variant: "secondary",
1007
+ style: {
1008
+ backgroundColor: "rgba(255,255,255,0.2)",
1009
+ color: "white",
1010
+ border: "1px solid rgba(255,255,255,0.3)",
1011
+ fontWeight: "600"
1012
+ },
1013
+ children: "Export JSON"
1014
+ }
1015
+ )
1016
+ ] })
1017
+ ] }) }),
1018
+ /* @__PURE__ */ jsxs(StatsGrid, { children: [
1019
+ /* @__PURE__ */ jsxs(StatCard, { $delay: "0.1s", $color: theme.colors.success[500], children: [
1020
+ /* @__PURE__ */ jsx(StatIcon, { className: "stat-icon", $bg: theme.colors.success[100], $color: theme.colors.success[600], children: /* @__PURE__ */ jsx(Check, {}) }),
1021
+ /* @__PURE__ */ jsx(StatValue, { className: "stat-value", children: activeSessions.length }),
1022
+ /* @__PURE__ */ jsx(StatLabel, { children: "Active" })
1023
+ ] }),
1024
+ /* @__PURE__ */ jsxs(StatCard, { $delay: "0.2s", $color: theme.colors.warning[500], children: [
1025
+ /* @__PURE__ */ jsx(StatIcon, { className: "stat-icon", $bg: theme.colors.warning[100], $color: theme.colors.warning[600], children: /* @__PURE__ */ jsx(Clock, {}) }),
1026
+ /* @__PURE__ */ jsx(StatValue, { className: "stat-value", children: idleSessions.length }),
1027
+ /* @__PURE__ */ jsx(StatLabel, { children: "Idle" })
1028
+ ] }),
1029
+ /* @__PURE__ */ jsxs(StatCard, { $delay: "0.3s", $color: theme.colors.danger[500], children: [
1030
+ /* @__PURE__ */ jsx(StatIcon, { className: "stat-icon", $bg: theme.colors.danger[100], $color: theme.colors.danger[600], children: /* @__PURE__ */ jsx(Cross, {}) }),
1031
+ /* @__PURE__ */ jsx(StatValue, { className: "stat-value", children: loggedOutSessions.length }),
1032
+ /* @__PURE__ */ jsx(StatLabel, { children: "Logged Out" })
1033
+ ] }),
1034
+ /* @__PURE__ */ jsxs(StatCard, { $delay: "0.4s", $color: theme.colors.neutral[600], children: [
1035
+ /* @__PURE__ */ jsx(StatIcon, { className: "stat-icon", $bg: theme.colors.neutral[100], $color: theme.colors.neutral[600], children: /* @__PURE__ */ jsx(Cross, {}) }),
1036
+ /* @__PURE__ */ jsx(StatValue, { className: "stat-value", children: terminatedSessions.length }),
1037
+ /* @__PURE__ */ jsx(StatLabel, { children: "Terminated" })
1038
+ ] }),
1039
+ /* @__PURE__ */ jsxs(StatCard, { $delay: "0.5s", $color: theme.colors.secondary[500], children: [
1040
+ /* @__PURE__ */ jsx(StatIcon, { className: "stat-icon", $bg: theme.colors.secondary[100], $color: theme.colors.secondary[600], children: /* @__PURE__ */ jsx(User, {}) }),
1041
+ /* @__PURE__ */ jsx(StatValue, { className: "stat-value", children: sessions.length }),
1042
+ /* @__PURE__ */ jsx(StatLabel, { children: "Total" })
1043
+ ] })
1044
+ ] }),
1045
+ loading && /* @__PURE__ */ jsx(Flex, { justifyContent: "center", padding: 8, children: /* @__PURE__ */ jsx(Loader, { children: "Loading sessions..." }) }),
1046
+ !loading && sessions.length > 0 && /* @__PURE__ */ jsxs(Box, { children: [
1047
+ /* @__PURE__ */ jsx(Box, { style: { marginBottom: theme.spacing.md }, children: /* @__PURE__ */ jsx(Typography, { variant: "delta", style: { marginBottom: theme.spacing.md, color: theme.colors.neutral[700] }, children: "📊 All Sessions" }) }),
1048
+ /* @__PURE__ */ jsxs(FilterBar, { children: [
1049
+ /* @__PURE__ */ jsxs(SearchInputWrapper, { children: [
1050
+ /* @__PURE__ */ jsx(SearchIcon, {}),
1051
+ /* @__PURE__ */ jsx(
1052
+ StyledSearchInput,
1053
+ {
1054
+ value: searchQuery,
1055
+ onChange: (e) => setSearchQuery(e.target.value),
1056
+ placeholder: "Search by user, IP address, or device...",
1057
+ type: "text"
1058
+ }
1059
+ )
1060
+ ] }),
1061
+ /* @__PURE__ */ jsx(Box, { style: { minWidth: "180px" }, children: /* @__PURE__ */ jsxs(
1062
+ SingleSelect,
1063
+ {
1064
+ value: filterStatus,
1065
+ onChange: setFilterStatus,
1066
+ placeholder: "Filter",
1067
+ size: "S",
1068
+ children: [
1069
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "all", children: "All Sessions" }),
1070
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "active", children: "🟢 Active (< 15 min)" }),
1071
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "idle", children: "🟡 Idle (> 15 min)" }),
1072
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "loggedout", children: "🔴 Logged Out" }),
1073
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "terminated", children: "⚫ Terminated" })
1074
+ ]
1075
+ }
1076
+ ) }),
1077
+ /* @__PURE__ */ jsx(Box, { style: { minWidth: "130px" }, children: /* @__PURE__ */ jsxs(
1078
+ SingleSelect,
1079
+ {
1080
+ value: entriesPerPage,
1081
+ onChange: setEntriesPerPage,
1082
+ placeholder: "Entries",
1083
+ size: "S",
1084
+ children: [
1085
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "10", children: "10 entries" }),
1086
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "25", children: "25 entries" }),
1087
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "50", children: "50 entries" }),
1088
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "100", children: "100 entries" })
1089
+ ]
1090
+ }
1091
+ ) })
1092
+ ] }),
1093
+ /* @__PURE__ */ jsx(Box, { style: { marginBottom: theme.spacing.md }, children: /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", children: [
1094
+ "Showing ",
1095
+ filteredSessions.length,
1096
+ " of ",
1097
+ sessions.length,
1098
+ " sessions",
1099
+ searchQuery && ` (filtered by "${searchQuery}")`
1100
+ ] }) }),
1101
+ filteredSessions.length > 0 ? /* @__PURE__ */ jsx(DataTable, { children: /* @__PURE__ */ jsxs(StyledTable, { children: [
1102
+ /* @__PURE__ */ jsx(Thead, { children: /* @__PURE__ */ jsxs(Tr, { children: [
1103
+ /* @__PURE__ */ jsx(Th, { children: "Status" }),
1104
+ /* @__PURE__ */ jsx(Th, { children: "User" }),
1105
+ /* @__PURE__ */ jsx(Th, { children: "Device" }),
1106
+ /* @__PURE__ */ jsx(Th, { children: "IP Address" }),
1107
+ /* @__PURE__ */ jsx(Th, { children: "Login Time" }),
1108
+ /* @__PURE__ */ jsx(Th, { children: "Last Active" }),
1109
+ /* @__PURE__ */ jsx(Th, { children: "Actions" })
1110
+ ] }) }),
1111
+ /* @__PURE__ */ jsx(Tbody, { children: filteredSessions.map((session) => {
1112
+ const deviceInfo = parseUserAgent(session.userAgent);
1113
+ const DeviceIcon = getDeviceIcon(deviceInfo.device);
1114
+ const sessionStatus = getSessionStatus(session);
1115
+ const statusConfig = {
1116
+ active: {
1117
+ bg: theme.colors.success[50],
1118
+ badgeColor: "success600",
1119
+ label: "🟢 Active",
1120
+ indicator: true
1121
+ },
1122
+ idle: {
1123
+ bg: theme.colors.warning[50],
1124
+ badgeColor: "warning600",
1125
+ label: "🟡 Idle",
1126
+ indicator: false
1127
+ },
1128
+ loggedout: {
1129
+ bg: theme.colors.danger[50],
1130
+ badgeColor: "danger600",
1131
+ label: "🔴 Logged Out",
1132
+ indicator: false,
1133
+ opacity: 0.7
1134
+ },
1135
+ terminated: {
1136
+ bg: theme.colors.neutral[100],
1137
+ badgeColor: "neutral600",
1138
+ label: "⚫ Terminated",
1139
+ indicator: false,
1140
+ opacity: 0.6
1141
+ }
1142
+ };
1143
+ const config = statusConfig[sessionStatus];
1144
+ return /* @__PURE__ */ jsxs(
1145
+ ClickableRow,
1146
+ {
1147
+ onClick: () => handleSessionClick(session),
1148
+ style: {
1149
+ background: config.bg,
1150
+ opacity: config.opacity || 1
1151
+ },
1152
+ children: [
1153
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 2, children: [
1154
+ /* @__PURE__ */ jsx(OnlineIndicator, { $online: config.indicator }),
1155
+ /* @__PURE__ */ jsx(
1156
+ Badge,
1157
+ {
1158
+ backgroundColor: config.badgeColor,
1159
+ textColor: "neutral0",
1160
+ size: "S",
1161
+ children: config.label
1162
+ }
1163
+ )
1164
+ ] }) }),
1165
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", children: [
1166
+ /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", ellipsis: true, children: session.user?.username || session.user?.email || "Unknown" }),
1167
+ session.user?.email && session.user?.username && /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", ellipsis: true, children: session.user.email })
1168
+ ] }) }),
1169
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 2, children: [
1170
+ /* @__PURE__ */ jsx(DeviceIcon, { width: "18px", height: "18px" }),
1171
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", children: [
1172
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "semiBold", children: deviceInfo.device }),
1173
+ /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", children: [
1174
+ deviceInfo.browser,
1175
+ " on ",
1176
+ deviceInfo.os
1177
+ ] })
1178
+ ] })
1179
+ ] }) }),
1180
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { variant: "omega", style: { fontFamily: "monospace" }, children: session.ipAddress }) }),
1181
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral700", children: new Date(session.loginTime).toLocaleString() }) }),
1182
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", children: [
1183
+ /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral700", children: new Date(session.lastActive || session.loginTime).toLocaleString() }),
1184
+ /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: sessionStatus === "active" ? "success600" : "neutral500", children: [
1185
+ session.minutesSinceActive,
1186
+ " min ago"
1187
+ ] })
1188
+ ] }) }),
1189
+ /* @__PURE__ */ jsx(Td, { onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsxs(ActionButtons, { className: "action-buttons", children: [
1190
+ /* @__PURE__ */ jsx(
1191
+ Button,
1192
+ {
1193
+ variant: "secondary",
1194
+ size: "S",
1195
+ onClick: (e) => {
1196
+ e.stopPropagation();
1197
+ handleSessionClick(session);
1198
+ },
1199
+ title: "View Details",
1200
+ children: /* @__PURE__ */ jsx(Eye, {})
1201
+ }
1202
+ ),
1203
+ /* @__PURE__ */ jsx(
1204
+ Button,
1205
+ {
1206
+ variant: "danger-light",
1207
+ size: "S",
1208
+ onClick: (e) => {
1209
+ e.stopPropagation();
1210
+ handleTerminateSession(session.id);
1211
+ },
1212
+ disabled: sessionStatus !== "active" && sessionStatus !== "idle",
1213
+ title: session.isActive ? "Terminate (Logout)" : "Already inactive",
1214
+ children: /* @__PURE__ */ jsx(Cross, {})
1215
+ }
1216
+ ),
1217
+ /* @__PURE__ */ jsx(
1218
+ Button,
1219
+ {
1220
+ variant: "danger",
1221
+ size: "S",
1222
+ onClick: (e) => {
1223
+ e.stopPropagation();
1224
+ handleDeleteSession(session.id);
1225
+ },
1226
+ title: "Delete Permanently",
1227
+ children: /* @__PURE__ */ jsx(Trash, {})
1228
+ }
1229
+ )
1230
+ ] }) })
1231
+ ]
1232
+ },
1233
+ session.id
1234
+ );
1235
+ }) })
1236
+ ] }) }) : (
1237
+ /* No results found */
1238
+ /* @__PURE__ */ jsxs(
1239
+ Box,
1240
+ {
1241
+ style: {
1242
+ background: theme.colors.neutral[0],
1243
+ borderRadius: theme.borderRadius.xl,
1244
+ border: `2px dashed ${theme.colors.neutral[200]}`,
1245
+ padding: "60px 32px",
1246
+ textAlign: "center",
1247
+ position: "relative",
1248
+ overflow: "hidden",
1249
+ minHeight: "300px",
1250
+ display: "flex",
1251
+ alignItems: "center",
1252
+ justifyContent: "center"
1253
+ },
1254
+ children: [
1255
+ /* @__PURE__ */ jsx(
1256
+ Box,
1257
+ {
1258
+ style: {
1259
+ position: "absolute",
1260
+ top: 0,
1261
+ left: 0,
1262
+ right: 0,
1263
+ bottom: 0,
1264
+ background: `linear-gradient(135deg, ${theme.colors.primary[50]} 0%, ${theme.colors.secondary[50]} 100%)`,
1265
+ opacity: 0.3,
1266
+ zIndex: 0
1267
+ }
1268
+ }
1269
+ ),
1270
+ /* @__PURE__ */ jsx(FloatingEmoji, { children: "🔍" }),
1271
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "center", gap: 4, style: { position: "relative", zIndex: 1 }, children: [
1272
+ /* @__PURE__ */ jsx(
1273
+ Box,
1274
+ {
1275
+ style: {
1276
+ width: "100px",
1277
+ height: "100px",
1278
+ borderRadius: "50%",
1279
+ background: `linear-gradient(135deg, ${theme.colors.primary[100]} 0%, ${theme.colors.secondary[100]} 100%)`,
1280
+ display: "flex",
1281
+ alignItems: "center",
1282
+ justifyContent: "center",
1283
+ boxShadow: theme.shadows.xl
1284
+ },
1285
+ children: /* @__PURE__ */ jsx(Search, { style: { width: "50px", height: "50px", color: theme.colors.primary[600] } })
1286
+ }
1287
+ ),
1288
+ /* @__PURE__ */ jsx(
1289
+ Typography,
1290
+ {
1291
+ variant: "alpha",
1292
+ style: {
1293
+ fontSize: "1.5rem",
1294
+ fontWeight: "700",
1295
+ color: theme.colors.neutral[800],
1296
+ marginBottom: "4px"
1297
+ },
1298
+ children: "No sessions found"
1299
+ }
1300
+ ),
1301
+ /* @__PURE__ */ jsx(
1302
+ Typography,
1303
+ {
1304
+ variant: "omega",
1305
+ textColor: "neutral600",
1306
+ style: {
1307
+ fontSize: "1rem",
1308
+ maxWidth: "400px",
1309
+ lineHeight: "1.6"
1310
+ },
1311
+ children: "Try adjusting your search query or filters to find sessions"
1312
+ }
1313
+ )
1314
+ ] })
1315
+ ]
1316
+ }
1317
+ )
1318
+ )
1319
+ ] }),
1320
+ !loading && sessions.length === 0 && /* @__PURE__ */ jsxs(
1321
+ Box,
1322
+ {
1323
+ style: {
1324
+ background: theme.colors.neutral[0],
1325
+ borderRadius: theme.borderRadius.xl,
1326
+ border: `2px dashed ${theme.colors.neutral[200]}`,
1327
+ padding: "80px 32px",
1328
+ textAlign: "center",
1329
+ position: "relative",
1330
+ overflow: "hidden",
1331
+ minHeight: "400px",
1332
+ display: "flex",
1333
+ alignItems: "center",
1334
+ justifyContent: "center"
1335
+ },
1336
+ children: [
1337
+ /* @__PURE__ */ jsx(
1338
+ Box,
1339
+ {
1340
+ style: {
1341
+ position: "absolute",
1342
+ top: 0,
1343
+ left: 0,
1344
+ right: 0,
1345
+ bottom: 0,
1346
+ background: `linear-gradient(135deg, ${theme.colors.primary[50]} 0%, ${theme.colors.secondary[50]} 100%)`,
1347
+ opacity: 0.3,
1348
+ zIndex: 0
1349
+ }
1350
+ }
1351
+ ),
1352
+ /* @__PURE__ */ jsx(FloatingEmoji, { children: "💻" }),
1353
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "center", gap: 6, style: { position: "relative", zIndex: 1 }, children: [
1354
+ /* @__PURE__ */ jsx(
1355
+ Box,
1356
+ {
1357
+ style: {
1358
+ width: "120px",
1359
+ height: "120px",
1360
+ borderRadius: "50%",
1361
+ background: `linear-gradient(135deg, ${theme.colors.primary[100]} 0%, ${theme.colors.secondary[100]} 100%)`,
1362
+ display: "flex",
1363
+ alignItems: "center",
1364
+ justifyContent: "center",
1365
+ boxShadow: theme.shadows.xl
1366
+ },
1367
+ children: /* @__PURE__ */ jsx(Monitor, { style: { width: "60px", height: "60px", color: theme.colors.primary[600] } })
1368
+ }
1369
+ ),
1370
+ /* @__PURE__ */ jsx(
1371
+ Typography,
1372
+ {
1373
+ variant: "alpha",
1374
+ style: {
1375
+ fontSize: "1.75rem",
1376
+ fontWeight: "700",
1377
+ color: theme.colors.neutral[800],
1378
+ marginBottom: "8px"
1379
+ },
1380
+ children: "No sessions yet"
1381
+ }
1382
+ ),
1383
+ /* @__PURE__ */ jsx(
1384
+ Typography,
1385
+ {
1386
+ variant: "omega",
1387
+ textColor: "neutral600",
1388
+ style: {
1389
+ fontSize: "1rem",
1390
+ maxWidth: "500px",
1391
+ lineHeight: "1.6"
1392
+ },
1393
+ children: "Sessions will appear here when users log in to your application"
1394
+ }
1395
+ )
1396
+ ] })
1397
+ ]
1398
+ }
1399
+ ),
1400
+ showDetailModal && selectedSession && /* @__PURE__ */ jsx(
1401
+ SessionDetailModal,
1402
+ {
1403
+ session: selectedSession,
1404
+ onClose: handleModalClose,
1405
+ onSessionTerminated: handleSessionTerminated
1406
+ }
1407
+ )
1408
+ ] });
1409
+ };
1410
+ const fadeIn = keyframes`
1411
+ from { opacity: 0; }
1412
+ to { opacity: 1; }
1413
+ `;
1414
+ const slideUp = keyframes`
1415
+ from {
1416
+ opacity: 0;
1417
+ transform: translateY(30px);
1418
+ }
1419
+ to {
1420
+ opacity: 1;
1421
+ transform: translateY(0);
1422
+ }
1423
+ `;
1424
+ const ModalOverlay = styled.div`
1425
+ position: fixed;
1426
+ top: 0;
1427
+ left: 0;
1428
+ right: 0;
1429
+ bottom: 0;
1430
+ background: rgba(4, 28, 47, 0.85);
1431
+ backdrop-filter: blur(8px);
1432
+ z-index: 9999;
1433
+ display: flex;
1434
+ align-items: center;
1435
+ justify-content: center;
1436
+ animation: ${fadeIn} 0.3s ease-out;
1437
+ padding: 20px;
1438
+ `;
1439
+ const ModalContent = styled(Box)`
1440
+ background: white;
1441
+ border-radius: 16px;
1442
+ width: 100%;
1443
+ max-width: 580px;
1444
+ box-shadow: 0 25px 50px rgba(0, 0, 0, 0.3);
1445
+ animation: ${slideUp} 0.4s cubic-bezier(0.4, 0, 0.2, 1);
1446
+ overflow: hidden;
1447
+ `;
1448
+ const GradientHeader = styled(Box)`
1449
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
1450
+ padding: 32px 40px;
1451
+ position: relative;
1452
+ overflow: hidden;
1453
+
1454
+ &::before {
1455
+ content: '';
1456
+ position: absolute;
1457
+ top: -50%;
1458
+ right: -50%;
1459
+ width: 200%;
1460
+ height: 200%;
1461
+ background: radial-gradient(circle, rgba(255,255,255,0.1) 0%, transparent 70%);
1462
+ }
1463
+ `;
1464
+ const IconWrapper = styled.div`
1465
+ width: 72px;
1466
+ height: 72px;
1467
+ border-radius: 50%;
1468
+ background: rgba(255, 255, 255, 0.2);
1469
+ display: flex;
1470
+ align-items: center;
1471
+ justify-content: center;
1472
+ margin: 0 auto 16px;
1473
+ backdrop-filter: blur(10px);
1474
+ border: 2px solid rgba(255, 255, 255, 0.3);
1475
+
1476
+ svg {
1477
+ width: 36px;
1478
+ height: 36px;
1479
+ color: white;
1480
+ }
1481
+ `;
1482
+ const CloseButton = styled.button`
1483
+ position: absolute;
1484
+ top: 16px;
1485
+ right: 16px;
1486
+ background: rgba(255, 255, 255, 0.2);
1487
+ border: 2px solid rgba(255, 255, 255, 0.3);
1488
+ border-radius: 50%;
1489
+ width: 36px;
1490
+ height: 36px;
1491
+ display: flex;
1492
+ align-items: center;
1493
+ justify-content: center;
1494
+ cursor: pointer;
1495
+ transition: all 0.2s;
1496
+ z-index: 10;
1497
+
1498
+ svg {
1499
+ width: 20px;
1500
+ height: 20px;
1501
+ color: white;
1502
+ }
1503
+
1504
+ &:hover {
1505
+ background: rgba(255, 255, 255, 0.3);
1506
+ transform: scale(1.1);
1507
+ }
1508
+
1509
+ &:active {
1510
+ transform: scale(0.95);
1511
+ }
1512
+ `;
1513
+ const ToggleButton = styled.button`
1514
+ background: none;
1515
+ border: none;
1516
+ color: #667eea;
1517
+ font-size: 13px;
1518
+ font-weight: 600;
1519
+ cursor: pointer;
1520
+ padding: 8px 0;
1521
+ text-decoration: underline;
1522
+ transition: color 0.2s;
1523
+
1524
+ &:hover {
1525
+ color: #764ba2;
1526
+ }
1527
+ `;
1528
+ const LicenseGuard = ({ children }) => {
1529
+ const { get, post } = useFetchClient();
1530
+ const { toggleNotification } = useNotification();
1531
+ const navigate = useNavigate();
1532
+ const [isChecking, setIsChecking] = useState(true);
1533
+ const [needsLicense, setNeedsLicense] = useState(false);
1534
+ const [isCreating, setIsCreating] = useState(false);
1535
+ const [useExistingKey, setUseExistingKey] = useState(false);
1536
+ const [useAutoCreate, setUseAutoCreate] = useState(true);
1537
+ const [existingLicenseKey, setExistingLicenseKey] = useState("");
1538
+ const [existingEmail, setExistingEmail] = useState("");
1539
+ const [adminUser, setAdminUser] = useState(null);
1540
+ const [formData, setFormData] = useState({
1541
+ email: "",
1542
+ firstName: "",
1543
+ lastName: ""
1544
+ });
1545
+ useEffect(() => {
1546
+ checkLicenseStatus();
1547
+ fetchAdminUser();
1548
+ }, []);
1549
+ const fetchAdminUser = async () => {
1550
+ try {
1551
+ const response = await get("/admin/users/me");
1552
+ const userData = response.data?.data || response.data;
1553
+ if (userData) {
1554
+ setAdminUser(userData);
1555
+ setFormData({
1556
+ email: userData.email || "",
1557
+ firstName: userData.firstname || "",
1558
+ lastName: userData.lastname || ""
1559
+ });
1560
+ }
1561
+ } catch (error) {
1562
+ console.debug("[LicenseGuard] Could not fetch admin user (not logged in yet)");
1563
+ }
1564
+ };
1565
+ const checkLicenseStatus = async () => {
1566
+ setIsChecking(true);
1567
+ try {
1568
+ const response = await get(`/${pluginId}/license/status`);
1569
+ if (response.data.valid) {
1570
+ setNeedsLicense(false);
1571
+ } else {
1572
+ setNeedsLicense(true);
1573
+ }
1574
+ } catch (error) {
1575
+ console.error("[LicenseGuard] Error checking license:", error);
1576
+ setNeedsLicense(true);
1577
+ } finally {
1578
+ setIsChecking(false);
1579
+ }
1580
+ };
1581
+ const handleAutoCreateLicense = async (e) => {
1582
+ e.preventDefault();
1583
+ setIsCreating(true);
1584
+ try {
1585
+ const response = await post(`/${pluginId}/license/auto-create`, {});
1586
+ if (response.data && response.data.success) {
1587
+ toggleNotification({
1588
+ type: "success",
1589
+ message: "License automatically created! Reloading..."
1590
+ });
1591
+ setNeedsLicense(false);
1592
+ setTimeout(() => {
1593
+ window.location.reload();
1594
+ }, 500);
1595
+ } else {
1596
+ throw new Error("Failed to auto-create license");
1597
+ }
1598
+ } catch (error) {
1599
+ console.error("[LicenseGuard] Error auto-creating license:", error);
1600
+ toggleNotification({
1601
+ type: "danger",
1602
+ message: error?.response?.data?.error?.message || "Failed to auto-create license. Try manual creation."
1603
+ });
1604
+ setIsCreating(false);
1605
+ setUseAutoCreate(false);
1606
+ }
1607
+ };
1608
+ const handleCreateLicense = async (e) => {
1609
+ e.preventDefault();
1610
+ if (!formData.email || !formData.firstName || !formData.lastName) {
1611
+ toggleNotification({
1612
+ type: "warning",
1613
+ message: "Please fill in all fields"
1614
+ });
1615
+ return;
1616
+ }
1617
+ setIsCreating(true);
1618
+ try {
1619
+ const response = await post(`/${pluginId}/license/create`, formData);
1620
+ if (response.data && response.data.success) {
1621
+ toggleNotification({
1622
+ type: "success",
1623
+ message: "License created successfully! Reloading..."
1624
+ });
1625
+ setNeedsLicense(false);
1626
+ setTimeout(() => {
1627
+ window.location.reload();
1628
+ }, 500);
1629
+ } else {
1630
+ throw new Error("Failed to create license");
1631
+ }
1632
+ } catch (error) {
1633
+ console.error("[LicenseGuard] Error creating license:", error);
1634
+ toggleNotification({
1635
+ type: "danger",
1636
+ message: error?.response?.data?.error?.message || "Failed to create license. Please try again."
1637
+ });
1638
+ setIsCreating(false);
1639
+ }
1640
+ };
1641
+ const handleValidateExistingKey = async (e) => {
1642
+ e.preventDefault();
1643
+ if (!existingLicenseKey.trim() || !existingEmail.trim()) {
1644
+ toggleNotification({
1645
+ type: "warning",
1646
+ message: "Please enter both license key and email address"
1647
+ });
1648
+ return;
1649
+ }
1650
+ setIsCreating(true);
1651
+ try {
1652
+ const response = await post(`/${pluginId}/license/store-key`, {
1653
+ licenseKey: existingLicenseKey.trim(),
1654
+ email: existingEmail.trim()
1655
+ });
1656
+ if (response.data && response.data.success) {
1657
+ toggleNotification({
1658
+ type: "success",
1659
+ message: "License key validated successfully! Reloading..."
1660
+ });
1661
+ setNeedsLicense(false);
1662
+ setTimeout(() => {
1663
+ window.location.reload();
1664
+ }, 500);
1665
+ } else {
1666
+ throw new Error("Invalid license key or email");
1667
+ }
1668
+ } catch (error) {
1669
+ console.error("[LicenseGuard] Error validating license key:", error);
1670
+ toggleNotification({
1671
+ type: "danger",
1672
+ message: error?.response?.data?.error?.message || "Invalid license key or email address. Please check and try again."
1673
+ });
1674
+ setIsCreating(false);
1675
+ }
1676
+ };
1677
+ const handleClose = () => {
1678
+ navigate("/content-manager");
1679
+ };
1680
+ if (isChecking) {
1681
+ return /* @__PURE__ */ jsx(Box, { padding: 8, style: { textAlign: "center" }, children: /* @__PURE__ */ jsx(Loader, { children: "Checking license..." }) });
1682
+ }
1683
+ if (needsLicense) {
1684
+ return /* @__PURE__ */ jsx(ModalOverlay, { children: /* @__PURE__ */ jsxs(ModalContent, { children: [
1685
+ /* @__PURE__ */ jsxs(GradientHeader, { children: [
1686
+ /* @__PURE__ */ jsx(CloseButton, { onClick: handleClose, type: "button", children: /* @__PURE__ */ jsx(Cross, {}) }),
1687
+ /* @__PURE__ */ jsx(IconWrapper, { children: /* @__PURE__ */ jsx(Key, {}) }),
1688
+ /* @__PURE__ */ jsxs(Box, { style: { textAlign: "center", position: "relative" }, children: [
1689
+ /* @__PURE__ */ jsx(
1690
+ Typography,
1691
+ {
1692
+ variant: "alpha",
1693
+ style: {
1694
+ color: "white",
1695
+ fontSize: "24px",
1696
+ fontWeight: "700",
1697
+ marginBottom: "12px",
1698
+ display: "block"
1699
+ },
1700
+ children: "🔐 Activate Session Manager"
1701
+ }
1702
+ ),
1703
+ /* @__PURE__ */ jsx(
1704
+ Typography,
1705
+ {
1706
+ variant: "epsilon",
1707
+ style: {
1708
+ color: "rgba(255, 255, 255, 0.9)",
1709
+ fontSize: "14px",
1710
+ display: "block"
1711
+ },
1712
+ children: useExistingKey ? "Enter your existing license key" : "Create a license to start using the plugin"
1713
+ }
1714
+ )
1715
+ ] })
1716
+ ] }),
1717
+ /* @__PURE__ */ jsx("form", { onSubmit: useExistingKey ? handleValidateExistingKey : useAutoCreate ? handleAutoCreateLicense : handleCreateLicense, children: /* @__PURE__ */ jsx(
1718
+ Box,
1719
+ {
1720
+ padding: 6,
1721
+ paddingLeft: 8,
1722
+ paddingRight: 8,
1723
+ children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 5, style: { width: "100%" }, children: [
1724
+ /* @__PURE__ */ jsxs(Box, { style: { textAlign: "center", width: "100%" }, children: [
1725
+ !useExistingKey && /* @__PURE__ */ jsx(
1726
+ ToggleButton,
1727
+ {
1728
+ type: "button",
1729
+ onClick: () => setUseAutoCreate(!useAutoCreate),
1730
+ disabled: isCreating,
1731
+ style: { marginBottom: "8px", display: "block", margin: "0 auto" },
1732
+ children: useAutoCreate ? "→ Manual entry" : "← Auto-create with my account"
1733
+ }
1734
+ ),
1735
+ /* @__PURE__ */ jsx(
1736
+ ToggleButton,
1737
+ {
1738
+ type: "button",
1739
+ onClick: () => {
1740
+ setUseExistingKey(!useExistingKey);
1741
+ if (!useExistingKey) setUseAutoCreate(false);
1742
+ },
1743
+ disabled: isCreating,
1744
+ children: useExistingKey ? "← Create new license" : "Have a license key? →"
1745
+ }
1746
+ )
1747
+ ] }),
1748
+ /* @__PURE__ */ jsx(
1749
+ Box,
1750
+ {
1751
+ background: "primary100",
1752
+ padding: 4,
1753
+ style: {
1754
+ borderRadius: "8px",
1755
+ border: "2px solid #BAE6FD",
1756
+ width: "100%"
1757
+ },
1758
+ children: /* @__PURE__ */ jsx(Typography, { variant: "omega", style: { fontSize: "13px", lineHeight: "1.6" }, children: useExistingKey ? "🔑 Enter your email and license key to activate." : useAutoCreate && adminUser && adminUser.email ? `✨ Click "Activate" to auto-create a license with your account (${adminUser.email})` : useAutoCreate ? '✨ Click "Activate" to auto-create a license with your admin account' : "💡 A license will be created with the details below." })
1759
+ }
1760
+ ),
1761
+ useExistingKey ? (
1762
+ // Existing License Key Input
1763
+ /* @__PURE__ */ jsxs(Fragment, { children: [
1764
+ /* @__PURE__ */ jsxs(Box, { style: { width: "100%" }, children: [
1765
+ /* @__PURE__ */ jsx(
1766
+ Typography,
1767
+ {
1768
+ variant: "pi",
1769
+ fontWeight: "bold",
1770
+ style: { marginBottom: "8px", display: "block" },
1771
+ children: "Email Address *"
1772
+ }
1773
+ ),
1774
+ /* @__PURE__ */ jsx(
1775
+ TextInput,
1776
+ {
1777
+ placeholder: "admin@example.com",
1778
+ type: "email",
1779
+ value: existingEmail,
1780
+ onChange: (e) => setExistingEmail(e.target.value),
1781
+ required: true,
1782
+ disabled: isCreating
1783
+ }
1784
+ ),
1785
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", textColor: "neutral600", style: { fontSize: "11px", marginTop: "4px" }, children: "Enter the email address associated with this license" })
1786
+ ] }),
1787
+ /* @__PURE__ */ jsxs(Box, { style: { width: "100%" }, children: [
1788
+ /* @__PURE__ */ jsx(
1789
+ Typography,
1790
+ {
1791
+ variant: "pi",
1792
+ fontWeight: "bold",
1793
+ style: { marginBottom: "8px", display: "block" },
1794
+ children: "License Key *"
1795
+ }
1796
+ ),
1797
+ /* @__PURE__ */ jsx(
1798
+ TextInput,
1799
+ {
1800
+ placeholder: "67C5-40D2-7695-718C",
1801
+ value: existingLicenseKey,
1802
+ onChange: (e) => setExistingLicenseKey(e.target.value),
1803
+ required: true,
1804
+ disabled: isCreating
1805
+ }
1806
+ ),
1807
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", textColor: "neutral600", style: { fontSize: "11px", marginTop: "4px" }, children: "Enter the license key in the format: XXXX-XXXX-XXXX-XXXX" })
1808
+ ] })
1809
+ ] })
1810
+ ) : useAutoCreate && adminUser ? (
1811
+ // Auto-create mode - Show user info
1812
+ /* @__PURE__ */ jsxs(
1813
+ Box,
1814
+ {
1815
+ background: "success100",
1816
+ padding: 5,
1817
+ style: {
1818
+ borderRadius: "8px",
1819
+ border: "2px solid #DCFCE7",
1820
+ textAlign: "center"
1821
+ },
1822
+ children: [
1823
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "bold", style: { marginBottom: "12px", display: "block" }, children: "Ready to activate with your account:" }),
1824
+ /* @__PURE__ */ jsxs(Typography, { variant: "pi", style: { marginBottom: "4px", display: "block" }, children: [
1825
+ "👤 ",
1826
+ adminUser.firstname || "Admin",
1827
+ " ",
1828
+ adminUser.lastname || "User"
1829
+ ] }),
1830
+ /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", children: [
1831
+ "📧 ",
1832
+ adminUser.email || "Loading..."
1833
+ ] })
1834
+ ]
1835
+ }
1836
+ )
1837
+ ) : (
1838
+ // Manual Create License Fields
1839
+ /* @__PURE__ */ jsxs(Fragment, { children: [
1840
+ /* @__PURE__ */ jsxs(Box, { style: { width: "100%" }, children: [
1841
+ /* @__PURE__ */ jsx(
1842
+ Typography,
1843
+ {
1844
+ variant: "pi",
1845
+ fontWeight: "bold",
1846
+ style: { marginBottom: "8px", display: "block" },
1847
+ children: "Email Address *"
1848
+ }
1849
+ ),
1850
+ /* @__PURE__ */ jsx(
1851
+ TextInput,
1852
+ {
1853
+ placeholder: "admin@example.com",
1854
+ type: "email",
1855
+ value: formData.email,
1856
+ onChange: (e) => setFormData({ ...formData, email: e.target.value }),
1857
+ required: true,
1858
+ disabled: isCreating
1859
+ }
1860
+ )
1861
+ ] }),
1862
+ /* @__PURE__ */ jsxs(Box, { style: { width: "100%" }, children: [
1863
+ /* @__PURE__ */ jsx(
1864
+ Typography,
1865
+ {
1866
+ variant: "pi",
1867
+ fontWeight: "bold",
1868
+ style: { marginBottom: "8px", display: "block" },
1869
+ children: "First Name *"
1870
+ }
1871
+ ),
1872
+ /* @__PURE__ */ jsx(
1873
+ TextInput,
1874
+ {
1875
+ placeholder: "John",
1876
+ value: formData.firstName,
1877
+ onChange: (e) => setFormData({ ...formData, firstName: e.target.value }),
1878
+ required: true,
1879
+ disabled: isCreating
1880
+ }
1881
+ )
1882
+ ] }),
1883
+ /* @__PURE__ */ jsxs(Box, { style: { width: "100%" }, children: [
1884
+ /* @__PURE__ */ jsx(
1885
+ Typography,
1886
+ {
1887
+ variant: "pi",
1888
+ fontWeight: "bold",
1889
+ style: { marginBottom: "8px", display: "block" },
1890
+ children: "Last Name *"
1891
+ }
1892
+ ),
1893
+ /* @__PURE__ */ jsx(
1894
+ TextInput,
1895
+ {
1896
+ placeholder: "Doe",
1897
+ value: formData.lastName,
1898
+ onChange: (e) => setFormData({ ...formData, lastName: e.target.value }),
1899
+ required: true,
1900
+ disabled: isCreating
1901
+ }
1902
+ )
1903
+ ] })
1904
+ ] })
1905
+ ),
1906
+ /* @__PURE__ */ jsx(Flex, { gap: 3, justifyContent: "center", style: { marginTop: "16px" }, children: useExistingKey ? /* @__PURE__ */ jsx(
1907
+ Button,
1908
+ {
1909
+ type: "submit",
1910
+ size: "L",
1911
+ startIcon: /* @__PURE__ */ jsx(Check, {}),
1912
+ loading: isCreating,
1913
+ disabled: isCreating || !existingLicenseKey.trim() || !existingEmail.trim(),
1914
+ style: {
1915
+ background: "linear-gradient(135deg, #667eea 0%, #764ba2 100%)",
1916
+ color: "white",
1917
+ fontWeight: "600",
1918
+ border: "none",
1919
+ boxShadow: "0 4px 12px rgba(102, 126, 234, 0.4)"
1920
+ },
1921
+ children: "Validate License"
1922
+ }
1923
+ ) : /* @__PURE__ */ jsx(
1924
+ Button,
1925
+ {
1926
+ type: "submit",
1927
+ size: "L",
1928
+ startIcon: /* @__PURE__ */ jsx(Check, {}),
1929
+ loading: isCreating,
1930
+ disabled: isCreating || !useAutoCreate && (!formData.email || !formData.firstName || !formData.lastName),
1931
+ style: {
1932
+ background: "linear-gradient(135deg, #667eea 0%, #764ba2 100%)",
1933
+ color: "white",
1934
+ fontWeight: "600",
1935
+ border: "none",
1936
+ boxShadow: "0 4px 12px rgba(102, 126, 234, 0.4)"
1937
+ },
1938
+ children: useAutoCreate ? "Activate License" : "Create License"
1939
+ }
1940
+ ) })
1941
+ ] })
1942
+ }
1943
+ ) })
1944
+ ] }) });
1945
+ }
1946
+ return /* @__PURE__ */ jsx(Fragment, { children });
1947
+ };
1948
+ const App = () => {
1949
+ return /* @__PURE__ */ jsx(LicenseGuard, { children: /* @__PURE__ */ jsx(HomePage, {}) });
1950
+ };
1951
+ export {
1952
+ App as default
1953
+ };