@alepha/ui 0.14.2 → 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.
- package/dist/admin/AdminAudits-DIrCCPk3.js.map +1 -1
- package/dist/admin/AdminNotifications-cIbywWKi.js.map +1 -1
- package/dist/admin/AdminParameters-D-q3Qmhv.js.map +1 -1
- package/dist/admin/AdminSessions-vOgkrQ2U.js.map +1 -1
- package/dist/admin/AdminUserAudits-CSsN1fIC.js.map +1 -1
- package/dist/admin/AdminUserCreate-B72nu-3W.js.map +1 -1
- package/dist/admin/AdminUserDetails-CKM2IEMr.js +475 -0
- package/dist/admin/AdminUserDetails-CKM2IEMr.js.map +1 -0
- package/dist/admin/{AdminUserDetails-z1y8kJeB.js → AdminUserDetails-Zib_B6Al.js} +1 -1
- package/dist/admin/{AdminUserLayout-DyQYacQQ.js → AdminUserLayout-BNBOEiAO.js} +1 -1
- package/dist/admin/AdminUserLayout-D7En9UBq.js +334 -0
- package/dist/admin/AdminUserLayout-D7En9UBq.js.map +1 -0
- package/dist/admin/AdminUserSessions-DEaGu6n6.js.map +1 -1
- package/dist/admin/{AdminUserSettings-CR7MxX_R.js → AdminUserSettings-Di73D7g2.js} +6 -5
- package/dist/admin/AdminUserSettings-Di73D7g2.js.map +1 -0
- package/dist/admin/AdminUserSettings-yI-JECf5.js +3 -0
- package/dist/admin/AdminUsers-BnGIRvmV.js.map +1 -1
- package/dist/admin/index.d.ts +10 -10
- package/dist/admin/index.d.ts.map +1 -1
- package/dist/admin/index.js +17 -17
- package/dist/admin/index.js.map +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +6 -5
- package/dist/core/index.js.map +1 -1
- package/package.json +11 -11
- package/src/admin/AdminRouter.ts +22 -19
- package/src/admin/MainRouter.ts +1 -1
- package/src/admin/components/audits/AdminAudits.tsx +2 -2
- package/src/admin/components/jobs/AdminJobs.tsx +2 -2
- package/src/admin/components/notifications/AdminNotifications.tsx +2 -2
- package/src/admin/components/parameters/AdminParameters.tsx +2 -2
- package/src/admin/components/sessions/AdminSessions.tsx +2 -2
- package/src/admin/components/shared/AdminResourceHeader.tsx +281 -0
- package/src/admin/components/shared/AdminResourceTabs.tsx +94 -0
- package/src/admin/components/shared/index.ts +10 -0
- package/src/admin/components/users/AdminUserAudits.tsx +2 -2
- package/src/admin/components/users/AdminUserCreate.tsx +2 -2
- package/src/admin/components/users/AdminUserDetails.tsx +337 -85
- package/src/admin/components/users/AdminUserLayout.tsx +164 -108
- package/src/admin/components/users/AdminUserSessions.tsx +2 -2
- package/src/admin/components/users/AdminUserSettings.tsx +10 -5
- package/src/admin/components/users/AdminUsers.tsx +6 -2
- package/src/core/components/form/TypeForm.tsx +3 -2
- package/src/core/components/layout/AlephaMantineProvider.tsx +5 -1
- package/src/core/components/layout/Sidebar.tsx +9 -6
- package/dist/admin/AdminUserDetails-BCt8Su-4.js +0 -222
- package/dist/admin/AdminUserDetails-BCt8Su-4.js.map +0 -1
- package/dist/admin/AdminUserLayout-Ck0GLRE5.js +0 -151
- package/dist/admin/AdminUserLayout-Ck0GLRE5.js.map +0 -1
- package/dist/admin/AdminUserSettings-CE66UTIP.js +0 -3
- package/dist/admin/AdminUserSettings-CR7MxX_R.js.map +0 -1
|
@@ -2,25 +2,110 @@ import { useClient } from "@alepha/react";
|
|
|
2
2
|
import { useForm } from "@alepha/react/form";
|
|
3
3
|
import { useI18n } from "@alepha/react/i18n";
|
|
4
4
|
import { useRouterState } from "@alepha/react/router";
|
|
5
|
-
import { ActionButton,
|
|
6
|
-
import {
|
|
7
|
-
|
|
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";
|
|
8
31
|
import { t } from "alepha";
|
|
9
|
-
import type {
|
|
10
|
-
import { useEffect, useState } from "react";
|
|
32
|
+
import type { AdminUserController, UserEntity } from "alepha/api/users";
|
|
33
|
+
import { type ReactNode, useEffect, useState } from "react";
|
|
11
34
|
|
|
12
35
|
export interface AdminUserDetailsProps {
|
|
13
36
|
userRealmName?: string;
|
|
14
37
|
}
|
|
15
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
|
+
|
|
16
100
|
const AdminUserDetails = (props: AdminUserDetailsProps) => {
|
|
17
101
|
const state = useRouterState();
|
|
18
|
-
const client = useClient<
|
|
102
|
+
const client = useClient<AdminUserController>();
|
|
19
103
|
const { l } = useI18n();
|
|
20
104
|
const userId = state.params.userId as string;
|
|
21
105
|
|
|
22
106
|
const [user, setUser] = useState<UserEntity | null>(null);
|
|
23
107
|
const [loading, setLoading] = useState(true);
|
|
108
|
+
const [editing, setEditing] = useState(false);
|
|
24
109
|
|
|
25
110
|
useEffect(() => {
|
|
26
111
|
const loadUser = async () => {
|
|
@@ -54,6 +139,7 @@ const AdminUserDetails = (props: AdminUserDetailsProps) => {
|
|
|
54
139
|
body: data,
|
|
55
140
|
});
|
|
56
141
|
setUser(updated);
|
|
142
|
+
setEditing(false);
|
|
57
143
|
},
|
|
58
144
|
});
|
|
59
145
|
|
|
@@ -70,111 +156,277 @@ const AdminUserDetails = (props: AdminUserDetailsProps) => {
|
|
|
70
156
|
|
|
71
157
|
if (loading) {
|
|
72
158
|
return (
|
|
73
|
-
<
|
|
159
|
+
<Center flex={1} py="xl">
|
|
74
160
|
<Loader />
|
|
75
|
-
</
|
|
161
|
+
</Center>
|
|
76
162
|
);
|
|
77
163
|
}
|
|
78
164
|
|
|
79
165
|
if (!user) {
|
|
80
166
|
return (
|
|
81
|
-
<
|
|
82
|
-
<
|
|
83
|
-
|
|
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>
|
|
84
173
|
);
|
|
85
174
|
}
|
|
86
175
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
<Text size="lg" fw={500}>
|
|
92
|
-
User Details
|
|
93
|
-
</Text>
|
|
176
|
+
const displayName =
|
|
177
|
+
user.firstName && user.lastName
|
|
178
|
+
? `${user.firstName} ${user.lastName}`
|
|
179
|
+
: user.firstName || user.lastName || null;
|
|
94
180
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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>
|
|
104
210
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
|
108
218
|
</Text>
|
|
109
|
-
|
|
110
|
-
|
|
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>
|
|
111
278
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
|
115
285
|
</Text>
|
|
116
|
-
{
|
|
117
|
-
<
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
<Group gap={4}>
|
|
125
|
-
<IconX size={14} color="var(--mantine-color-red-6)" />
|
|
126
|
-
<Text size="sm" c="red">
|
|
127
|
-
Not Verified
|
|
128
|
-
</Text>
|
|
129
|
-
</Group>
|
|
286
|
+
{!editing && (
|
|
287
|
+
<ActionButton
|
|
288
|
+
variant="subtle"
|
|
289
|
+
size="xs"
|
|
290
|
+
onClick={() => setEditing(true)}
|
|
291
|
+
>
|
|
292
|
+
Edit
|
|
293
|
+
</ActionButton>
|
|
130
294
|
)}
|
|
131
|
-
</
|
|
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>
|
|
132
357
|
|
|
133
|
-
|
|
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 }} />
|
|
134
369
|
<Text size="xs" c="dimmed">
|
|
135
370
|
Created
|
|
136
371
|
</Text>
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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 }} />
|
|
141
383
|
<Text size="xs" c="dimmed">
|
|
142
384
|
Updated
|
|
143
385
|
</Text>
|
|
144
|
-
<Text size="sm">{l(user.updatedAt, { date: "medium" })}</Text>
|
|
145
|
-
</Stack>
|
|
146
|
-
</Group>
|
|
147
|
-
</Stack>
|
|
148
|
-
</Card>
|
|
149
|
-
|
|
150
|
-
<Card withBorder p="lg">
|
|
151
|
-
<form {...form.props}>
|
|
152
|
-
<Stack gap="md">
|
|
153
|
-
<Text size="lg" fw={500}>
|
|
154
|
-
Edit User
|
|
155
|
-
</Text>
|
|
156
|
-
|
|
157
|
-
<Group grow>
|
|
158
|
-
<Control title="Email" input={form.input.email} />
|
|
159
|
-
<Control title="Phone Number" input={form.input.phoneNumber} />
|
|
160
386
|
</Group>
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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>
|
|
165
400
|
</Group>
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
<Group>
|
|
172
|
-
<
|
|
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>
|
|
173
411
|
</Group>
|
|
174
|
-
|
|
175
|
-
|
|
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>
|
|
176
428
|
</Card>
|
|
177
|
-
</
|
|
429
|
+
</Stack>
|
|
178
430
|
);
|
|
179
431
|
};
|
|
180
432
|
|