strapi-plugin-magic-mark 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/COPYRIGHT_NOTICE.txt +20 -0
  2. package/LICENSE +28 -0
  3. package/README.md +372 -0
  4. package/dist/_chunks/App-7ZH1Reka.mjs +1390 -0
  5. package/dist/_chunks/App-CMSut1pt.js +1392 -0
  6. package/dist/_chunks/de-Bag-366k.mjs +49 -0
  7. package/dist/_chunks/de-Dic_hhjg.js +49 -0
  8. package/dist/_chunks/en-C5BvHqNo.js +54 -0
  9. package/dist/_chunks/en-zokEerzt.mjs +54 -0
  10. package/dist/_chunks/es-BlSQpU1z.js +54 -0
  11. package/dist/_chunks/es-Br1ucP3h.mjs +54 -0
  12. package/dist/_chunks/fr-BHciYPYG.js +54 -0
  13. package/dist/_chunks/fr-Dzo3kt_q.mjs +54 -0
  14. package/dist/_chunks/index-B-Cc7QNW.mjs +322 -0
  15. package/dist/_chunks/index-B11QBtag.js +324 -0
  16. package/dist/_chunks/index-DYHEyGJr.mjs +2020 -0
  17. package/dist/_chunks/index-DkkmdRgb.js +2024 -0
  18. package/dist/_chunks/pt-DQoGyzyD.mjs +54 -0
  19. package/dist/_chunks/pt-Dawo5aUA.js +54 -0
  20. package/dist/admin/index.js +3 -0
  21. package/dist/admin/index.mjs +4 -0
  22. package/dist/admin/src/components/AdvancedFilterButton.d.ts +3 -0
  23. package/dist/admin/src/components/AdvancedFilterModal.d.ts +21 -0
  24. package/dist/admin/src/components/CreateEditModal.d.ts +11 -0
  25. package/dist/admin/src/components/CreateViewModal.d.ts +9 -0
  26. package/dist/admin/src/components/CustomSelect.d.ts +13 -0
  27. package/dist/admin/src/components/FilterPreview.d.ts +6 -0
  28. package/dist/admin/src/components/HomePage.d.ts +0 -0
  29. package/dist/admin/src/components/Initializer.d.ts +6 -0
  30. package/dist/admin/src/components/LicenseGuard.d.ts +6 -0
  31. package/dist/admin/src/components/PluginIcon.d.ts +3 -0
  32. package/dist/admin/src/components/QueryBuilder.d.ts +23 -0
  33. package/dist/admin/src/components/SimpleAdvancedFilterModal.d.ts +15 -0
  34. package/dist/admin/src/components/ViewsListPopover.d.ts +2 -0
  35. package/dist/admin/src/components/ViewsWidget.d.ts +8 -0
  36. package/dist/admin/src/index.d.ts +15 -0
  37. package/dist/admin/src/pages/App.d.ts +3 -0
  38. package/dist/admin/src/pages/HomePage.d.ts +3 -0
  39. package/dist/admin/src/pages/HomePageModern.d.ts +3 -0
  40. package/dist/admin/src/pages/License/index.d.ts +3 -0
  41. package/dist/admin/src/permissions.d.ts +15 -0
  42. package/dist/admin/src/pluginId.d.ts +2 -0
  43. package/dist/admin/src/utils/queryGenerator.d.ts +28 -0
  44. package/dist/admin/src/utils/queryParser.d.ts +25 -0
  45. package/dist/admin/src/utils/queryToStructure.d.ts +20 -0
  46. package/dist/server/index.js +1309 -0
  47. package/dist/server/index.mjs +1307 -0
  48. package/dist/server/src/bootstrap.d.ts +5 -0
  49. package/dist/server/src/config/index.d.ts +5 -0
  50. package/dist/server/src/content-types/index.d.ts +82 -0
  51. package/dist/server/src/controllers/controller.d.ts +11 -0
  52. package/dist/server/src/controllers/index.d.ts +20 -0
  53. package/dist/server/src/controllers/license.d.ts +27 -0
  54. package/dist/server/src/destroy.d.ts +5 -0
  55. package/dist/server/src/index.d.ts +195 -0
  56. package/dist/server/src/middlewares/index.d.ts +4 -0
  57. package/dist/server/src/middlewares/license-check.d.ts +6 -0
  58. package/dist/server/src/policies/index.d.ts +4 -0
  59. package/dist/server/src/policies/license-check.d.ts +6 -0
  60. package/dist/server/src/register.d.ts +5 -0
  61. package/dist/server/src/routes/admin.d.ts +12 -0
  62. package/dist/server/src/routes/content-api.d.ts +5 -0
  63. package/dist/server/src/routes/index.d.ts +18 -0
  64. package/dist/server/src/services/index.d.ts +57 -0
  65. package/dist/server/src/services/license-guard.d.ts +103 -0
  66. package/dist/server/src/services/service.d.ts +33 -0
  67. package/package.json +108 -0
  68. package/strapi-server.js +4 -0
@@ -0,0 +1,1390 @@
1
+ import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
+ import { useState, useEffect } from "react";
3
+ import { useIntl } from "react-intl";
4
+ import { useNavigate } from "react-router-dom";
5
+ import styled, { keyframes } from "styled-components";
6
+ import { Flex, Loader, Box, Typography, SingleSelect, SingleSelectOption, Thead, Tr, Th, VisuallyHidden, Tbody, Td, Button, Table, TextInput } from "@strapi/design-system";
7
+ import { Sparkle, User, Pin, Link, Eye, Pencil, Trash, Search, Cross, Key, Check } from "@strapi/icons";
8
+ import { useFetchClient, useNotification } from "@strapi/strapi/admin";
9
+ import { p as pluginId, C as CreateEditModal } from "./index-DYHEyGJr.mjs";
10
+ const theme = {
11
+ colors: {
12
+ primary: {
13
+ 50: "#F0F9FF",
14
+ 100: "#E0F2FE",
15
+ 500: "#0EA5E9",
16
+ 600: "#0284C7",
17
+ 700: "#0369A1"
18
+ },
19
+ secondary: {
20
+ 600: "#9333EA"
21
+ },
22
+ success: {
23
+ 100: "#DCFCE7",
24
+ 500: "#22C55E",
25
+ 600: "#16A34A"
26
+ },
27
+ warning: {
28
+ 100: "#FEF3C7",
29
+ 500: "#F59E0B",
30
+ 600: "#D97706"
31
+ },
32
+ neutral: {
33
+ 0: "#FFFFFF",
34
+ 50: "#F9FAFB",
35
+ 100: "#F3F4F6",
36
+ 200: "#E5E7EB",
37
+ 600: "#4B5563",
38
+ 700: "#374151",
39
+ 800: "#1F2937"
40
+ }
41
+ },
42
+ shadows: {
43
+ sm: "0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1)",
44
+ xl: "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)"
45
+ },
46
+ transitions: {
47
+ fast: "150ms cubic-bezier(0.4, 0, 0.2, 1)",
48
+ normal: "300ms cubic-bezier(0.4, 0, 0.2, 1)",
49
+ slow: "500ms cubic-bezier(0.4, 0, 0.2, 1)"
50
+ },
51
+ spacing: {
52
+ xs: "4px",
53
+ sm: "8px",
54
+ md: "16px",
55
+ lg: "24px",
56
+ xl: "32px",
57
+ "2xl": "48px"
58
+ },
59
+ borderRadius: {
60
+ md: "8px",
61
+ lg: "12px",
62
+ xl: "16px"
63
+ }
64
+ };
65
+ const fadeIn$1 = keyframes`
66
+ from { opacity: 0; transform: translateY(10px); }
67
+ to { opacity: 1; transform: translateY(0); }
68
+ `;
69
+ keyframes`
70
+ from { opacity: 0; transform: translateX(-10px); }
71
+ to { opacity: 1; transform: translateX(0); }
72
+ `;
73
+ const shimmer = keyframes`
74
+ 0% { background-position: -200% 0; }
75
+ 100% { background-position: 200% 0; }
76
+ `;
77
+ const float = keyframes`
78
+ 0%, 100% { transform: translateY(0px); }
79
+ 50% { transform: translateY(-5px); }
80
+ `;
81
+ const breakpoints = {
82
+ mobile: "768px"
83
+ };
84
+ const Container = styled(Box)`
85
+ animation: ${fadeIn$1} ${theme.transitions.slow};
86
+ min-height: 100vh;
87
+ max-width: 1440px;
88
+ margin: 0 auto;
89
+ padding: ${theme.spacing.xl} ${theme.spacing.lg} 0;
90
+
91
+ @media screen and (max-width: ${breakpoints.mobile}) {
92
+ padding: ${theme.spacing.md} ${theme.spacing.sm} 0;
93
+ }
94
+ `;
95
+ const Header = styled(Box)`
96
+ background: linear-gradient(135deg,
97
+ ${theme.colors.primary[600]} 0%,
98
+ ${theme.colors.secondary[600]} 100%
99
+ );
100
+ border-radius: ${theme.borderRadius.xl};
101
+ padding: ${theme.spacing.xl} ${theme.spacing["2xl"]};
102
+ margin-bottom: ${theme.spacing.xl};
103
+ position: relative;
104
+ overflow: hidden;
105
+ box-shadow: ${theme.shadows.xl};
106
+
107
+ @media screen and (max-width: ${breakpoints.mobile}) {
108
+ padding: ${theme.spacing.lg} ${theme.spacing.md} !important;
109
+ border-radius: ${theme.borderRadius.lg} !important;
110
+ }
111
+
112
+ &::before {
113
+ content: '';
114
+ position: absolute;
115
+ top: 0;
116
+ left: -100%;
117
+ width: 200%;
118
+ height: 100%;
119
+ background: linear-gradient(
120
+ 90deg,
121
+ transparent,
122
+ rgba(255, 255, 255, 0.1),
123
+ transparent
124
+ );
125
+ animation: ${shimmer} 3s infinite;
126
+ }
127
+
128
+ &::after {
129
+ content: '';
130
+ position: absolute;
131
+ top: 0;
132
+ right: 0;
133
+ width: 100%;
134
+ height: 100%;
135
+ background-image: radial-gradient(circle at 20% 80%, transparent 50%, rgba(255, 255, 255, 0.1) 50%);
136
+ background-size: 15px 15px;
137
+ opacity: 0.3;
138
+ }
139
+ `;
140
+ const HeaderContent = styled(Flex)`
141
+ position: relative;
142
+ z-index: 1;
143
+ `;
144
+ const Title = styled(Typography)`
145
+ color: ${theme.colors.neutral[0]};
146
+ font-size: 2rem;
147
+ font-weight: 700;
148
+ letter-spacing: -0.025em;
149
+ text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
150
+ display: flex;
151
+ align-items: center;
152
+ gap: ${theme.spacing.sm};
153
+
154
+ svg {
155
+ width: 28px;
156
+ height: 28px;
157
+ animation: ${float} 3s ease-in-out infinite;
158
+ }
159
+ `;
160
+ const Subtitle = styled(Typography)`
161
+ color: rgba(255, 255, 255, 0.9);
162
+ font-size: 0.95rem;
163
+ font-weight: 400;
164
+ margin-top: ${theme.spacing.xs};
165
+ letter-spacing: 0.01em;
166
+ `;
167
+ const StatsGrid = styled.div`
168
+ margin-bottom: ${theme.spacing.xl};
169
+ display: grid;
170
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
171
+ gap: ${theme.spacing.md};
172
+ justify-content: center;
173
+ max-width: 1200px;
174
+ margin-left: auto;
175
+ margin-right: auto;
176
+
177
+ @media screen and (max-width: ${breakpoints.mobile}) {
178
+ grid-template-columns: repeat(2, 1fr) !important;
179
+ gap: 12px !important;
180
+ margin-bottom: 24px !important;
181
+ }
182
+ `;
183
+ const StatCard = styled(Box)`
184
+ background: ${theme.colors.neutral[0]};
185
+ border-radius: ${theme.borderRadius.lg};
186
+ padding: ${theme.spacing.lg};
187
+ position: relative;
188
+ overflow: hidden;
189
+ transition: all ${theme.transitions.normal};
190
+ animation: ${fadeIn$1} ${theme.transitions.slow} backwards;
191
+ animation-delay: ${(props) => props.$delay || "0s"};
192
+ box-shadow: ${theme.shadows.sm};
193
+ border: 1px solid ${theme.colors.neutral[200]};
194
+ min-width: 200px;
195
+ flex: 1;
196
+ text-align: center;
197
+ display: flex;
198
+ flex-direction: column;
199
+ align-items: center;
200
+ justify-content: center;
201
+
202
+ &:hover {
203
+ transform: translateY(-4px);
204
+ box-shadow: ${theme.shadows.xl};
205
+ border-color: ${(props) => props.$color || theme.colors.primary[500]};
206
+
207
+ .stat-icon {
208
+ transform: scale(1.1);
209
+ }
210
+
211
+ .stat-value {
212
+ transform: scale(1.05);
213
+ }
214
+ }
215
+
216
+ @media screen and (max-width: ${breakpoints.mobile}) {
217
+ min-width: unset !important;
218
+ padding: ${theme.spacing.md} !important;
219
+
220
+ &:hover {
221
+ transform: none !important;
222
+ }
223
+ }
224
+ `;
225
+ const StatIcon = styled(Box)`
226
+ width: 64px;
227
+ height: 64px;
228
+ border-radius: ${theme.borderRadius.md};
229
+ display: flex;
230
+ align-items: center;
231
+ justify-content: center;
232
+ background: ${(props) => props.$bg || theme.colors.primary[100]};
233
+ transition: all ${theme.transitions.normal};
234
+ margin-bottom: ${theme.spacing.md};
235
+
236
+ svg {
237
+ width: 32px;
238
+ height: 32px;
239
+ color: ${(props) => props.$color || theme.colors.primary[600]};
240
+ }
241
+ `;
242
+ const StatValue = styled(Typography)`
243
+ font-size: 2.5rem;
244
+ font-weight: 700;
245
+ color: ${theme.colors.neutral[800]};
246
+ line-height: 1;
247
+ margin-bottom: ${theme.spacing.xs};
248
+ transition: transform ${theme.transitions.normal};
249
+ `;
250
+ const StatLabel = styled(Typography)`
251
+ font-size: 0.875rem;
252
+ color: ${theme.colors.neutral[600]};
253
+ font-weight: 500;
254
+ letter-spacing: 0.025em;
255
+ text-transform: capitalize;
256
+ `;
257
+ const DataTable = styled(Box)`
258
+ background: ${theme.colors.neutral[0]};
259
+ border-radius: ${theme.borderRadius.lg};
260
+ overflow: hidden;
261
+ box-shadow: ${theme.shadows.sm};
262
+ border: 1px solid ${theme.colors.neutral[200]};
263
+ margin-bottom: ${theme.spacing.xl};
264
+ `;
265
+ const StyledTable = styled(Table)`
266
+ thead {
267
+ background: ${theme.colors.neutral[0]};
268
+ border-bottom: 2px solid ${theme.colors.neutral[100]};
269
+
270
+ th {
271
+ font-weight: 600;
272
+ color: ${theme.colors.neutral[700]};
273
+ font-size: 0.875rem;
274
+ text-transform: uppercase;
275
+ letter-spacing: 0.025em;
276
+ padding: ${theme.spacing.lg} ${theme.spacing.lg};
277
+ }
278
+ }
279
+
280
+ tbody tr {
281
+ transition: all ${theme.transitions.fast};
282
+ border-bottom: 1px solid ${theme.colors.neutral[100]};
283
+
284
+ &:last-child {
285
+ border-bottom: none;
286
+ }
287
+
288
+ &:hover {
289
+ background: ${theme.colors.neutral[50]};
290
+
291
+ .action-buttons {
292
+ opacity: 1;
293
+ }
294
+ }
295
+
296
+ td {
297
+ padding: ${theme.spacing.lg} ${theme.spacing.lg};
298
+ color: ${theme.colors.neutral[700]};
299
+ vertical-align: middle;
300
+ }
301
+ }
302
+ `;
303
+ styled(Box)`
304
+ width: 4px;
305
+ height: 40px;
306
+ background: ${(props) => props.$isPinned ? theme.colors.warning[500] : "transparent"};
307
+ border-radius: 2px;
308
+ transition: all ${theme.transitions.normal};
309
+ `;
310
+ styled.div`
311
+ font-size: 32px;
312
+ line-height: 1;
313
+ text-align: center;
314
+ `;
315
+ const ActionButtons = styled(Flex)`
316
+ opacity: 1;
317
+ transition: all ${theme.transitions.fast};
318
+ gap: ${theme.spacing.xs};
319
+ justify-content: flex-end;
320
+ `;
321
+ const FloatingEmoji = styled.div`
322
+ position: absolute;
323
+ bottom: 40px;
324
+ right: 40px;
325
+ font-size: 72px;
326
+ opacity: 0.08;
327
+ animation: ${float} 4s ease-in-out infinite;
328
+ `;
329
+ const FilterBar = styled(Flex)`
330
+ background: ${theme.colors.neutral[0]};
331
+ padding: ${theme.spacing.md} ${theme.spacing.lg};
332
+ border-radius: ${theme.borderRadius.lg};
333
+ margin-bottom: ${theme.spacing.lg};
334
+ box-shadow: ${theme.shadows.sm};
335
+ border: 1px solid ${theme.colors.neutral[200]};
336
+ gap: ${theme.spacing.md};
337
+ align-items: center;
338
+ `;
339
+ const FilterSelect = styled(Box)`
340
+ min-width: 120px;
341
+ `;
342
+ const SearchInputWrapper = styled.div`
343
+ position: relative;
344
+ width: 100%;
345
+ display: flex;
346
+ align-items: center;
347
+ `;
348
+ const SearchIcon = styled(Search)`
349
+ position: absolute;
350
+ left: 12px;
351
+ width: 16px;
352
+ height: 16px;
353
+ color: ${theme.colors.neutral[600]};
354
+ pointer-events: none;
355
+ `;
356
+ const StyledSearchInput = styled.input`
357
+ width: 100%;
358
+ padding: ${theme.spacing.sm} ${theme.spacing.sm} ${theme.spacing.sm} 36px;
359
+ border: 1px solid ${theme.colors.neutral[200]};
360
+ border-radius: ${theme.borderRadius.md};
361
+ font-size: 0.875rem;
362
+ transition: all ${theme.transitions.fast};
363
+ background: ${theme.colors.neutral[0]};
364
+ color: ${theme.colors.neutral[800]};
365
+
366
+ &:focus {
367
+ outline: none;
368
+ border-color: ${theme.colors.primary[500]};
369
+ box-shadow: 0 0 0 3px ${theme.colors.primary[100]};
370
+ }
371
+
372
+ &::placeholder {
373
+ color: ${theme.colors.neutral[600]};
374
+ }
375
+ `;
376
+ const HomePageModern = () => {
377
+ const { formatMessage } = useIntl();
378
+ const navigate = useNavigate();
379
+ const { get, post, del } = useFetchClient();
380
+ const [currentUser, setCurrentUser] = useState(null);
381
+ const [bookmarks, setBookmarks] = useState([]);
382
+ const [loading, setLoading] = useState(false);
383
+ const [showModal, setShowModal] = useState(false);
384
+ const [editingBookmark, setEditingBookmark] = useState(null);
385
+ const [searchQuery, setSearchQuery] = useState("");
386
+ const [filterType, setFilterType] = useState("all");
387
+ const [entriesPerPage, setEntriesPerPage] = useState("10");
388
+ const [availableRoles, setAvailableRoles] = useState([]);
389
+ const [availableUsers, setAvailableUsers] = useState([]);
390
+ useEffect(() => {
391
+ fetchBookmarks();
392
+ fetchCurrentUser();
393
+ fetchRoles();
394
+ fetchUsers();
395
+ }, []);
396
+ const fetchRoles = async () => {
397
+ try {
398
+ const response = await get(`/${pluginId}/roles`);
399
+ const roles = response.data?.data?.data || response.data?.data || [];
400
+ console.log("[Magic-Mark] Available roles in HomePage:", roles);
401
+ setAvailableRoles(roles);
402
+ } catch (error) {
403
+ console.error("[Magic-Mark] Error fetching roles:", error);
404
+ }
405
+ };
406
+ const fetchUsers = async () => {
407
+ try {
408
+ const response = await get("/admin/users?pageSize=100&page=1&sort=firstname");
409
+ console.log("[Magic-Mark] Admin users API response:", response);
410
+ const allUsers = response.data?.data?.results || response.data?.results || [];
411
+ console.log("[Magic-Mark] All users from API in HomePage:", allUsers);
412
+ const users = currentUser && Array.isArray(allUsers) ? allUsers.filter((u) => u.id !== currentUser.id) : allUsers;
413
+ console.log("[Magic-Mark] Available users in HomePage:", users);
414
+ setAvailableUsers(users);
415
+ } catch (error) {
416
+ console.error("[Magic-Mark] Error fetching users from admin API:", error);
417
+ try {
418
+ const response = await get(`/${pluginId}/users`);
419
+ const users = response.data?.data?.data || response.data?.data || [];
420
+ setAvailableUsers(users);
421
+ } catch (fallbackError) {
422
+ console.warn("[Magic-Mark] Both user endpoints failed");
423
+ setAvailableUsers([]);
424
+ }
425
+ }
426
+ };
427
+ const fetchCurrentUser = async () => {
428
+ try {
429
+ const response = await get("/admin/users/me");
430
+ console.log("[Magic-Mark] Current user response:", response);
431
+ const userData = response.data?.data || response.data || response;
432
+ setCurrentUser(userData);
433
+ console.log("[Magic-Mark] Current user set to:", userData);
434
+ } catch (error) {
435
+ console.error("[Magic-Mark] Error fetching current user:", error);
436
+ }
437
+ };
438
+ const fetchBookmarks = async () => {
439
+ setLoading(true);
440
+ try {
441
+ const { data } = await get(`/${pluginId}/bookmarks`);
442
+ console.log("[Magic-Mark HomePage] Bookmarks loaded:", data);
443
+ console.log("[Magic-Mark HomePage] Current user state:", currentUser);
444
+ setBookmarks(data.data || []);
445
+ } catch (error) {
446
+ console.error("[Magic-Mark HomePage] Error fetching bookmarks:", error);
447
+ } finally {
448
+ setLoading(false);
449
+ }
450
+ };
451
+ const handleDelete = async (id) => {
452
+ if (!confirm(formatMessage({
453
+ id: `${pluginId}.confirm.delete`,
454
+ defaultMessage: "Are you sure you want to delete this bookmark?"
455
+ }))) {
456
+ return;
457
+ }
458
+ try {
459
+ await del(`/${pluginId}/bookmarks/${id}`);
460
+ console.log("[Magic-Mark HomePage] Bookmark deleted:", id);
461
+ fetchBookmarks();
462
+ } catch (error) {
463
+ console.error("[Magic-Mark HomePage] Error deleting bookmark:", error);
464
+ }
465
+ };
466
+ const handlePin = async (bookmark) => {
467
+ try {
468
+ await post(`/${pluginId}/bookmarks/${bookmark.id}/pin`, {
469
+ isPinned: !bookmark.isPinned
470
+ });
471
+ console.log("[Magic-Mark HomePage] Bookmark pinned:", bookmark.id);
472
+ fetchBookmarks();
473
+ } catch (error) {
474
+ console.error("[Magic-Mark HomePage] Error pinning bookmark:", error);
475
+ }
476
+ };
477
+ const handleEdit = (bookmark) => {
478
+ setEditingBookmark(bookmark);
479
+ setShowModal(true);
480
+ };
481
+ const handleModalClose = () => {
482
+ setShowModal(false);
483
+ setEditingBookmark(null);
484
+ };
485
+ const handleModalSuccess = () => {
486
+ setShowModal(false);
487
+ setEditingBookmark(null);
488
+ fetchBookmarks();
489
+ };
490
+ const handleBookmarkClick = (bookmark) => {
491
+ if (bookmark.path) {
492
+ let path = bookmark.path;
493
+ if (path.startsWith("/admin/")) {
494
+ path = path.substring(6);
495
+ }
496
+ const url = bookmark.query ? `${path}?${bookmark.query}` : path;
497
+ console.log("[HomePage] Navigating to:", url);
498
+ navigate(url);
499
+ }
500
+ };
501
+ const filteredBookmarks = bookmarks.filter((bookmark) => {
502
+ if (filterType === "pinned" && !bookmark.isPinned) return false;
503
+ if (filterType === "unpinned" && bookmark.isPinned) return false;
504
+ if (!searchQuery) return true;
505
+ const query = searchQuery.toLowerCase();
506
+ return bookmark.name.toLowerCase().includes(query) || bookmark.description && bookmark.description.toLowerCase().includes(query) || bookmark.path.toLowerCase().includes(query);
507
+ }).slice(0, parseInt(entriesPerPage));
508
+ const pinnedBookmarks = bookmarks.filter((b) => b.isPinned);
509
+ const myBookmarks = bookmarks.filter((b) => b.createdBy?.id === currentUser?.id);
510
+ const sharedWithMe = bookmarks.filter((b) => b.createdBy?.id !== currentUser?.id && b.createdBy?.id);
511
+ return /* @__PURE__ */ jsxs(Container, { padding: 8, children: [
512
+ /* @__PURE__ */ jsx(Header, { children: /* @__PURE__ */ jsxs(HeaderContent, { direction: "column", alignItems: "flex-start", gap: 2, children: [
513
+ /* @__PURE__ */ jsxs(Title, { children: [
514
+ /* @__PURE__ */ jsx(Sparkle, {}),
515
+ " MagicMark"
516
+ ] }),
517
+ /* @__PURE__ */ jsx(Subtitle, { children: "Save filtered views and navigate with one click" })
518
+ ] }) }),
519
+ /* @__PURE__ */ jsxs(StatsGrid, { children: [
520
+ /* @__PURE__ */ jsxs(StatCard, { $delay: "0.1s", $color: theme.colors.primary[500], children: [
521
+ /* @__PURE__ */ jsx(StatIcon, { className: "stat-icon", $bg: theme.colors.primary[100], $color: theme.colors.primary[600], children: /* @__PURE__ */ jsx(User, {}) }),
522
+ /* @__PURE__ */ jsx(StatValue, { className: "stat-value", children: myBookmarks.length }),
523
+ /* @__PURE__ */ jsx(StatLabel, { children: "My Bookmarks" })
524
+ ] }),
525
+ /* @__PURE__ */ jsxs(StatCard, { $delay: "0.2s", $color: theme.colors.success[500], children: [
526
+ /* @__PURE__ */ jsx(StatIcon, { className: "stat-icon", $bg: theme.colors.success[100], $color: theme.colors.success[600], children: /* @__PURE__ */ jsx(Sparkle, {}) }),
527
+ /* @__PURE__ */ jsx(StatValue, { className: "stat-value", children: sharedWithMe.length }),
528
+ /* @__PURE__ */ jsx(StatLabel, { children: "Shared with Me" })
529
+ ] }),
530
+ /* @__PURE__ */ jsxs(StatCard, { $delay: "0.3s", $color: theme.colors.warning[500], children: [
531
+ /* @__PURE__ */ jsx(StatIcon, { className: "stat-icon", $bg: theme.colors.warning[100], $color: theme.colors.warning[600], children: /* @__PURE__ */ jsx(Pin, {}) }),
532
+ /* @__PURE__ */ jsx(StatValue, { className: "stat-value", children: pinnedBookmarks.length }),
533
+ /* @__PURE__ */ jsx(StatLabel, { children: "Pinned" })
534
+ ] }),
535
+ /* @__PURE__ */ jsxs(StatCard, { $delay: "0.4s", $color: theme.colors.neutral[600], children: [
536
+ /* @__PURE__ */ jsx(StatIcon, { className: "stat-icon", $bg: theme.colors.neutral[100], $color: theme.colors.neutral[600], children: /* @__PURE__ */ jsx(Link, {}) }),
537
+ /* @__PURE__ */ jsx(StatValue, { className: "stat-value", children: bookmarks.length }),
538
+ /* @__PURE__ */ jsx(StatLabel, { children: "Total Available" })
539
+ ] })
540
+ ] }),
541
+ loading && /* @__PURE__ */ jsx(Flex, { justifyContent: "center", padding: 8, children: /* @__PURE__ */ jsx(Loader, { children: "Loading bookmarks..." }) }),
542
+ !loading && sharedWithMe.length > 0 && /* @__PURE__ */ jsx(Box, { marginBottom: 4, children: /* @__PURE__ */ jsxs(Box, { style: {
543
+ padding: theme.spacing.lg,
544
+ background: theme.colors.primary[50],
545
+ borderRadius: theme.borderRadius.lg,
546
+ border: `1px solid ${theme.colors.primary[200]}`
547
+ }, children: [
548
+ /* @__PURE__ */ jsx(Typography, { variant: "beta", style: { marginBottom: theme.spacing.sm, color: theme.colors.primary[700] }, children: "🤝 Shared with You" }),
549
+ /* @__PURE__ */ jsxs(Typography, { variant: "pi", style: { color: theme.colors.primary[600] }, children: [
550
+ sharedWithMe.length,
551
+ " bookmark",
552
+ sharedWithMe.length > 1 ? "s" : "",
553
+ " have been shared with you"
554
+ ] }),
555
+ /* @__PURE__ */ jsx(Box, { marginTop: 2, children: [...new Map(sharedWithMe.map((b) => [b.createdBy?.id, b.createdBy])).values()].map((creator) => {
556
+ const creatorBookmarks = sharedWithMe.filter((b) => b.createdBy?.id === creator?.id);
557
+ return creator && /* @__PURE__ */ jsxs(Flex, { alignItems: "center", marginTop: 1, children: [
558
+ /* @__PURE__ */ jsxs(Typography, { variant: "pi", fontWeight: "semiBold", children: [
559
+ creator.firstname || "Unknown",
560
+ " ",
561
+ creator.lastname || "",
562
+ ":"
563
+ ] }),
564
+ /* @__PURE__ */ jsxs(Typography, { variant: "pi", marginLeft: 1, children: [
565
+ creatorBookmarks.length,
566
+ " bookmark",
567
+ creatorBookmarks.length > 1 ? "s" : ""
568
+ ] })
569
+ ] }, creator.id);
570
+ }) })
571
+ ] }) }),
572
+ !loading && bookmarks.length > 0 && /* @__PURE__ */ jsxs(Box, { children: [
573
+ /* @__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 Available Bookmarks" }) }),
574
+ /* @__PURE__ */ jsxs(FilterBar, { children: [
575
+ /* @__PURE__ */ jsxs(SearchInputWrapper, { style: { flex: 1 }, children: [
576
+ /* @__PURE__ */ jsx(SearchIcon, {}),
577
+ /* @__PURE__ */ jsx(
578
+ StyledSearchInput,
579
+ {
580
+ value: searchQuery,
581
+ onChange: (e) => setSearchQuery(e.target.value),
582
+ placeholder: "Search by name, description...",
583
+ type: "text"
584
+ }
585
+ )
586
+ ] }),
587
+ /* @__PURE__ */ jsx(FilterSelect, { children: /* @__PURE__ */ jsxs(
588
+ SingleSelect,
589
+ {
590
+ value: filterType,
591
+ onChange: setFilterType,
592
+ placeholder: "Filter",
593
+ size: "S",
594
+ children: [
595
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "all", children: "Show All" }),
596
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "pinned", children: "Pinned Only" }),
597
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "unpinned", children: "Unpinned Only" })
598
+ ]
599
+ }
600
+ ) }),
601
+ /* @__PURE__ */ jsx(FilterSelect, { children: /* @__PURE__ */ jsxs(
602
+ SingleSelect,
603
+ {
604
+ value: entriesPerPage,
605
+ onChange: setEntriesPerPage,
606
+ placeholder: "Entries",
607
+ size: "S",
608
+ children: [
609
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "10", children: "10 entries" }),
610
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "25", children: "25 entries" }),
611
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "50", children: "50 entries" }),
612
+ /* @__PURE__ */ jsx(SingleSelectOption, { value: "100", children: "100 entries" })
613
+ ]
614
+ }
615
+ ) })
616
+ ] }),
617
+ /* @__PURE__ */ jsx(DataTable, { children: /* @__PURE__ */ jsxs(StyledTable, { children: [
618
+ /* @__PURE__ */ jsx(Thead, { children: /* @__PURE__ */ jsxs(Tr, { children: [
619
+ /* @__PURE__ */ jsx(Th, { children: formatMessage({
620
+ id: `${pluginId}.table.name`,
621
+ defaultMessage: "Name"
622
+ }) }),
623
+ /* @__PURE__ */ jsx(Th, { children: formatMessage({
624
+ id: `${pluginId}.table.description`,
625
+ defaultMessage: "Description"
626
+ }) }),
627
+ /* @__PURE__ */ jsx(Th, { children: /* @__PURE__ */ jsx(VisuallyHidden, { children: "Actions" }) })
628
+ ] }) }),
629
+ /* @__PURE__ */ jsx(Tbody, { children: filteredBookmarks.map((bookmark) => /* @__PURE__ */ jsxs(Tr, { style: {
630
+ background: bookmark.isPinned ? theme.colors.warning[50] : "transparent"
631
+ }, children: [
632
+ /* @__PURE__ */ jsx(Td, { onClick: () => handleBookmarkClick(bookmark), style: { cursor: "pointer" }, children: /* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 3, children: [
633
+ /* @__PURE__ */ jsx(
634
+ Box,
635
+ {
636
+ style: {
637
+ width: "36px",
638
+ height: "36px",
639
+ display: "flex",
640
+ alignItems: "center",
641
+ justifyContent: "center",
642
+ flexShrink: 0,
643
+ fontSize: "24px"
644
+ },
645
+ children: bookmark.emoji
646
+ }
647
+ ),
648
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", gap: 0, children: [
649
+ /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", ellipsis: true, style: { fontSize: "1.125rem", lineHeight: "1.4" }, children: bookmark.name }),
650
+ /* @__PURE__ */ jsxs(Flex, { gap: 1, alignItems: "center", children: [
651
+ bookmark.createdBy?.id && currentUser?.id && bookmark.createdBy.id === currentUser.id ? /* @__PURE__ */ jsx(Typography, { variant: "pi", style: { fontSize: "0.75rem", color: theme.colors.primary[600], fontWeight: 500 }, children: "• My Bookmark" }) : /* @__PURE__ */ jsxs(Typography, { variant: "pi", style: { fontSize: "0.75rem", color: theme.colors.neutral[600] }, children: [
652
+ "• Shared by ",
653
+ bookmark.createdBy?.firstname || "Unknown"
654
+ ] }),
655
+ bookmark.isPublic && /* @__PURE__ */ jsx(Typography, { variant: "pi", style: { fontSize: "0.75rem", color: theme.colors.success[600], marginLeft: "8px" }, children: "• Public" }),
656
+ bookmark.sharedWithRoles && bookmark.sharedWithRoles.length > 0 && !bookmark.isPublic && /* @__PURE__ */ jsxs(Typography, { variant: "pi", style: { fontSize: "0.75rem", color: theme.colors.warning[600], marginLeft: "8px" }, children: [
657
+ "• Roles: ",
658
+ bookmark.sharedWithRoles.map((roleId) => {
659
+ const role = availableRoles.find((r) => r.id === roleId);
660
+ return role?.name || `Role ${roleId}`;
661
+ }).join(", ")
662
+ ] }),
663
+ bookmark.sharedWithUsers && bookmark.sharedWithUsers.length > 0 && !bookmark.isPublic && /* @__PURE__ */ jsxs(Typography, { variant: "pi", style: { fontSize: "0.75rem", color: theme.colors.primary[600], marginLeft: "8px" }, children: [
664
+ "• Users: ",
665
+ bookmark.sharedWithUsers.map((userId) => {
666
+ const user = availableUsers.find((u) => u.id === userId);
667
+ return user ? `${user.firstname} ${user.lastname}` : `User ${userId}`;
668
+ }).join(", ")
669
+ ] })
670
+ ] })
671
+ ] })
672
+ ] }) }),
673
+ /* @__PURE__ */ jsx(Td, { onClick: () => handleBookmarkClick(bookmark), style: { cursor: "pointer" }, children: /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", ellipsis: true, style: { fontSize: "1rem", lineHeight: "1.6", fontWeight: 400 }, children: bookmark.description || "-" }) }),
674
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsxs(
675
+ ActionButtons,
676
+ {
677
+ className: "action-buttons",
678
+ children: [
679
+ /* @__PURE__ */ jsx(
680
+ Button,
681
+ {
682
+ variant: bookmark.isPinned ? "secondary" : "ghost",
683
+ size: "S",
684
+ onClick: (e) => {
685
+ e.stopPropagation();
686
+ handlePin(bookmark);
687
+ },
688
+ style: {
689
+ color: bookmark.isPinned ? theme.colors.warning[600] : "inherit",
690
+ background: bookmark.isPinned ? theme.colors.warning[100] : "transparent"
691
+ },
692
+ children: /* @__PURE__ */ jsx(Pin, {})
693
+ }
694
+ ),
695
+ /* @__PURE__ */ jsx(
696
+ Button,
697
+ {
698
+ variant: "ghost",
699
+ size: "S",
700
+ onClick: (e) => {
701
+ e.stopPropagation();
702
+ handleBookmarkClick(bookmark);
703
+ },
704
+ children: /* @__PURE__ */ jsx(Eye, {})
705
+ }
706
+ ),
707
+ bookmark.createdBy && /* @__PURE__ */ jsx(
708
+ Button,
709
+ {
710
+ variant: "ghost",
711
+ size: "S",
712
+ onClick: (e) => {
713
+ e.stopPropagation();
714
+ handleEdit(bookmark);
715
+ },
716
+ disabled: bookmark.createdBy?.id !== currentUser?.id,
717
+ children: /* @__PURE__ */ jsx(Pencil, {})
718
+ }
719
+ ),
720
+ bookmark.createdBy?.id && currentUser?.id && bookmark.createdBy.id === currentUser.id && /* @__PURE__ */ jsx(
721
+ Button,
722
+ {
723
+ variant: "ghost",
724
+ size: "S",
725
+ onClick: (e) => {
726
+ e.stopPropagation();
727
+ handleDelete(bookmark.id);
728
+ },
729
+ children: /* @__PURE__ */ jsx(Trash, {})
730
+ }
731
+ )
732
+ ]
733
+ }
734
+ ) })
735
+ ] }, bookmark.id)) })
736
+ ] }) })
737
+ ] }),
738
+ !loading && bookmarks.length === 0 && /* @__PURE__ */ jsxs(
739
+ Box,
740
+ {
741
+ style: {
742
+ background: theme.colors.neutral[0],
743
+ borderRadius: theme.borderRadius.xl,
744
+ border: `2px dashed ${theme.colors.neutral[200]}`,
745
+ padding: theme.spacing["3xl"],
746
+ textAlign: "center",
747
+ position: "relative",
748
+ overflow: "hidden",
749
+ minHeight: "400px",
750
+ display: "flex",
751
+ alignItems: "center",
752
+ justifyContent: "center"
753
+ },
754
+ children: [
755
+ /* @__PURE__ */ jsx(
756
+ Box,
757
+ {
758
+ style: {
759
+ content: "",
760
+ position: "absolute",
761
+ top: 0,
762
+ left: 0,
763
+ right: 0,
764
+ bottom: 0,
765
+ background: `linear-gradient(135deg, ${theme.colors.primary[50]} 0%, ${theme.colors.secondary[50]} 100%)`,
766
+ opacity: 0.3,
767
+ zIndex: 0
768
+ }
769
+ }
770
+ ),
771
+ /* @__PURE__ */ jsx(FloatingEmoji, { children: "✨" }),
772
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "center", gap: 6, style: { position: "relative", zIndex: 1 }, children: [
773
+ /* @__PURE__ */ jsx(
774
+ Box,
775
+ {
776
+ style: {
777
+ width: "120px",
778
+ height: "120px",
779
+ borderRadius: "50%",
780
+ background: `linear-gradient(135deg, ${theme.colors.primary[100]} 0%, ${theme.colors.secondary[100]} 100%)`,
781
+ display: "flex",
782
+ alignItems: "center",
783
+ justifyContent: "center",
784
+ boxShadow: theme.shadows.xl
785
+ },
786
+ children: /* @__PURE__ */ jsx(Sparkle, { style: { width: "60px", height: "60px", color: theme.colors.primary[600] } })
787
+ }
788
+ ),
789
+ /* @__PURE__ */ jsx(
790
+ Typography,
791
+ {
792
+ variant: "alpha",
793
+ style: {
794
+ fontSize: "1.75rem",
795
+ fontWeight: "700",
796
+ color: theme.colors.neutral[800],
797
+ marginBottom: "8px"
798
+ },
799
+ children: "No bookmarks yet"
800
+ }
801
+ ),
802
+ /* @__PURE__ */ jsxs(
803
+ Typography,
804
+ {
805
+ variant: "omega",
806
+ textColor: "neutral600",
807
+ style: {
808
+ fontSize: "1rem",
809
+ maxWidth: "500px",
810
+ lineHeight: "1.6"
811
+ },
812
+ children: [
813
+ "Navigate to any Content Manager view, apply filters, and click ",
814
+ /* @__PURE__ */ jsx("strong", { children: '"Save Bookmark"' }),
815
+ " to create quick access shortcuts"
816
+ ]
817
+ }
818
+ )
819
+ ] })
820
+ ]
821
+ }
822
+ ),
823
+ showModal && /* @__PURE__ */ jsx(
824
+ CreateEditModal,
825
+ {
826
+ bookmark: editingBookmark,
827
+ pluginId,
828
+ onClose: handleModalClose,
829
+ onSuccess: handleModalSuccess,
830
+ currentPath: "",
831
+ currentQuery: ""
832
+ }
833
+ )
834
+ ] });
835
+ };
836
+ const fadeIn = keyframes`
837
+ from { opacity: 0; }
838
+ to { opacity: 1; }
839
+ `;
840
+ const slideUp = keyframes`
841
+ from {
842
+ opacity: 0;
843
+ transform: translateY(30px);
844
+ }
845
+ to {
846
+ opacity: 1;
847
+ transform: translateY(0);
848
+ }
849
+ `;
850
+ const ModalOverlay = styled.div`
851
+ position: fixed;
852
+ top: 0;
853
+ left: 0;
854
+ right: 0;
855
+ bottom: 0;
856
+ background: rgba(4, 28, 47, 0.85);
857
+ backdrop-filter: blur(8px);
858
+ z-index: 9999;
859
+ display: flex;
860
+ align-items: center;
861
+ justify-content: center;
862
+ animation: ${fadeIn} 0.3s ease-out;
863
+ padding: 20px;
864
+ `;
865
+ const ModalContent = styled(Box)`
866
+ background: white;
867
+ border-radius: 16px;
868
+ width: 100%;
869
+ max-width: 580px;
870
+ box-shadow: 0 25px 50px rgba(0, 0, 0, 0.3);
871
+ animation: ${slideUp} 0.4s cubic-bezier(0.4, 0, 0.2, 1);
872
+ overflow: hidden;
873
+ `;
874
+ const GradientHeader = styled(Box)`
875
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
876
+ padding: 32px 40px;
877
+ position: relative;
878
+ overflow: hidden;
879
+
880
+ &::before {
881
+ content: '';
882
+ position: absolute;
883
+ top: -50%;
884
+ right: -50%;
885
+ width: 200%;
886
+ height: 200%;
887
+ background: radial-gradient(circle, rgba(255,255,255,0.1) 0%, transparent 70%);
888
+ }
889
+ `;
890
+ const IconWrapper = styled.div`
891
+ width: 72px;
892
+ height: 72px;
893
+ border-radius: 50%;
894
+ background: rgba(255, 255, 255, 0.2);
895
+ display: flex;
896
+ align-items: center;
897
+ justify-content: center;
898
+ margin: 0 auto 16px;
899
+ backdrop-filter: blur(10px);
900
+ border: 2px solid rgba(255, 255, 255, 0.3);
901
+
902
+ svg {
903
+ width: 36px;
904
+ height: 36px;
905
+ color: white;
906
+ }
907
+ `;
908
+ const CloseButton = styled.button`
909
+ position: absolute;
910
+ top: 16px;
911
+ right: 16px;
912
+ background: rgba(255, 255, 255, 0.2);
913
+ border: 2px solid rgba(255, 255, 255, 0.3);
914
+ border-radius: 50%;
915
+ width: 36px;
916
+ height: 36px;
917
+ display: flex;
918
+ align-items: center;
919
+ justify-content: center;
920
+ cursor: pointer;
921
+ transition: all 0.2s;
922
+ z-index: 10;
923
+
924
+ svg {
925
+ width: 20px;
926
+ height: 20px;
927
+ color: white;
928
+ }
929
+
930
+ &:hover {
931
+ background: rgba(255, 255, 255, 0.3);
932
+ transform: scale(1.1);
933
+ }
934
+
935
+ &:active {
936
+ transform: scale(0.95);
937
+ }
938
+ `;
939
+ const ToggleButton = styled.button`
940
+ background: none;
941
+ border: none;
942
+ color: #667eea;
943
+ font-size: 13px;
944
+ font-weight: 600;
945
+ cursor: pointer;
946
+ padding: 8px 0;
947
+ text-decoration: underline;
948
+ transition: color 0.2s;
949
+
950
+ &:hover {
951
+ color: #764ba2;
952
+ }
953
+ `;
954
+ const LicenseGuard = ({ children }) => {
955
+ const { get, post } = useFetchClient();
956
+ const { toggleNotification } = useNotification();
957
+ const navigate = useNavigate();
958
+ const [isChecking, setIsChecking] = useState(true);
959
+ const [needsLicense, setNeedsLicense] = useState(false);
960
+ const [isCreating, setIsCreating] = useState(false);
961
+ const [useExistingKey, setUseExistingKey] = useState(false);
962
+ const [useAutoCreate, setUseAutoCreate] = useState(true);
963
+ const [existingLicenseKey, setExistingLicenseKey] = useState("");
964
+ const [existingEmail, setExistingEmail] = useState("");
965
+ const [adminUser, setAdminUser] = useState(null);
966
+ const [formData, setFormData] = useState({
967
+ email: "",
968
+ firstName: "",
969
+ lastName: ""
970
+ });
971
+ useEffect(() => {
972
+ checkLicenseStatus();
973
+ fetchAdminUser();
974
+ }, []);
975
+ const fetchAdminUser = async () => {
976
+ try {
977
+ const response = await get("/admin/users/me");
978
+ console.log("Admin user response:", response);
979
+ const userData = response.data?.data || response.data;
980
+ console.log("User data extracted:", userData);
981
+ if (userData) {
982
+ setAdminUser(userData);
983
+ setFormData({
984
+ email: userData.email || "",
985
+ firstName: userData.firstname || "",
986
+ lastName: userData.lastname || ""
987
+ });
988
+ console.log("Admin user set:", {
989
+ email: userData.email,
990
+ firstname: userData.firstname,
991
+ lastname: userData.lastname
992
+ });
993
+ }
994
+ } catch (error) {
995
+ console.error("Error fetching admin user:", error);
996
+ }
997
+ };
998
+ const checkLicenseStatus = async () => {
999
+ setIsChecking(true);
1000
+ try {
1001
+ const response = await get("/magic-mark/license/status");
1002
+ if (response.data.valid) {
1003
+ setNeedsLicense(false);
1004
+ } else {
1005
+ setNeedsLicense(true);
1006
+ }
1007
+ } catch (error) {
1008
+ console.error("Error checking license:", error);
1009
+ setNeedsLicense(true);
1010
+ } finally {
1011
+ setIsChecking(false);
1012
+ }
1013
+ };
1014
+ const handleAutoCreateLicense = async (e) => {
1015
+ e.preventDefault();
1016
+ setIsCreating(true);
1017
+ try {
1018
+ console.log("Auto-creating license with admin user data...");
1019
+ const response = await post("/magic-mark/license/auto-create", {});
1020
+ if (response.data && response.data.success) {
1021
+ toggleNotification({
1022
+ type: "success",
1023
+ message: `License automatically created! Reloading...`
1024
+ });
1025
+ setNeedsLicense(false);
1026
+ setTimeout(() => {
1027
+ window.location.reload();
1028
+ }, 500);
1029
+ } else {
1030
+ throw new Error("Failed to auto-create license");
1031
+ }
1032
+ } catch (error) {
1033
+ console.error("Error auto-creating license:", error);
1034
+ toggleNotification({
1035
+ type: "danger",
1036
+ message: error?.response?.data?.error?.message || "Failed to auto-create license. Try manual creation."
1037
+ });
1038
+ setIsCreating(false);
1039
+ setUseAutoCreate(false);
1040
+ }
1041
+ };
1042
+ const handleCreateLicense = async (e) => {
1043
+ e.preventDefault();
1044
+ if (!formData.email || !formData.firstName || !formData.lastName) {
1045
+ toggleNotification({
1046
+ type: "warning",
1047
+ message: "Please fill in all fields"
1048
+ });
1049
+ return;
1050
+ }
1051
+ setIsCreating(true);
1052
+ try {
1053
+ console.log("Creating license with data:", formData);
1054
+ const response = await post("/magic-mark/license/create", formData);
1055
+ console.log("License creation response:", response);
1056
+ if (response.data && response.data.success) {
1057
+ toggleNotification({
1058
+ type: "success",
1059
+ message: `License created successfully! Reloading...`
1060
+ });
1061
+ setNeedsLicense(false);
1062
+ setTimeout(() => {
1063
+ window.location.reload();
1064
+ }, 500);
1065
+ } else {
1066
+ throw new Error("Failed to create license");
1067
+ }
1068
+ } catch (error) {
1069
+ console.error("Error creating license:", error);
1070
+ toggleNotification({
1071
+ type: "danger",
1072
+ message: error?.response?.data?.error?.message || "Failed to create license. Please try again."
1073
+ });
1074
+ setIsCreating(false);
1075
+ }
1076
+ };
1077
+ const handleValidateExistingKey = async (e) => {
1078
+ e.preventDefault();
1079
+ if (!existingLicenseKey.trim() || !existingEmail.trim()) {
1080
+ toggleNotification({
1081
+ type: "warning",
1082
+ message: "Please enter both license key and email address"
1083
+ });
1084
+ return;
1085
+ }
1086
+ setIsCreating(true);
1087
+ try {
1088
+ console.log("Validating existing license key...");
1089
+ const pluginStore = await post("/magic-mark/license/store-key", {
1090
+ licenseKey: existingLicenseKey.trim(),
1091
+ email: existingEmail.trim()
1092
+ });
1093
+ if (pluginStore.data && pluginStore.data.success) {
1094
+ toggleNotification({
1095
+ type: "success",
1096
+ message: "License key validated successfully! Reloading..."
1097
+ });
1098
+ setNeedsLicense(false);
1099
+ setTimeout(() => {
1100
+ window.location.reload();
1101
+ }, 500);
1102
+ } else {
1103
+ throw new Error("Invalid license key or email");
1104
+ }
1105
+ } catch (error) {
1106
+ console.error("Error validating license key:", error);
1107
+ toggleNotification({
1108
+ type: "danger",
1109
+ message: error?.response?.data?.error?.message || "Invalid license key or email address. Please check and try again."
1110
+ });
1111
+ setIsCreating(false);
1112
+ }
1113
+ };
1114
+ const handleClose = () => {
1115
+ navigate("/content-manager");
1116
+ };
1117
+ if (isChecking) {
1118
+ return /* @__PURE__ */ jsx(Box, { padding: 8, style: { textAlign: "center" }, children: /* @__PURE__ */ jsx(Loader, { children: "Checking license..." }) });
1119
+ }
1120
+ if (needsLicense) {
1121
+ return /* @__PURE__ */ jsx(ModalOverlay, { children: /* @__PURE__ */ jsxs(ModalContent, { children: [
1122
+ /* @__PURE__ */ jsxs(GradientHeader, { children: [
1123
+ /* @__PURE__ */ jsx(CloseButton, { onClick: handleClose, type: "button", children: /* @__PURE__ */ jsx(Cross, {}) }),
1124
+ /* @__PURE__ */ jsx(IconWrapper, { children: /* @__PURE__ */ jsx(Key, {}) }),
1125
+ /* @__PURE__ */ jsxs(Box, { style: { textAlign: "center", position: "relative" }, children: [
1126
+ /* @__PURE__ */ jsx(
1127
+ Typography,
1128
+ {
1129
+ variant: "alpha",
1130
+ style: {
1131
+ color: "white",
1132
+ fontSize: "24px",
1133
+ fontWeight: "700",
1134
+ marginBottom: "12px",
1135
+ display: "block"
1136
+ },
1137
+ children: "🔐 Activate MagicMark Plugin"
1138
+ }
1139
+ ),
1140
+ /* @__PURE__ */ jsx(
1141
+ Typography,
1142
+ {
1143
+ variant: "epsilon",
1144
+ style: {
1145
+ color: "rgba(255, 255, 255, 0.9)",
1146
+ fontSize: "14px",
1147
+ display: "block"
1148
+ },
1149
+ children: useExistingKey ? "Enter your existing license key" : "Create a license to start using the plugin"
1150
+ }
1151
+ )
1152
+ ] })
1153
+ ] }),
1154
+ /* @__PURE__ */ jsx("form", { onSubmit: useExistingKey ? handleValidateExistingKey : useAutoCreate ? handleAutoCreateLicense : handleCreateLicense, children: /* @__PURE__ */ jsx(
1155
+ Box,
1156
+ {
1157
+ padding: 6,
1158
+ paddingLeft: 8,
1159
+ paddingRight: 8,
1160
+ children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 5, style: { width: "100%" }, children: [
1161
+ /* @__PURE__ */ jsxs(Box, { style: { textAlign: "center", width: "100%" }, children: [
1162
+ !useExistingKey && /* @__PURE__ */ jsx(
1163
+ ToggleButton,
1164
+ {
1165
+ type: "button",
1166
+ onClick: () => setUseAutoCreate(!useAutoCreate),
1167
+ disabled: isCreating,
1168
+ style: { marginBottom: "8px", display: "block", margin: "0 auto" },
1169
+ children: useAutoCreate ? "→ Manual entry" : "← Auto-create with my account"
1170
+ }
1171
+ ),
1172
+ /* @__PURE__ */ jsx(
1173
+ ToggleButton,
1174
+ {
1175
+ type: "button",
1176
+ onClick: () => {
1177
+ setUseExistingKey(!useExistingKey);
1178
+ if (!useExistingKey) setUseAutoCreate(false);
1179
+ },
1180
+ disabled: isCreating,
1181
+ children: useExistingKey ? "← Create new license" : "Have a license key? →"
1182
+ }
1183
+ )
1184
+ ] }),
1185
+ /* @__PURE__ */ jsx(
1186
+ Box,
1187
+ {
1188
+ background: "primary100",
1189
+ padding: 4,
1190
+ style: {
1191
+ borderRadius: "8px",
1192
+ border: "2px solid #BAE6FD",
1193
+ width: "100%"
1194
+ },
1195
+ 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." })
1196
+ }
1197
+ ),
1198
+ useExistingKey ? (
1199
+ // Existing License Key Input
1200
+ /* @__PURE__ */ jsxs(Fragment, { children: [
1201
+ /* @__PURE__ */ jsxs(Box, { style: { width: "100%" }, children: [
1202
+ /* @__PURE__ */ jsx(
1203
+ Typography,
1204
+ {
1205
+ variant: "pi",
1206
+ fontWeight: "bold",
1207
+ style: { marginBottom: "8px", display: "block" },
1208
+ children: "Email Address *"
1209
+ }
1210
+ ),
1211
+ /* @__PURE__ */ jsx(
1212
+ TextInput,
1213
+ {
1214
+ placeholder: "admin@example.com",
1215
+ type: "email",
1216
+ value: existingEmail,
1217
+ onChange: (e) => setExistingEmail(e.target.value),
1218
+ required: true,
1219
+ disabled: isCreating
1220
+ }
1221
+ ),
1222
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", textColor: "neutral600", style: { fontSize: "11px", marginTop: "4px" }, children: "Enter the email address associated with this license" })
1223
+ ] }),
1224
+ /* @__PURE__ */ jsxs(Box, { style: { width: "100%" }, children: [
1225
+ /* @__PURE__ */ jsx(
1226
+ Typography,
1227
+ {
1228
+ variant: "pi",
1229
+ fontWeight: "bold",
1230
+ style: { marginBottom: "8px", display: "block" },
1231
+ children: "License Key *"
1232
+ }
1233
+ ),
1234
+ /* @__PURE__ */ jsx(
1235
+ TextInput,
1236
+ {
1237
+ placeholder: "67C5-40D2-7695-718C",
1238
+ value: existingLicenseKey,
1239
+ onChange: (e) => setExistingLicenseKey(e.target.value),
1240
+ required: true,
1241
+ disabled: isCreating
1242
+ }
1243
+ ),
1244
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", textColor: "neutral600", style: { fontSize: "11px", marginTop: "4px" }, children: "Enter the license key in the format: XXXX-XXXX-XXXX-XXXX" })
1245
+ ] })
1246
+ ] })
1247
+ ) : useAutoCreate && adminUser ? (
1248
+ // Auto-create mode - Show user info
1249
+ /* @__PURE__ */ jsxs(
1250
+ Box,
1251
+ {
1252
+ background: "success100",
1253
+ padding: 5,
1254
+ style: {
1255
+ borderRadius: "8px",
1256
+ border: "2px solid #DCFCE7",
1257
+ textAlign: "center"
1258
+ },
1259
+ children: [
1260
+ /* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "bold", style: { marginBottom: "12px", display: "block" }, children: "Ready to activate with your account:" }),
1261
+ /* @__PURE__ */ jsxs(Typography, { variant: "pi", style: { marginBottom: "4px", display: "block" }, children: [
1262
+ "👤 ",
1263
+ adminUser.firstname || "Admin",
1264
+ " ",
1265
+ adminUser.lastname || "User"
1266
+ ] }),
1267
+ /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", children: [
1268
+ "📧 ",
1269
+ adminUser.email || "Loading..."
1270
+ ] })
1271
+ ]
1272
+ }
1273
+ )
1274
+ ) : (
1275
+ // Manual Create License Fields
1276
+ /* @__PURE__ */ jsxs(Fragment, { children: [
1277
+ /* @__PURE__ */ jsxs(Box, { style: { width: "100%" }, children: [
1278
+ /* @__PURE__ */ jsx(
1279
+ Typography,
1280
+ {
1281
+ variant: "pi",
1282
+ fontWeight: "bold",
1283
+ style: { marginBottom: "8px", display: "block" },
1284
+ children: "Email Address *"
1285
+ }
1286
+ ),
1287
+ /* @__PURE__ */ jsx(
1288
+ TextInput,
1289
+ {
1290
+ placeholder: "admin@example.com",
1291
+ type: "email",
1292
+ value: formData.email,
1293
+ onChange: (e) => setFormData({ ...formData, email: e.target.value }),
1294
+ required: true,
1295
+ disabled: isCreating
1296
+ }
1297
+ )
1298
+ ] }),
1299
+ /* @__PURE__ */ jsxs(Box, { style: { width: "100%" }, children: [
1300
+ /* @__PURE__ */ jsx(
1301
+ Typography,
1302
+ {
1303
+ variant: "pi",
1304
+ fontWeight: "bold",
1305
+ style: { marginBottom: "8px", display: "block" },
1306
+ children: "First Name *"
1307
+ }
1308
+ ),
1309
+ /* @__PURE__ */ jsx(
1310
+ TextInput,
1311
+ {
1312
+ placeholder: "John",
1313
+ value: formData.firstName,
1314
+ onChange: (e) => setFormData({ ...formData, firstName: e.target.value }),
1315
+ required: true,
1316
+ disabled: isCreating
1317
+ }
1318
+ )
1319
+ ] }),
1320
+ /* @__PURE__ */ jsxs(Box, { style: { width: "100%" }, children: [
1321
+ /* @__PURE__ */ jsx(
1322
+ Typography,
1323
+ {
1324
+ variant: "pi",
1325
+ fontWeight: "bold",
1326
+ style: { marginBottom: "8px", display: "block" },
1327
+ children: "Last Name *"
1328
+ }
1329
+ ),
1330
+ /* @__PURE__ */ jsx(
1331
+ TextInput,
1332
+ {
1333
+ placeholder: "Doe",
1334
+ value: formData.lastName,
1335
+ onChange: (e) => setFormData({ ...formData, lastName: e.target.value }),
1336
+ required: true,
1337
+ disabled: isCreating
1338
+ }
1339
+ )
1340
+ ] })
1341
+ ] })
1342
+ ),
1343
+ /* @__PURE__ */ jsx(Flex, { gap: 3, justifyContent: "center", style: { marginTop: "16px" }, children: useExistingKey ? /* @__PURE__ */ jsx(
1344
+ Button,
1345
+ {
1346
+ type: "submit",
1347
+ size: "L",
1348
+ startIcon: /* @__PURE__ */ jsx(Check, {}),
1349
+ loading: isCreating,
1350
+ disabled: isCreating || !existingLicenseKey.trim() || !existingEmail.trim(),
1351
+ style: {
1352
+ background: "linear-gradient(135deg, #667eea 0%, #764ba2 100%)",
1353
+ color: "white",
1354
+ fontWeight: "600",
1355
+ border: "none",
1356
+ boxShadow: "0 4px 12px rgba(102, 126, 234, 0.4)"
1357
+ },
1358
+ children: "Validate License"
1359
+ }
1360
+ ) : /* @__PURE__ */ jsx(
1361
+ Button,
1362
+ {
1363
+ type: "submit",
1364
+ size: "L",
1365
+ startIcon: /* @__PURE__ */ jsx(Check, {}),
1366
+ loading: isCreating,
1367
+ disabled: isCreating || !useAutoCreate && (!formData.email || !formData.firstName || !formData.lastName),
1368
+ style: {
1369
+ background: "linear-gradient(135deg, #667eea 0%, #764ba2 100%)",
1370
+ color: "white",
1371
+ fontWeight: "600",
1372
+ border: "none",
1373
+ boxShadow: "0 4px 12px rgba(102, 126, 234, 0.4)"
1374
+ },
1375
+ children: useAutoCreate ? "Activate License" : "Create License"
1376
+ }
1377
+ ) })
1378
+ ] })
1379
+ }
1380
+ ) })
1381
+ ] }) });
1382
+ }
1383
+ return /* @__PURE__ */ jsx(Fragment, { children });
1384
+ };
1385
+ const App = () => {
1386
+ return /* @__PURE__ */ jsx(LicenseGuard, { children: /* @__PURE__ */ jsx(HomePageModern, {}) });
1387
+ };
1388
+ export {
1389
+ App as default
1390
+ };