@alepha/ui 0.14.1 → 0.14.3

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 (183) hide show
  1. package/dist/admin/AdminAudits-B3EhKhN7.js +3 -0
  2. package/dist/admin/{AdminAudits-CwvH8e8c.js → AdminAudits-DIrCCPk3.js} +3 -2
  3. package/dist/admin/AdminAudits-DIrCCPk3.js.map +1 -0
  4. package/dist/admin/AdminFiles-C8OG4dtD.js +3 -0
  5. package/dist/admin/{AdminFiles-C_w1tb_x.js → AdminFiles-RsL178Ta.js} +2 -2
  6. package/dist/admin/{AdminFiles-C_w1tb_x.js.map → AdminFiles-RsL178Ta.js.map} +1 -1
  7. package/dist/admin/AdminNotifications-BSL4B2fQ.js +3 -0
  8. package/dist/admin/{AdminNotifications-DuYy74AN.js → AdminNotifications-cIbywWKi.js} +2 -2
  9. package/dist/admin/AdminNotifications-cIbywWKi.js.map +1 -0
  10. package/dist/admin/{AdminParameters-DYg48Jwe.js → AdminParameters-BKObzzpN.js} +1 -1
  11. package/dist/admin/{AdminParameters-YagqWTG3.js → AdminParameters-D-q3Qmhv.js} +2 -2
  12. package/dist/admin/{AdminParameters-YagqWTG3.js.map → AdminParameters-D-q3Qmhv.js.map} +1 -1
  13. package/dist/admin/AdminSessions-DHG9zPfr.js +3 -0
  14. package/dist/admin/{AdminSessions-BCjgJ-93.js → AdminSessions-vOgkrQ2U.js} +3 -2
  15. package/dist/admin/AdminSessions-vOgkrQ2U.js.map +1 -0
  16. package/dist/admin/{AdminUserAudits-B_PUXCKC.js → AdminUserAudits-CSsN1fIC.js} +3 -2
  17. package/dist/admin/AdminUserAudits-CSsN1fIC.js.map +1 -0
  18. package/dist/admin/{AdminUserAudits-D7cTcElL.js → AdminUserAudits-DmAnivo3.js} +1 -1
  19. package/dist/admin/{AdminUserCreate-DzfRbGZ4.js → AdminUserCreate-B72nu-3W.js} +3 -2
  20. package/dist/admin/AdminUserCreate-B72nu-3W.js.map +1 -0
  21. package/dist/admin/{AdminUserCreate-oUA1KDIl.js → AdminUserCreate-DpA13zwj.js} +1 -1
  22. package/dist/admin/AdminUserDetails-CKM2IEMr.js +475 -0
  23. package/dist/admin/AdminUserDetails-CKM2IEMr.js.map +1 -0
  24. package/dist/admin/{AdminUserDetails-y1H5DW8Y.js → AdminUserDetails-Zib_B6Al.js} +1 -1
  25. package/dist/admin/{AdminUserLayout-Dejnz13m.js → AdminUserLayout-BNBOEiAO.js} +1 -1
  26. package/dist/admin/AdminUserLayout-D7En9UBq.js +334 -0
  27. package/dist/admin/AdminUserLayout-D7En9UBq.js.map +1 -0
  28. package/dist/admin/AdminUserSessions-D9X2_HMA.js +3 -0
  29. package/dist/admin/{AdminUserSessions-DO9H85O-.js → AdminUserSessions-DEaGu6n6.js} +3 -2
  30. package/dist/admin/AdminUserSessions-DEaGu6n6.js.map +1 -0
  31. package/dist/admin/{AdminUserSettings-B3jA8g3p.js → AdminUserSettings-Di73D7g2.js} +8 -6
  32. package/dist/admin/AdminUserSettings-Di73D7g2.js.map +1 -0
  33. package/dist/admin/AdminUserSettings-yI-JECf5.js +3 -0
  34. package/dist/admin/{AdminUsers-ebbrJBT0.js → AdminUsers-BnGIRvmV.js} +3 -2
  35. package/dist/admin/AdminUsers-BnGIRvmV.js.map +1 -0
  36. package/dist/admin/AdminUsers-CG9-2Z8W.js +3 -0
  37. package/dist/admin/index.d.ts +25 -25
  38. package/dist/admin/index.d.ts.map +1 -1
  39. package/dist/admin/index.js +37 -36
  40. package/dist/admin/index.js.map +1 -1
  41. package/dist/auth/{AuthLayout-BAZJHzDG.js → AuthLayout-B1sUB8fB.js} +2 -2
  42. package/dist/auth/AuthLayout-B1sUB8fB.js.map +1 -0
  43. package/dist/auth/Login-BWi-pPbO.js +4 -0
  44. package/dist/auth/{Login-CeNZZjrr.js → Login-Cjxv3EDi.js} +2 -2
  45. package/dist/auth/Login-Cjxv3EDi.js.map +1 -0
  46. package/dist/auth/{Register-s4ENeyiE.js → Register-BKBIpHhW.js} +3 -2
  47. package/dist/auth/Register-BKBIpHhW.js.map +1 -0
  48. package/dist/auth/Register-CtdvihIM.js +4 -0
  49. package/dist/auth/ResetPassword-BUdM7T_R.js +3 -0
  50. package/dist/auth/{ResetPassword-GLIFkJT7.js → ResetPassword-DvqD_1SJ.js} +3 -2
  51. package/dist/auth/ResetPassword-DvqD_1SJ.js.map +1 -0
  52. package/dist/auth/VerifyEmail-BYmtnkEl.js +3 -0
  53. package/dist/auth/{VerifyEmail-R79sSej_.js → VerifyEmail-VaBruOnO.js} +3 -2
  54. package/dist/auth/VerifyEmail-VaBruOnO.js.map +1 -0
  55. package/dist/auth/index.d.ts +11 -11
  56. package/dist/auth/index.d.ts.map +1 -1
  57. package/dist/auth/index.js +10 -10
  58. package/dist/auth/index.js.map +1 -1
  59. package/dist/core/index.d.ts +36 -55
  60. package/dist/core/index.d.ts.map +1 -1
  61. package/dist/core/index.js +50 -350
  62. package/dist/core/index.js.map +1 -1
  63. package/dist/demo/DemoDataTable-2mzzf__a.js +150 -0
  64. package/dist/demo/DemoDataTable-2mzzf__a.js.map +1 -0
  65. package/dist/demo/DemoHome-CnuL5WV9.js +25 -0
  66. package/dist/demo/DemoHome-CnuL5WV9.js.map +1 -0
  67. package/dist/demo/DemoHome-D6Z7EE4V.js +3 -0
  68. package/dist/demo/DemoJsonViewer-CYUggLop.js +4 -0
  69. package/dist/demo/DemoJsonViewer-NUGst5wW.js +430 -0
  70. package/dist/demo/DemoJsonViewer-NUGst5wW.js.map +1 -0
  71. package/dist/demo/DemoLayout-ZFDzyvY3.js +3 -0
  72. package/dist/demo/DemoLayout-dvbeuBBf.js +47 -0
  73. package/dist/demo/DemoLayout-dvbeuBBf.js.map +1 -0
  74. package/dist/demo/DemoLogin--wE44i23.js +327 -0
  75. package/dist/demo/DemoLogin--wE44i23.js.map +1 -0
  76. package/dist/demo/DemoRegister-BtrMksx6.js +488 -0
  77. package/dist/demo/DemoRegister-BtrMksx6.js.map +1 -0
  78. package/dist/demo/DemoResetPassword-DVXiiiX7.js +341 -0
  79. package/dist/demo/DemoResetPassword-DVXiiiX7.js.map +1 -0
  80. package/dist/demo/DemoSidebar-DWnjYHoP.js +82 -0
  81. package/dist/demo/DemoSidebar-DWnjYHoP.js.map +1 -0
  82. package/dist/demo/DemoTypeForm-P5_VInW2.js +83 -0
  83. package/dist/demo/DemoTypeForm-P5_VInW2.js.map +1 -0
  84. package/dist/demo/DemoVerifyEmail-C_ooC5u8.js +152 -0
  85. package/dist/demo/DemoVerifyEmail-C_ooC5u8.js.map +1 -0
  86. package/dist/demo/IconGoogle-DvmFiEDB.js +58 -0
  87. package/dist/demo/IconGoogle-DvmFiEDB.js.map +1 -0
  88. package/dist/demo/Showcase-vemLuO2t.js +187 -0
  89. package/dist/demo/Showcase-vemLuO2t.js.map +1 -0
  90. package/dist/demo/index.d.ts +97 -0
  91. package/dist/demo/index.d.ts.map +1 -0
  92. package/dist/demo/index.js +121 -0
  93. package/dist/demo/index.js.map +1 -0
  94. package/dist/json/index.d.ts +58 -0
  95. package/dist/json/index.d.ts.map +1 -0
  96. package/dist/json/index.js +325 -0
  97. package/dist/json/index.js.map +1 -0
  98. package/package.json +25 -14
  99. package/src/admin/AdminRouter.ts +23 -20
  100. package/src/admin/MainRouter.ts +2 -2
  101. package/src/admin/components/audits/AdminAudits.tsx +4 -3
  102. package/src/admin/components/jobs/AdminJobs.tsx +2 -2
  103. package/src/admin/components/notifications/AdminNotifications.tsx +2 -2
  104. package/src/admin/components/parameters/AdminParameters.tsx +2 -2
  105. package/src/admin/components/sessions/AdminSessions.tsx +4 -3
  106. package/src/admin/components/shared/AdminResourceHeader.tsx +281 -0
  107. package/src/admin/components/shared/AdminResourceTabs.tsx +94 -0
  108. package/src/admin/components/shared/index.ts +10 -0
  109. package/src/admin/components/users/AdminUserAudits.tsx +4 -3
  110. package/src/admin/components/users/AdminUserCreate.tsx +4 -3
  111. package/src/admin/components/users/AdminUserDetails.tsx +339 -86
  112. package/src/admin/components/users/AdminUserLayout.tsx +165 -113
  113. package/src/admin/components/users/AdminUserSessions.tsx +4 -3
  114. package/src/admin/components/users/AdminUserSettings.tsx +12 -6
  115. package/src/admin/components/users/AdminUsers.tsx +8 -3
  116. package/src/auth/AuthRouter.ts +1 -1
  117. package/src/auth/components/AuthLayout.tsx +1 -1
  118. package/src/auth/components/Login.tsx +1 -1
  119. package/src/auth/components/Register.tsx +2 -1
  120. package/src/auth/components/ResetPassword.tsx +2 -1
  121. package/src/auth/components/VerifyEmail.tsx +2 -1
  122. package/src/auth/components/buttons/UserButton.tsx +1 -1
  123. package/src/core/RootRouter.ts +1 -1
  124. package/src/core/components/buttons/ActionButton.tsx +3 -4
  125. package/src/core/components/form/Control.tsx +12 -1
  126. package/src/core/components/form/ControlNumber.tsx +5 -0
  127. package/src/core/components/form/TypeForm.tsx +3 -2
  128. package/src/core/components/layout/AdminShell.tsx +2 -1
  129. package/src/core/components/layout/AlephaMantineProvider.tsx +7 -2
  130. package/src/core/components/layout/Omnibar.tsx +2 -1
  131. package/src/core/components/layout/Sidebar.tsx +18 -18
  132. package/src/core/index.ts +1 -2
  133. package/src/core/services/DialogService.tsx +0 -17
  134. package/{styles.css → src/core/styles.css} +1 -5
  135. package/src/demo/DemoRouter.ts +123 -0
  136. package/src/demo/components/DemoHome.tsx +29 -0
  137. package/src/demo/components/DemoLayout.tsx +52 -0
  138. package/src/demo/components/auth/DemoLogin.tsx +130 -0
  139. package/src/demo/components/auth/DemoRegister.tsx +144 -0
  140. package/src/demo/components/auth/DemoResetPassword.tsx +69 -0
  141. package/src/demo/components/auth/DemoVerifyEmail.tsx +28 -0
  142. package/src/demo/components/core/DemoDataTable.tsx +174 -0
  143. package/src/demo/components/core/DemoSidebar.tsx +85 -0
  144. package/src/demo/components/core/DemoTypeForm.tsx +69 -0
  145. package/src/demo/components/json/DemoJsonViewer.tsx +128 -0
  146. package/src/demo/components/shared/MacWindow.tsx +105 -0
  147. package/src/demo/components/shared/Showcase.tsx +112 -0
  148. package/src/demo/index.ts +30 -0
  149. package/src/demo/styles.css +0 -0
  150. package/src/json/components/JsonViewer.css +25 -0
  151. package/src/json/components/JsonViewer.tsx +526 -0
  152. package/src/json/extensions/DialogService.tsx +31 -0
  153. package/src/json/index.ts +5 -0
  154. package/src/json/styles.css +1 -0
  155. package/dist/admin/AdminAudits-CwvH8e8c.js.map +0 -1
  156. package/dist/admin/AdminAudits-Dv8Vk_6r.js +0 -3
  157. package/dist/admin/AdminFiles-5CPA3lQk.js +0 -3
  158. package/dist/admin/AdminNotifications-DLjmZWtf.js +0 -3
  159. package/dist/admin/AdminNotifications-DuYy74AN.js.map +0 -1
  160. package/dist/admin/AdminSessions-BCjgJ-93.js.map +0 -1
  161. package/dist/admin/AdminSessions-DEh2uN-4.js +0 -3
  162. package/dist/admin/AdminUserAudits-B_PUXCKC.js.map +0 -1
  163. package/dist/admin/AdminUserCreate-DzfRbGZ4.js.map +0 -1
  164. package/dist/admin/AdminUserDetails-DeTrJm-t.js +0 -221
  165. package/dist/admin/AdminUserDetails-DeTrJm-t.js.map +0 -1
  166. package/dist/admin/AdminUserLayout-CsfrrZkD.js +0 -150
  167. package/dist/admin/AdminUserLayout-CsfrrZkD.js.map +0 -1
  168. package/dist/admin/AdminUserSessions-Bbhcpz4k.js +0 -3
  169. package/dist/admin/AdminUserSessions-DO9H85O-.js.map +0 -1
  170. package/dist/admin/AdminUserSettings-B3jA8g3p.js.map +0 -1
  171. package/dist/admin/AdminUserSettings-CE0xpbQc.js +0 -3
  172. package/dist/admin/AdminUsers-CegGZDhW.js +0 -3
  173. package/dist/admin/AdminUsers-ebbrJBT0.js.map +0 -1
  174. package/dist/auth/AuthLayout-BAZJHzDG.js.map +0 -1
  175. package/dist/auth/Login-CeNZZjrr.js.map +0 -1
  176. package/dist/auth/Login-hQcu1nlu.js +0 -4
  177. package/dist/auth/Register-B6HBNVHS.js +0 -4
  178. package/dist/auth/Register-s4ENeyiE.js.map +0 -1
  179. package/dist/auth/ResetPassword-Cjd-W-Nu.js +0 -3
  180. package/dist/auth/ResetPassword-GLIFkJT7.js.map +0 -1
  181. package/dist/auth/VerifyEmail-Dc9ABKUw.js +0 -3
  182. package/dist/auth/VerifyEmail-R79sSej_.js.map +0 -1
  183. package/src/core/components/data/JsonViewer.tsx +0 -361
@@ -1,25 +1,111 @@
1
- import { useClient, useRouterState } from "@alepha/react";
1
+ import { useClient } from "@alepha/react";
2
2
  import { useForm } from "@alepha/react/form";
3
3
  import { useI18n } from "@alepha/react/i18n";
4
- import { ActionButton, Control, Flex, Text } from "@alepha/ui";
5
- import { Card, Group, Loader, Stack } from "@mantine/core";
6
- import { IconCheck, IconX } from "@tabler/icons-react";
4
+ import { useRouterState } from "@alepha/react/router";
5
+ import { ActionButton, ClipboardButton, Control } from "@alepha/ui";
6
+ import {
7
+ Badge,
8
+ Box,
9
+ Card,
10
+ Center,
11
+ Divider,
12
+ Grid,
13
+ Group,
14
+ Loader,
15
+ Paper,
16
+ SimpleGrid,
17
+ Stack,
18
+ Text,
19
+ ThemeIcon,
20
+ } from "@mantine/core";
21
+ import {
22
+ IconActivity,
23
+ IconCalendar,
24
+ IconCheck,
25
+ IconDevices,
26
+ IconKey,
27
+ IconShieldCheck,
28
+ IconUser,
29
+ IconX,
30
+ } from "@tabler/icons-react";
7
31
  import { t } from "alepha";
8
- import type { UserController, UserEntity } from "alepha/api/users";
9
- import { useEffect, useState } from "react";
32
+ import type { AdminUserController, UserEntity } from "alepha/api/users";
33
+ import { type ReactNode, useEffect, useState } from "react";
10
34
 
11
35
  export interface AdminUserDetailsProps {
12
36
  userRealmName?: string;
13
37
  }
14
38
 
39
+ interface DataRowProps {
40
+ label: string;
41
+ value: ReactNode;
42
+ copyValue?: string;
43
+ }
44
+
45
+ const DataRow = ({ label, value, copyValue }: DataRowProps) => (
46
+ <Group
47
+ justify="space-between"
48
+ py={8}
49
+ wrap="nowrap"
50
+ style={{ borderBottom: "1px solid var(--mantine-color-default-border)" }}
51
+ >
52
+ <Text size="sm" c="dimmed" style={{ flexShrink: 0 }}>
53
+ {label}
54
+ </Text>
55
+ <Group gap={6} wrap="nowrap" style={{ minWidth: 0 }}>
56
+ {typeof value === "string" ? (
57
+ <Text size="sm" fw={500} truncate style={{ maxWidth: 220 }}>
58
+ {value || "—"}
59
+ </Text>
60
+ ) : (
61
+ value
62
+ )}
63
+ {copyValue && (
64
+ <ClipboardButton
65
+ value={copyValue}
66
+ size="xs"
67
+ variant="subtle"
68
+ c="dimmed"
69
+ />
70
+ )}
71
+ </Group>
72
+ </Group>
73
+ );
74
+
75
+ interface StatCardProps {
76
+ icon: ReactNode;
77
+ label: string;
78
+ value: string | number;
79
+ color: string;
80
+ }
81
+
82
+ const StatCard = ({ icon, label, value, color }: StatCardProps) => (
83
+ <Paper p="md" radius="md" withBorder>
84
+ <Group gap="sm">
85
+ <ThemeIcon size="lg" radius="md" variant="light" color={color}>
86
+ {icon}
87
+ </ThemeIcon>
88
+ <Box>
89
+ <Text size="xl" fw={700} lh={1}>
90
+ {value}
91
+ </Text>
92
+ <Text size="xs" c="dimmed">
93
+ {label}
94
+ </Text>
95
+ </Box>
96
+ </Group>
97
+ </Paper>
98
+ );
99
+
15
100
  const AdminUserDetails = (props: AdminUserDetailsProps) => {
16
101
  const state = useRouterState();
17
- const client = useClient<UserController>();
102
+ const client = useClient<AdminUserController>();
18
103
  const { l } = useI18n();
19
104
  const userId = state.params.userId as string;
20
105
 
21
106
  const [user, setUser] = useState<UserEntity | null>(null);
22
107
  const [loading, setLoading] = useState(true);
108
+ const [editing, setEditing] = useState(false);
23
109
 
24
110
  useEffect(() => {
25
111
  const loadUser = async () => {
@@ -53,6 +139,7 @@ const AdminUserDetails = (props: AdminUserDetailsProps) => {
53
139
  body: data,
54
140
  });
55
141
  setUser(updated);
142
+ setEditing(false);
56
143
  },
57
144
  });
58
145
 
@@ -69,111 +156,277 @@ const AdminUserDetails = (props: AdminUserDetailsProps) => {
69
156
 
70
157
  if (loading) {
71
158
  return (
72
- <Flex flex={1} justify="center" align="center">
159
+ <Center flex={1} py="xl">
73
160
  <Loader />
74
- </Flex>
161
+ </Center>
75
162
  );
76
163
  }
77
164
 
78
165
  if (!user) {
79
166
  return (
80
- <Flex flex={1} justify="center" align="center">
81
- <Text c="dimmed">User not found</Text>
82
- </Flex>
167
+ <Center flex={1} py="xl">
168
+ <Stack align="center" gap="xs">
169
+ <IconUser size={48} opacity={0.3} />
170
+ <Text c="dimmed">User not found</Text>
171
+ </Stack>
172
+ </Center>
83
173
  );
84
174
  }
85
175
 
86
- return (
87
- <Flex flex={1} direction="column" gap="md">
88
- <Card withBorder p="lg">
89
- <Stack gap="md">
90
- <Text size="lg" fw={500}>
91
- User Details
92
- </Text>
176
+ const displayName =
177
+ user.firstName && user.lastName
178
+ ? `${user.firstName} ${user.lastName}`
179
+ : user.firstName || user.lastName || null;
93
180
 
94
- <Group gap="xl">
95
- <Stack gap={4}>
96
- <Text size="xs" c="dimmed">
97
- User ID
98
- </Text>
99
- <Text size="sm" ff="monospace">
100
- {user.id}
101
- </Text>
102
- </Stack>
181
+ return (
182
+ <Stack gap="md">
183
+ {/* Stats Overview */}
184
+ <SimpleGrid cols={{ base: 2, sm: 4 }}>
185
+ <StatCard
186
+ icon={<IconDevices size={18} />}
187
+ label="Sessions"
188
+ value={0}
189
+ color="blue"
190
+ />
191
+ <StatCard
192
+ icon={<IconActivity size={18} />}
193
+ label="API Calls"
194
+ value={0}
195
+ color="green"
196
+ />
197
+ <StatCard
198
+ icon={<IconKey size={18} />}
199
+ label="Failed Logins"
200
+ value={0}
201
+ color="orange"
202
+ />
203
+ <StatCard
204
+ icon={<IconShieldCheck size={18} />}
205
+ label="Roles"
206
+ value={user.roles.length}
207
+ color="violet"
208
+ />
209
+ </SimpleGrid>
103
210
 
104
- <Stack gap={4}>
105
- <Text size="xs" c="dimmed">
106
- Username
211
+ <Grid>
212
+ {/* Left Column - Account Details */}
213
+ <Grid.Col span={{ base: 12, md: 6 }}>
214
+ <Card padding={0} radius="md" withBorder h="100%">
215
+ <Group justify="space-between" p="md" pb={0}>
216
+ <Text fw={600} size="sm">
217
+ Account Details
107
218
  </Text>
108
- <Text size="sm">{user.username || "-"}</Text>
109
- </Stack>
219
+ </Group>
220
+ <Box px="md" pb="md">
221
+ <DataRow label="User ID" value={user.id} copyValue={user.id} />
222
+ <DataRow
223
+ label="Username"
224
+ value={user.username || "—"}
225
+ copyValue={user.username}
226
+ />
227
+ <DataRow
228
+ label="Email"
229
+ value={
230
+ <Group gap={6}>
231
+ <Text size="sm" fw={500}>
232
+ {user.email || "—"}
233
+ </Text>
234
+ {user.email && (
235
+ <Badge
236
+ size="xs"
237
+ variant="light"
238
+ color={user.emailVerified ? "green" : "orange"}
239
+ >
240
+ {user.emailVerified ? "verified" : "unverified"}
241
+ </Badge>
242
+ )}
243
+ </Group>
244
+ }
245
+ copyValue={user.email}
246
+ />
247
+ <DataRow
248
+ label="Phone"
249
+ value={user.phoneNumber || "—"}
250
+ copyValue={user.phoneNumber}
251
+ />
252
+ <DataRow label="Realm" value={user.realm} />
253
+ <DataRow
254
+ label="Status"
255
+ value={
256
+ <Group gap={4}>
257
+ <ThemeIcon
258
+ size={16}
259
+ radius="xl"
260
+ color={user.enabled ? "green" : "red"}
261
+ variant="filled"
262
+ >
263
+ {user.enabled ? (
264
+ <IconCheck size={10} />
265
+ ) : (
266
+ <IconX size={10} />
267
+ )}
268
+ </ThemeIcon>
269
+ <Text size="sm" fw={500}>
270
+ {user.enabled ? "Active" : "Disabled"}
271
+ </Text>
272
+ </Group>
273
+ }
274
+ />
275
+ </Box>
276
+ </Card>
277
+ </Grid.Col>
110
278
 
111
- <Stack gap={4}>
112
- <Text size="xs" c="dimmed">
113
- Email Verified
279
+ {/* Right Column - Personal Info */}
280
+ <Grid.Col span={{ base: 12, md: 6 }}>
281
+ <Card padding={0} radius="md" withBorder h="100%">
282
+ <Group justify="space-between" p="md" pb={0}>
283
+ <Text fw={600} size="sm">
284
+ Personal Information
114
285
  </Text>
115
- {user.emailVerified ? (
116
- <Group gap={4}>
117
- <IconCheck size={14} color="var(--mantine-color-green-6)" />
118
- <Text size="sm" c="green">
119
- Verified
120
- </Text>
121
- </Group>
122
- ) : (
123
- <Group gap={4}>
124
- <IconX size={14} color="var(--mantine-color-red-6)" />
125
- <Text size="sm" c="red">
126
- Not Verified
127
- </Text>
128
- </Group>
286
+ {!editing && (
287
+ <ActionButton
288
+ variant="subtle"
289
+ size="xs"
290
+ onClick={() => setEditing(true)}
291
+ >
292
+ Edit
293
+ </ActionButton>
129
294
  )}
130
- </Stack>
295
+ </Group>
296
+
297
+ {editing ? (
298
+ <Box p="md">
299
+ <form {...form.props}>
300
+ <Stack gap="sm">
301
+ <SimpleGrid cols={2}>
302
+ <Control
303
+ title="First Name"
304
+ input={form.input.firstName}
305
+ />
306
+ <Control title="Last Name" input={form.input.lastName} />
307
+ </SimpleGrid>
308
+ <SimpleGrid cols={2}>
309
+ <Control title="Email" input={form.input.email} />
310
+ <Control title="Phone" input={form.input.phoneNumber} />
311
+ </SimpleGrid>
312
+ <Control title="Roles" input={form.input.roles} />
313
+ <Divider />
314
+ <Group justify="flex-end" gap="xs">
315
+ <ActionButton
316
+ variant="subtle"
317
+ size="xs"
318
+ onClick={() => setEditing(false)}
319
+ >
320
+ Cancel
321
+ </ActionButton>
322
+ <ActionButton size="xs" form={form}>
323
+ Save
324
+ </ActionButton>
325
+ </Group>
326
+ </Stack>
327
+ </form>
328
+ </Box>
329
+ ) : (
330
+ <Box px="md" pb="md">
331
+ <DataRow label="First Name" value={user.firstName || "—"} />
332
+ <DataRow label="Last Name" value={user.lastName || "—"} />
333
+ <DataRow label="Display Name" value={displayName || "—"} />
334
+ <DataRow
335
+ label="Roles"
336
+ value={
337
+ user.roles.length > 0 ? (
338
+ <Group gap={4}>
339
+ {user.roles.map((role) => (
340
+ <Badge key={role} size="xs" variant="light">
341
+ {role}
342
+ </Badge>
343
+ ))}
344
+ </Group>
345
+ ) : (
346
+ <Text size="sm" c="dimmed">
347
+ No roles
348
+ </Text>
349
+ )
350
+ }
351
+ />
352
+ </Box>
353
+ )}
354
+ </Card>
355
+ </Grid.Col>
356
+ </Grid>
131
357
 
132
- <Stack gap={4}>
358
+ {/* Timeline */}
359
+ <Card padding={0} radius="md" withBorder>
360
+ <Group justify="space-between" p="md" pb={0}>
361
+ <Text fw={600} size="sm">
362
+ Activity Timeline
363
+ </Text>
364
+ </Group>
365
+ <SimpleGrid cols={{ base: 2, sm: 4 }} p="md">
366
+ <Box>
367
+ <Group gap={6} mb={4}>
368
+ <IconCalendar size={14} style={{ opacity: 0.5 }} />
133
369
  <Text size="xs" c="dimmed">
134
370
  Created
135
371
  </Text>
136
- <Text size="sm">{l(user.createdAt, { date: "medium" })}</Text>
137
- </Stack>
138
-
139
- <Stack gap={4}>
372
+ </Group>
373
+ <Text size="sm" fw={500}>
374
+ {l(user.createdAt, { date: "ll" })}
375
+ </Text>
376
+ <Text size="xs" c="dimmed">
377
+ {l(user.createdAt, { date: "fromNow" })}
378
+ </Text>
379
+ </Box>
380
+ <Box>
381
+ <Group gap={6} mb={4}>
382
+ <IconCalendar size={14} style={{ opacity: 0.5 }} />
140
383
  <Text size="xs" c="dimmed">
141
384
  Updated
142
385
  </Text>
143
- <Text size="sm">{l(user.updatedAt, { date: "medium" })}</Text>
144
- </Stack>
145
- </Group>
146
- </Stack>
147
- </Card>
148
-
149
- <Card withBorder p="lg">
150
- <form {...form.props}>
151
- <Stack gap="md">
152
- <Text size="lg" fw={500}>
153
- Edit User
154
- </Text>
155
-
156
- <Group grow>
157
- <Control title="Email" input={form.input.email} />
158
- <Control title="Phone Number" input={form.input.phoneNumber} />
159
386
  </Group>
160
-
161
- <Group grow>
162
- <Control title="First Name" input={form.input.firstName} />
163
- <Control title="Last Name" input={form.input.lastName} />
387
+ <Text size="sm" fw={500}>
388
+ {l(user.updatedAt, { date: "ll" })}
389
+ </Text>
390
+ <Text size="xs" c="dimmed">
391
+ {l(user.updatedAt, { date: "fromNow" })}
392
+ </Text>
393
+ </Box>
394
+ <Box>
395
+ <Group gap={6} mb={4}>
396
+ <IconDevices size={14} style={{ opacity: 0.5 }} />
397
+ <Text size="xs" c="dimmed">
398
+ Last Login
399
+ </Text>
164
400
  </Group>
165
-
166
- <Control title="Roles" input={form.input.roles} />
167
-
168
- <Control title="Enabled" input={form.input.enabled} />
169
-
170
- <Group>
171
- <ActionButton form={form}>Save Changes</ActionButton>
401
+ <Text size="sm" c="dimmed">
402
+
403
+ </Text>
404
+ </Box>
405
+ <Box>
406
+ <Group gap={6} mb={4}>
407
+ <IconCheck size={14} style={{ opacity: 0.5 }} />
408
+ <Text size="xs" c="dimmed">
409
+ Email Verified
410
+ </Text>
172
411
  </Group>
173
- </Stack>
174
- </form>
412
+ {user.emailVerified ? (
413
+ <>
414
+ <Text size="sm" fw={500}>
415
+ {l(user.updatedAt, { date: "ll" })}
416
+ </Text>
417
+ <Text size="xs" c="dimmed">
418
+ {l(user.updatedAt, { date: "fromNow" })}
419
+ </Text>
420
+ </>
421
+ ) : (
422
+ <Text size="sm" c="dimmed">
423
+ Not verified
424
+ </Text>
425
+ )}
426
+ </Box>
427
+ </SimpleGrid>
175
428
  </Card>
176
- </Flex>
429
+ </Stack>
177
430
  );
178
431
  };
179
432