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