@burdenoff/microfe-auth 2026.522.1 → 2026.523.1
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UserProfilePage.d.ts","sourceRoot":"","sources":["../../../src/auth/pages/UserProfilePage.tsx"],"names":[],"mappings":"AA4BA;;GAEG;AACH,wBAAgB,eAAe,
|
|
1
|
+
{"version":3,"file":"UserProfilePage.d.ts","sourceRoot":"","sources":["../../../src/auth/pages/UserProfilePage.tsx"],"names":[],"mappings":"AA4BA;;GAEG;AACH,wBAAgB,eAAe,4CA+qB9B"}
|
|
@@ -15,48 +15,58 @@ function x() {
|
|
|
15
15
|
let { t: x } = h(), S = (e, t) => {
|
|
16
16
|
let n = x(e);
|
|
17
17
|
return n === e ? t : n;
|
|
18
|
-
}, C = m(), w = b(), T = e((e) => e.isAuthenticated), E = e((e) => e.user), D = e((e) => e.setUser), { updateCurrentUserProfile: O, isLoading: k } = t(), A = d(), j = d(), M = d(), N = d(), P = d(), F = y("workspace"), [
|
|
18
|
+
}, C = m(), w = b(), T = e((e) => e.isAuthenticated), E = e((e) => e.user), D = e((e) => e.setUser), { updateCurrentUserProfile: O, isLoading: k } = t(), A = d(), j = d(), M = d(), N = d(), P = d(), F = e((e) => e.currentWorkspaceId), I = y("workspace"), [L] = l({ client: I }), [R] = c({ client: I }), z = f(null), [B, V] = p(!1), H = async (e) => {
|
|
19
19
|
let t = e.target.files?.[0];
|
|
20
|
-
if (t)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
if (!t) return;
|
|
21
|
+
if (!t.type.startsWith("image/")) {
|
|
22
|
+
J(S("auth.profile.invalidImageType", "Please select an image file"));
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (!F) {
|
|
26
|
+
J(S("auth.profile.noWorkspace", "Please select a workspace before uploading a profile picture"));
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
V(!0), J(null);
|
|
30
|
+
let n = { "x-workspace-id": F };
|
|
31
|
+
try {
|
|
32
|
+
let e = t.name.split(".").pop()?.toLowerCase() ?? "", r = await L({
|
|
33
|
+
variables: { input: {
|
|
28
34
|
fileName: t.name,
|
|
29
35
|
fileSize: t.size.toString(),
|
|
30
36
|
mimeType: t.type,
|
|
31
37
|
extension: e
|
|
32
|
-
} }
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
38
|
+
} },
|
|
39
|
+
context: { headers: n }
|
|
40
|
+
}), i = r.data?.initiateUpload.session, a = r.data?.initiateUpload.uploadUrl;
|
|
41
|
+
if (!i || !a) throw Error("Failed to initiate upload");
|
|
42
|
+
if (!(await fetch(a, {
|
|
43
|
+
method: "PUT",
|
|
44
|
+
headers: { "Content-Type": t.type },
|
|
45
|
+
body: t
|
|
46
|
+
})).ok) throw Error("Failed to upload file");
|
|
47
|
+
let o = (await R({
|
|
48
|
+
variables: { input: { sessionId: i.id } },
|
|
49
|
+
context: { headers: n }
|
|
50
|
+
})).data?.completeUpload.file?.downloadUrl;
|
|
51
|
+
if (!o) throw Error("Upload succeeded but no URL returned");
|
|
52
|
+
await O({ avatar: o }), E && D({
|
|
53
|
+
...E,
|
|
54
|
+
avatar: o
|
|
55
|
+
}), w.updateUser({ avatar: o }), X(S("auth.profile.avatarUpdated", "Profile picture updated!"));
|
|
56
|
+
} catch (e) {
|
|
57
|
+
J(e instanceof Error ? e.message : S("auth.profile.avatarFailed", "Failed to upload picture"));
|
|
58
|
+
} finally {
|
|
59
|
+
V(!1), z.current && (z.current.value = "");
|
|
50
60
|
}
|
|
51
|
-
}, [
|
|
61
|
+
}, [U, W] = p(!1), [G, K] = p({
|
|
52
62
|
username: "",
|
|
53
63
|
firstName: "",
|
|
54
64
|
lastName: "",
|
|
55
65
|
name: "",
|
|
56
66
|
phoneNumber: ""
|
|
57
|
-
}), [
|
|
67
|
+
}), [q, J] = p(null), [Y, X] = p(null);
|
|
58
68
|
return u(() => {
|
|
59
|
-
E &&
|
|
69
|
+
E && K({
|
|
60
70
|
username: E.username || "",
|
|
61
71
|
firstName: E.firstName || "",
|
|
62
72
|
lastName: E.lastName || "",
|
|
@@ -101,22 +111,22 @@ function x() {
|
|
|
101
111
|
children: S("auth.profile.viewAndManage", "View and manage your account information")
|
|
102
112
|
})]
|
|
103
113
|
}),
|
|
104
|
-
|
|
114
|
+
Y && /* @__PURE__ */ v("div", {
|
|
105
115
|
className: "mb-6 flex items-center gap-3 p-4 rounded-xl bg-[var(--color-status-success-bg-subtle)] border border-[var(--color-status-success-border)]",
|
|
106
116
|
children: [
|
|
107
117
|
/* @__PURE__ */ _(i, { className: "w-5 h-5 text-[var(--color-status-success-text)] flex-shrink-0" }),
|
|
108
118
|
/* @__PURE__ */ _("p", {
|
|
109
119
|
className: "text-[var(--color-status-success-text)]",
|
|
110
|
-
children:
|
|
120
|
+
children: Y
|
|
111
121
|
}),
|
|
112
122
|
/* @__PURE__ */ _("button", {
|
|
113
|
-
onClick: () =>
|
|
123
|
+
onClick: () => X(null),
|
|
114
124
|
className: "ml-auto text-sm text-[var(--color-status-success-text)] hover:underline transition-colors duration-200",
|
|
115
125
|
children: S("auth.profile.dismiss", "Dismiss")
|
|
116
126
|
})
|
|
117
127
|
]
|
|
118
128
|
}),
|
|
119
|
-
|
|
129
|
+
q && /* @__PURE__ */ v("div", {
|
|
120
130
|
className: "mb-6 flex items-start gap-3 p-4 rounded-xl bg-[var(--color-status-error-bg-subtle)] border border-[var(--color-status-error-border)]",
|
|
121
131
|
children: [
|
|
122
132
|
/* @__PURE__ */ _(r, { className: "w-5 h-5 text-[var(--color-status-error-text)] flex-shrink-0 mt-0.5" }),
|
|
@@ -124,11 +134,11 @@ function x() {
|
|
|
124
134
|
className: "flex-1",
|
|
125
135
|
children: /* @__PURE__ */ _("p", {
|
|
126
136
|
className: "text-sm text-[var(--color-status-error-text)]",
|
|
127
|
-
children:
|
|
137
|
+
children: q
|
|
128
138
|
})
|
|
129
139
|
}),
|
|
130
140
|
/* @__PURE__ */ _("button", {
|
|
131
|
-
onClick: () =>
|
|
141
|
+
onClick: () => J(null),
|
|
132
142
|
className: "text-sm text-[var(--color-status-error-text)] hover:underline transition-colors duration-200",
|
|
133
143
|
children: S("auth.profile.dismiss", "Dismiss")
|
|
134
144
|
})
|
|
@@ -153,11 +163,11 @@ function x() {
|
|
|
153
163
|
}),
|
|
154
164
|
/* @__PURE__ */ _("button", {
|
|
155
165
|
type: "button",
|
|
156
|
-
onClick: () =>
|
|
157
|
-
disabled:
|
|
166
|
+
onClick: () => z.current?.click(),
|
|
167
|
+
disabled: B,
|
|
158
168
|
"aria-label": S("auth.profile.changeAvatar", "Change profile picture"),
|
|
159
169
|
className: "absolute inset-0 rounded-full flex items-center justify-center bg-black/40 opacity-0 group-hover:opacity-100 transition-opacity duration-200 cursor-pointer",
|
|
160
|
-
children:
|
|
170
|
+
children: B ? /* @__PURE__ */ _(o, { className: "w-6 h-6 text-white animate-spin" }) : /* @__PURE__ */ v("svg", {
|
|
161
171
|
className: "w-6 h-6 text-white",
|
|
162
172
|
fill: "none",
|
|
163
173
|
viewBox: "0 0 24 24",
|
|
@@ -176,11 +186,11 @@ function x() {
|
|
|
176
186
|
})
|
|
177
187
|
}),
|
|
178
188
|
/* @__PURE__ */ _("input", {
|
|
179
|
-
ref:
|
|
189
|
+
ref: z,
|
|
180
190
|
type: "file",
|
|
181
191
|
accept: "image/*",
|
|
182
192
|
className: "hidden",
|
|
183
|
-
onChange: (e) => void
|
|
193
|
+
onChange: (e) => void H(e),
|
|
184
194
|
"aria-hidden": "true"
|
|
185
195
|
})
|
|
186
196
|
]
|
|
@@ -210,19 +220,19 @@ function x() {
|
|
|
210
220
|
})
|
|
211
221
|
}), /* @__PURE__ */ _("div", {
|
|
212
222
|
className: "p-6",
|
|
213
|
-
children:
|
|
223
|
+
children: U ? /* @__PURE__ */ v("form", {
|
|
214
224
|
onSubmit: async (e) => {
|
|
215
|
-
e.preventDefault(),
|
|
225
|
+
e.preventDefault(), J(null), X(null);
|
|
216
226
|
try {
|
|
217
227
|
await O({
|
|
218
|
-
username:
|
|
219
|
-
firstName:
|
|
220
|
-
lastName:
|
|
221
|
-
name:
|
|
222
|
-
phoneNumber:
|
|
223
|
-
}),
|
|
228
|
+
username: G.username || void 0,
|
|
229
|
+
firstName: G.firstName || void 0,
|
|
230
|
+
lastName: G.lastName || void 0,
|
|
231
|
+
name: G.name || void 0,
|
|
232
|
+
phoneNumber: G.phoneNumber || void 0
|
|
233
|
+
}), X(S("auth.profile.updateSuccess", "Profile updated successfully!")), W(!1);
|
|
224
234
|
} catch (e) {
|
|
225
|
-
|
|
235
|
+
J(e instanceof Error ? e.message : S("auth.profile.updateFailed", "Failed to update profile"));
|
|
226
236
|
}
|
|
227
237
|
},
|
|
228
238
|
className: "space-y-6",
|
|
@@ -244,9 +254,9 @@ function x() {
|
|
|
244
254
|
}), /* @__PURE__ */ _("input", {
|
|
245
255
|
id: A,
|
|
246
256
|
type: "text",
|
|
247
|
-
value:
|
|
248
|
-
onChange: (e) =>
|
|
249
|
-
...
|
|
257
|
+
value: G.username,
|
|
258
|
+
onChange: (e) => K({
|
|
259
|
+
...G,
|
|
250
260
|
username: e.target.value
|
|
251
261
|
}),
|
|
252
262
|
className: "block w-full pl-[3.5rem] pr-4 py-3 border border-[var(--color-border-default)] rounded-xl bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all duration-300",
|
|
@@ -260,9 +270,9 @@ function x() {
|
|
|
260
270
|
}), /* @__PURE__ */ _("input", {
|
|
261
271
|
id: j,
|
|
262
272
|
type: "text",
|
|
263
|
-
value:
|
|
264
|
-
onChange: (e) =>
|
|
265
|
-
...
|
|
273
|
+
value: G.name,
|
|
274
|
+
onChange: (e) => K({
|
|
275
|
+
...G,
|
|
266
276
|
name: e.target.value
|
|
267
277
|
}),
|
|
268
278
|
className: "block w-full px-4 py-3 border border-[var(--color-border-default)] rounded-xl bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all duration-300",
|
|
@@ -275,9 +285,9 @@ function x() {
|
|
|
275
285
|
}), /* @__PURE__ */ _("input", {
|
|
276
286
|
id: M,
|
|
277
287
|
type: "text",
|
|
278
|
-
value:
|
|
279
|
-
onChange: (e) =>
|
|
280
|
-
...
|
|
288
|
+
value: G.firstName,
|
|
289
|
+
onChange: (e) => K({
|
|
290
|
+
...G,
|
|
281
291
|
firstName: e.target.value
|
|
282
292
|
}),
|
|
283
293
|
className: "block w-full px-4 py-3 border border-[var(--color-border-default)] rounded-xl bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all duration-300",
|
|
@@ -290,9 +300,9 @@ function x() {
|
|
|
290
300
|
}), /* @__PURE__ */ _("input", {
|
|
291
301
|
id: N,
|
|
292
302
|
type: "text",
|
|
293
|
-
value:
|
|
294
|
-
onChange: (e) =>
|
|
295
|
-
...
|
|
303
|
+
value: G.lastName,
|
|
304
|
+
onChange: (e) => K({
|
|
305
|
+
...G,
|
|
296
306
|
lastName: e.target.value
|
|
297
307
|
}),
|
|
298
308
|
className: "block w-full px-4 py-3 border border-[var(--color-border-default)] rounded-xl bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all duration-300",
|
|
@@ -307,9 +317,9 @@ function x() {
|
|
|
307
317
|
}), /* @__PURE__ */ _("input", {
|
|
308
318
|
id: P,
|
|
309
319
|
type: "tel",
|
|
310
|
-
value:
|
|
311
|
-
onChange: (e) =>
|
|
312
|
-
...
|
|
320
|
+
value: G.phoneNumber,
|
|
321
|
+
onChange: (e) => K({
|
|
322
|
+
...G,
|
|
313
323
|
phoneNumber: e.target.value
|
|
314
324
|
}),
|
|
315
325
|
className: "block w-full px-4 py-3 border border-[var(--color-border-default)] rounded-xl bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all duration-300",
|
|
@@ -327,13 +337,13 @@ function x() {
|
|
|
327
337
|
}), /* @__PURE__ */ _("button", {
|
|
328
338
|
type: "button",
|
|
329
339
|
onClick: () => {
|
|
330
|
-
E &&
|
|
340
|
+
E && K({
|
|
331
341
|
username: E.username || "",
|
|
332
342
|
firstName: E.firstName || "",
|
|
333
343
|
lastName: E.lastName || "",
|
|
334
344
|
name: E.name || "",
|
|
335
345
|
phoneNumber: E.phoneNumber || ""
|
|
336
|
-
}),
|
|
346
|
+
}), W(!1), J(null);
|
|
337
347
|
},
|
|
338
348
|
className: "px-6 py-3 rounded-xl border border-[var(--color-border-default)] text-[var(--color-text-secondary)] font-medium hover:bg-[var(--color-bg-muted)] transition-colors duration-200",
|
|
339
349
|
children: S("auth.profile.cancel", "Cancel")
|
|
@@ -455,7 +465,7 @@ function x() {
|
|
|
455
465
|
}), /* @__PURE__ */ v("div", {
|
|
456
466
|
className: "flex gap-3 pt-6 mt-6 border-t border-[var(--color-border-default)]",
|
|
457
467
|
children: [/* @__PURE__ */ _("button", {
|
|
458
|
-
onClick: () =>
|
|
468
|
+
onClick: () => W(!0),
|
|
459
469
|
className: "auth-primary-button px-6 py-3 font-medium",
|
|
460
470
|
children: S("auth.profile.editProfile", "Edit Profile")
|
|
461
471
|
}), /* @__PURE__ */ _("button", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UserProfilePage.js","names":[],"sources":["../../../src/auth/pages/UserProfilePage.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useId } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { useAuth as useShellAuth } from \"@burdenoff/fe-libs/shared/providers/shell/AuthProvider\";\nimport { useNavigate } from \"react-router-dom\";\nimport { useUserOperations } from \"../hooks\";\nimport { useAuthStore } from \"../store/authStore\";\nimport { AuthLayout } from \"../components/AuthLayout\";\nimport {\n SpinnerIcon,\n AlertIcon,\n UserIcon,\n EmailIcon,\n CheckIcon,\n} from \"../components/AuthIcons\";\nimport {\n useInitiateAvatarUploadMutation,\n useCompleteAvatarUploadMutation,\n} from \"../../generated/wspace-operations\";\nimport { useGatewayClient } from \"@burdenoff/fe-libs/shared/graphql\";\n\ninterface ProfileFormData {\n username: string;\n firstName: string;\n lastName: string;\n name: string;\n phoneNumber: string;\n}\n\n/**\n * User Profile page for viewing and editing own profile\n */\nexport function UserProfilePage() {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n\n const navigate = useNavigate();\n const shellAuth = useShellAuth();\n const isAuthenticated = useAuthStore((state) => state.isAuthenticated);\n const currentUser = useAuthStore((state) => state.user);\n const setStoreUser = useAuthStore((state) => state.setUser);\n const { updateCurrentUserProfile, isLoading } = useUserOperations();\n\n const usernameId = useId();\n const displayNameId = useId();\n const firstNameId = useId();\n const lastNameId = useId();\n const phoneNumberId = useId();\n\n const wspaceClient = useGatewayClient(\"workspace\");\n const [initiateUpload] = useInitiateAvatarUploadMutation({\n client: wspaceClient,\n });\n const [completeUpload] = useCompleteAvatarUploadMutation({\n client: wspaceClient,\n });\n const fileInputRef = useRef<HTMLInputElement>(null);\n const [isUploadingAvatar, setIsUploadingAvatar] = useState(false);\n\n const handleAvatarUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n if (!file.type.startsWith(\"image/\")) {\n setError(\n tr(\"auth.profile.invalidImageType\", \"Please select an image file\"),\n );\n return;\n }\n setIsUploadingAvatar(true);\n setError(null);\n try {\n const extension = file.name.split(\".\").pop()?.toLowerCase() ?? \"\";\n const initiateResult = await initiateUpload({\n variables: {\n input: {\n fileName: file.name,\n fileSize: file.size.toString(),\n mimeType: file.type,\n extension,\n },\n },\n });\n const session = initiateResult.data?.initiateUpload.session;\n const uploadUrl = initiateResult.data?.initiateUpload.uploadUrl;\n if (!session || !uploadUrl) throw new Error(\"Failed to initiate upload\");\n\n const uploadResp = await fetch(uploadUrl, {\n method: \"PUT\",\n headers: { \"Content-Type\": file.type },\n body: file,\n });\n if (!uploadResp.ok) throw new Error(\"Failed to upload file\");\n\n const completeResult = await completeUpload({\n variables: { input: { sessionId: session.id } },\n });\n const avatarUrl = completeResult.data?.completeUpload.file?.downloadUrl;\n if (!avatarUrl) throw new Error(\"Upload succeeded but no URL returned\");\n\n await updateCurrentUserProfile({ avatar: avatarUrl });\n // Update both the local authStore and the shell AuthProvider so the nav\n // bar avatar reflects the change immediately without a page reload.\n if (currentUser) {\n setStoreUser({ ...currentUser, avatar: avatarUrl });\n }\n shellAuth.updateUser({ avatar: avatarUrl });\n setSuccessMessage(\n tr(\"auth.profile.avatarUpdated\", \"Profile picture updated!\"),\n );\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : tr(\"auth.profile.avatarFailed\", \"Failed to upload picture\"),\n );\n } finally {\n setIsUploadingAvatar(false);\n if (fileInputRef.current) fileInputRef.current.value = \"\";\n }\n };\n\n const [isEditing, setIsEditing] = useState(false);\n const [formData, setFormData] = useState<ProfileFormData>({\n username: \"\",\n firstName: \"\",\n lastName: \"\",\n name: \"\",\n phoneNumber: \"\",\n });\n const [error, setError] = useState<string | null>(null);\n const [successMessage, setSuccessMessage] = useState<string | null>(null);\n\n // Populate form with current user data\n useEffect(() => {\n if (currentUser) {\n setFormData({\n username: currentUser.username || \"\",\n firstName: currentUser.firstName || \"\",\n lastName: currentUser.lastName || \"\",\n name: currentUser.name || \"\",\n phoneNumber: currentUser.phoneNumber || \"\",\n });\n }\n }, [currentUser]);\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n setSuccessMessage(null);\n\n try {\n await updateCurrentUserProfile({\n username: formData.username || undefined,\n firstName: formData.firstName || undefined,\n lastName: formData.lastName || undefined,\n name: formData.name || undefined,\n phoneNumber: formData.phoneNumber || undefined,\n });\n setSuccessMessage(\n tr(\"auth.profile.updateSuccess\", \"Profile updated successfully!\"),\n );\n setIsEditing(false);\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : tr(\"auth.profile.updateFailed\", \"Failed to update profile\"),\n );\n }\n };\n\n const cancelEdit = () => {\n if (currentUser) {\n setFormData({\n username: currentUser.username || \"\",\n firstName: currentUser.firstName || \"\",\n lastName: currentUser.lastName || \"\",\n name: currentUser.name || \"\",\n phoneNumber: currentUser.phoneNumber || \"\",\n });\n }\n setIsEditing(false);\n setError(null);\n };\n\n // Not authenticated\n if (!isAuthenticated || !currentUser) {\n return (\n <AuthLayout\n title={tr(\"auth.profile.title\", \"Profile\")}\n subtitle={tr(\"auth.profile.subtitle\", \"View and manage your profile\")}\n >\n <div className=\"text-center py-12\">\n <div className=\"w-16 h-16 mx-auto mb-4 rounded-full bg-[var(--color-status-warning-bg-subtle)] flex items-center justify-center\">\n <AlertIcon className=\"w-8 h-8 text-[var(--color-status-warning-text)]\" />\n </div>\n <h2 className=\"text-xl font-semibold text-[var(--color-text-primary)] mb-2\">\n {tr(\"auth.profile.authRequired\", \"Authentication Required\")}\n </h2>\n <p className=\"text-[var(--color-text-secondary)] mb-6\">\n {tr(\n \"auth.profile.signInToView\",\n \"Please sign in to view your profile\",\n )}\n </p>\n <button\n onClick={() => navigate(\"/auth/login\")}\n className=\"auth-primary-button px-6 py-3 font-semibold\"\n >\n {tr(\"auth.profile.signIn\", \"Sign In\")}\n </button>\n </div>\n </AuthLayout>\n );\n }\n\n return (\n <div className=\"max-w-4xl mx-auto p-6\">\n {/* Header */}\n <div className=\"mb-8\">\n <h1 className=\"text-3xl font-semibold text-[var(--color-text-primary)]\">\n {tr(\"auth.profile.myProfile\", \"My Profile\")}\n </h1>\n <p className=\"text-[var(--color-text-secondary)] mt-2\">\n {tr(\n \"auth.profile.viewAndManage\",\n \"View and manage your account information\",\n )}\n </p>\n </div>\n\n {/* Success Message */}\n {successMessage && (\n <div className=\"mb-6 flex items-center gap-3 p-4 rounded-xl bg-[var(--color-status-success-bg-subtle)] border border-[var(--color-status-success-border)]\">\n <CheckIcon className=\"w-5 h-5 text-[var(--color-status-success-text)] flex-shrink-0\" />\n <p className=\"text-[var(--color-status-success-text)]\">\n {successMessage}\n </p>\n <button\n onClick={() => setSuccessMessage(null)}\n className=\"ml-auto text-sm text-[var(--color-status-success-text)] hover:underline transition-colors duration-200\"\n >\n {tr(\"auth.profile.dismiss\", \"Dismiss\")}\n </button>\n </div>\n )}\n\n {/* Error Message */}\n {error && (\n <div className=\"mb-6 flex items-start gap-3 p-4 rounded-xl bg-[var(--color-status-error-bg-subtle)] border border-[var(--color-status-error-border)]\">\n <AlertIcon className=\"w-5 h-5 text-[var(--color-status-error-text)] flex-shrink-0 mt-0.5\" />\n <div className=\"flex-1\">\n <p className=\"text-sm text-[var(--color-status-error-text)]\">\n {error}\n </p>\n </div>\n <button\n onClick={() => setError(null)}\n className=\"text-sm text-[var(--color-status-error-text)] hover:underline transition-colors duration-200\"\n >\n {tr(\"auth.profile.dismiss\", \"Dismiss\")}\n </button>\n </div>\n )}\n\n {/* Profile Card */}\n <div className=\"rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] shadow-sm overflow-hidden\">\n {/* Profile Header */}\n <div className=\"auth-hero-card p-6\">\n <div className=\"flex items-center gap-4\">\n <div className=\"relative group\">\n {currentUser.avatar ? (\n <img\n src={currentUser.avatar}\n alt={tr(\"auth.profile.avatarAlt\", \"Profile picture\")}\n className=\"w-20 h-20 rounded-full object-cover shadow-lg\"\n />\n ) : (\n <div className=\"w-20 h-20 rounded-full bg-bg-surface/20 backdrop-blur-sm flex items-center justify-center text-white text-3xl font-semibold shadow-lg\">\n {(\n currentUser.name ||\n currentUser.username ||\n currentUser.email\n )\n .charAt(0)\n .toUpperCase()}\n </div>\n )}\n <button\n type=\"button\"\n onClick={() => fileInputRef.current?.click()}\n disabled={isUploadingAvatar}\n aria-label={tr(\n \"auth.profile.changeAvatar\",\n \"Change profile picture\",\n )}\n className=\"absolute inset-0 rounded-full flex items-center justify-center bg-black/40 opacity-0 group-hover:opacity-100 transition-opacity duration-200 cursor-pointer\"\n >\n {isUploadingAvatar ? (\n <SpinnerIcon className=\"w-6 h-6 text-white animate-spin\" />\n ) : (\n <svg\n className=\"w-6 h-6 text-white\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M3 9a2 2 0 012-2h.93a2 2 0 001.664-.89l.812-1.22A2 2 0 0110.07 4h3.86a2 2 0 011.664.89l.812 1.22A2 2 0 0018.07 7H19a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2V9z\"\n />\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M15 13a3 3 0 11-6 0 3 3 0 016 0z\"\n />\n </svg>\n )}\n </button>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/*\"\n className=\"hidden\"\n onChange={(e) => void handleAvatarUpload(e)}\n aria-hidden=\"true\"\n />\n </div>\n <div className=\"text-white\">\n <h2 className=\"text-2xl font-semibold\">\n {currentUser.name ||\n `${currentUser.firstName || \"\"} ${currentUser.lastName || \"\"}`.trim() ||\n currentUser.username}\n </h2>\n <p className=\"text-white/80 flex items-center gap-2\">\n <EmailIcon className=\"w-4 h-4\" />\n {currentUser.email}\n </p>\n <div className=\"flex items-center gap-2 mt-2\">\n <span className=\"px-2.5 py-1 rounded-full text-xs font-medium bg-bg-surface/20 backdrop-blur-sm\">\n {currentUser.role?.replace(\"_\", \" \") ||\n tr(\"auth.profile.member\", \"Member\")}\n </span>\n {currentUser.emailVerified && (\n <span className=\"px-2.5 py-1 rounded-full text-xs font-medium bg-status-success-text/30 flex items-center gap-1\">\n <CheckIcon className=\"w-3 h-3\" />\n {tr(\"auth.profile.verified\", \"Verified\")}\n </span>\n )}\n </div>\n </div>\n </div>\n </div>\n\n {/* Profile Body */}\n <div className=\"p-6\">\n {isEditing ? (\n /* Edit Form */\n <form onSubmit={handleSubmit} className=\"space-y-6\">\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\n <div>\n <label\n htmlFor={usernameId}\n className=\"block text-sm font-medium text-[var(--color-text-primary)] mb-2\"\n >\n {tr(\"auth.profile.username\", \"Username\")}\n </label>\n <div className=\"relative\">\n <div className=\"absolute inset-y-0 left-0 pl-3.5 flex items-center pointer-events-none\">\n <UserIcon\n className=\"w-5 h-5 text-[var(--color-text-tertiary)]\"\n aria-hidden=\"true\"\n />\n </div>\n <input\n id={usernameId}\n type=\"text\"\n value={formData.username}\n onChange={(e) =>\n setFormData({ ...formData, username: e.target.value })\n }\n className=\"block w-full pl-[3.5rem] pr-4 py-3 border border-[var(--color-border-default)] rounded-xl bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all duration-300\"\n placeholder={tr(\n \"auth.profile.usernamePlaceholder\",\n \"Enter username\",\n )}\n />\n </div>\n </div>\n\n <div>\n <label\n htmlFor={displayNameId}\n className=\"block text-sm font-medium text-[var(--color-text-primary)] mb-2\"\n >\n {tr(\"auth.profile.displayName\", \"Display Name\")}\n </label>\n <input\n id={displayNameId}\n type=\"text\"\n value={formData.name}\n onChange={(e) =>\n setFormData({ ...formData, name: e.target.value })\n }\n className=\"block w-full px-4 py-3 border border-[var(--color-border-default)] rounded-xl bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all duration-300\"\n placeholder={tr(\n \"auth.profile.displayNamePlaceholder\",\n \"Enter display name\",\n )}\n />\n </div>\n\n <div>\n <label\n htmlFor={firstNameId}\n className=\"block text-sm font-medium text-[var(--color-text-primary)] mb-2\"\n >\n {tr(\"auth.profile.firstName\", \"First Name\")}\n </label>\n <input\n id={firstNameId}\n type=\"text\"\n value={formData.firstName}\n onChange={(e) =>\n setFormData({ ...formData, firstName: e.target.value })\n }\n className=\"block w-full px-4 py-3 border border-[var(--color-border-default)] rounded-xl bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all duration-300\"\n placeholder={tr(\n \"auth.profile.firstNamePlaceholder\",\n \"Enter first name\",\n )}\n />\n </div>\n\n <div>\n <label\n htmlFor={lastNameId}\n className=\"block text-sm font-medium text-[var(--color-text-primary)] mb-2\"\n >\n {tr(\"auth.profile.lastName\", \"Last Name\")}\n </label>\n <input\n id={lastNameId}\n type=\"text\"\n value={formData.lastName}\n onChange={(e) =>\n setFormData({ ...formData, lastName: e.target.value })\n }\n className=\"block w-full px-4 py-3 border border-[var(--color-border-default)] rounded-xl bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all duration-300\"\n placeholder={tr(\n \"auth.profile.lastNamePlaceholder\",\n \"Enter last name\",\n )}\n />\n </div>\n\n <div className=\"md:col-span-2\">\n <label\n htmlFor={phoneNumberId}\n className=\"block text-sm font-medium text-[var(--color-text-primary)] mb-2\"\n >\n {tr(\"auth.profile.phoneNumber\", \"Phone Number\")}\n </label>\n <input\n id={phoneNumberId}\n type=\"tel\"\n value={formData.phoneNumber}\n onChange={(e) =>\n setFormData({ ...formData, phoneNumber: e.target.value })\n }\n className=\"block w-full px-4 py-3 border border-[var(--color-border-default)] rounded-xl bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all duration-300\"\n placeholder={tr(\n \"auth.profile.phonePlaceholder\",\n \"Enter phone number\",\n )}\n />\n </div>\n </div>\n\n <div className=\"flex gap-3 pt-4 border-t border-[var(--color-border-default)]\">\n <button\n type=\"submit\"\n disabled={isLoading}\n className=\"auth-primary-button flex items-center gap-2 px-6 py-3 font-medium\"\n >\n {isLoading ? (\n <>\n <SpinnerIcon className=\"w-4 h-4 animate-spin\" />\n {tr(\"auth.profile.saving\", \"Saving...\")}\n </>\n ) : (\n tr(\"auth.profile.saveChanges\", \"Save Changes\")\n )}\n </button>\n <button\n type=\"button\"\n onClick={cancelEdit}\n className=\"px-6 py-3 rounded-xl border border-[var(--color-border-default)] text-[var(--color-text-secondary)] font-medium hover:bg-[var(--color-bg-muted)] transition-colors duration-200\"\n >\n {tr(\"auth.profile.cancel\", \"Cancel\")}\n </button>\n </div>\n </form>\n ) : (\n /* View Mode */\n <>\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\n <div className=\"p-4 rounded-xl bg-[var(--color-bg-muted)]\">\n <label className=\"block text-sm font-medium text-[var(--color-text-tertiary)] mb-1\">\n {tr(\"auth.profile.username\", \"Username\")}\n </label>\n <p className=\"text-[var(--color-text-primary)] font-medium\">\n {currentUser.username || \"-\"}\n </p>\n </div>\n\n <div className=\"p-4 rounded-xl bg-[var(--color-bg-muted)]\">\n <label className=\"block text-sm font-medium text-[var(--color-text-tertiary)] mb-1\">\n {tr(\"auth.profile.displayName\", \"Display Name\")}\n </label>\n <p className=\"text-[var(--color-text-primary)] font-medium\">\n {currentUser.name || \"-\"}\n </p>\n </div>\n\n <div className=\"p-4 rounded-xl bg-[var(--color-bg-muted)]\">\n <label className=\"block text-sm font-medium text-[var(--color-text-tertiary)] mb-1\">\n {tr(\"auth.profile.firstName\", \"First Name\")}\n </label>\n <p className=\"text-[var(--color-text-primary)] font-medium\">\n {currentUser.firstName || \"-\"}\n </p>\n </div>\n\n <div className=\"p-4 rounded-xl bg-[var(--color-bg-muted)]\">\n <label className=\"block text-sm font-medium text-[var(--color-text-tertiary)] mb-1\">\n {tr(\"auth.profile.lastName\", \"Last Name\")}\n </label>\n <p className=\"text-[var(--color-text-primary)] font-medium\">\n {currentUser.lastName || \"-\"}\n </p>\n </div>\n\n <div className=\"p-4 rounded-xl bg-[var(--color-bg-muted)]\">\n <label className=\"block text-sm font-medium text-[var(--color-text-tertiary)] mb-1\">\n {tr(\"auth.profile.email\", \"Email\")}\n </label>\n <p className=\"text-[var(--color-text-primary)] font-medium flex items-center gap-2\">\n {currentUser.email}\n {currentUser.emailVerified && (\n <span className=\"inline-flex items-center gap-1 text-[var(--color-status-success-text)] text-xs\">\n <CheckIcon className=\"w-3 h-3\" />\n {tr(\"auth.profile.verified\", \"Verified\")}\n </span>\n )}\n </p>\n </div>\n\n <div className=\"p-4 rounded-xl bg-[var(--color-bg-muted)]\">\n <label className=\"block text-sm font-medium text-[var(--color-text-tertiary)] mb-1\">\n {tr(\"auth.profile.phoneNumber\", \"Phone Number\")}\n </label>\n <p className=\"text-[var(--color-text-primary)] font-medium\">\n {currentUser.phoneNumber || \"-\"}\n </p>\n </div>\n\n <div className=\"p-4 rounded-xl bg-[var(--color-bg-muted)]\">\n <label className=\"block text-sm font-medium text-[var(--color-text-tertiary)] mb-1\">\n {tr(\"auth.profile.role\", \"Role\")}\n </label>\n <p className=\"text-[var(--color-text-primary)] font-medium\">\n {currentUser.role?.replace(\"_\", \" \") ||\n tr(\"auth.profile.member\", \"Member\")}\n </p>\n </div>\n\n <div className=\"p-4 rounded-xl bg-[var(--color-bg-muted)]\">\n <label className=\"block text-sm font-medium text-[var(--color-text-tertiary)] mb-1\">\n {tr(\"auth.profile.mfaStatus\", \"MFA Status\")}\n </label>\n <p className=\"text-[var(--color-text-primary)] font-medium\">\n {currentUser.mfaEnabled ? (\n <span className=\"text-[var(--color-status-success-text)] flex items-center gap-1\">\n <CheckIcon className=\"w-4 h-4\" />\n {tr(\"auth.profile.enabled\", \"Enabled\")}\n </span>\n ) : (\n <span className=\"text-[var(--color-status-warning-text)]\">\n {tr(\"auth.profile.notEnabled\", \"Not Enabled\")}\n </span>\n )}\n </p>\n </div>\n\n <div className=\"p-4 rounded-xl bg-[var(--color-bg-muted)]\">\n <label className=\"block text-sm font-medium text-[var(--color-text-tertiary)] mb-1\">\n {tr(\"auth.profile.lastLogin\", \"Last Login\")}\n </label>\n <p className=\"text-[var(--color-text-primary)] font-medium\">\n {currentUser.lastLoginAt\n ? new Date(currentUser.lastLoginAt).toLocaleString()\n : tr(\"auth.profile.never\", \"Never\")}\n </p>\n </div>\n\n <div className=\"p-4 rounded-xl bg-[var(--color-bg-muted)]\">\n <label className=\"block text-sm font-medium text-[var(--color-text-tertiary)] mb-1\">\n {tr(\"auth.profile.accountCreated\", \"Account Created\")}\n </label>\n <p className=\"text-[var(--color-text-primary)] font-medium\">\n {currentUser.createdAt\n ? new Date(currentUser.createdAt).toLocaleString()\n : \"-\"}\n </p>\n </div>\n </div>\n\n <div className=\"flex gap-3 pt-6 mt-6 border-t border-[var(--color-border-default)]\">\n <button\n onClick={() => setIsEditing(true)}\n className=\"auth-primary-button px-6 py-3 font-medium\"\n >\n {tr(\"auth.profile.editProfile\", \"Edit Profile\")}\n </button>\n <button\n onClick={() => navigate(\"/auth/security\")}\n className=\"px-6 py-3 rounded-xl border border-[var(--color-border-default)] text-[var(--color-text-secondary)] font-medium hover:bg-[var(--color-bg-muted)] transition-colors duration-200\"\n >\n {tr(\"auth.profile.securitySettings\", \"Security Settings\")}\n </button>\n </div>\n </>\n )}\n </div>\n </div>\n\n {/* Quick Links */}\n <div className=\"mt-8 grid grid-cols-1 md:grid-cols-3 gap-4\">\n <button\n onClick={() => navigate(\"/auth/mfa\")}\n className=\"p-4 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] hover:border-[var(--color-action-primary-border)] transition-colors duration-200 text-left group\"\n >\n <div className=\"w-10 h-10 rounded-lg bg-[var(--color-bg-accent)] flex items-center justify-center mb-3 group-hover:bg-[var(--color-action-primary-bg-subtle)] transition-colors duration-200\">\n <svg\n className=\"w-5 h-5 text-[var(--color-text-link)]\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z\"\n />\n </svg>\n </div>\n <h3 className=\"font-medium text-[var(--color-text-primary)]\">\n {tr(\"auth.profile.twoFactorAuth\", \"Two-Factor Auth\")}\n </h3>\n <p className=\"text-sm text-[var(--color-text-tertiary)] mt-1\">\n {currentUser.mfaEnabled\n ? tr(\"auth.profile.manageMfa\", \"Manage MFA settings\")\n : tr(\"auth.profile.enableMfa\", \"Enable MFA for extra security\")}\n </p>\n </button>\n\n <button\n onClick={() => navigate(\"/auth/api-keys\")}\n className=\"p-4 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] hover:border-[var(--color-action-secondary-border)] transition-colors duration-200 text-left group\"\n >\n <div className=\"w-10 h-10 rounded-lg bg-[var(--color-action-secondary-bg-subtle)] flex items-center justify-center mb-3 group-hover:bg-[var(--color-action-secondary-bg-subtle)] transition-colors duration-200\">\n <svg\n className=\"w-5 h-5 text-[var(--color-action-secondary-text)]\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z\"\n />\n </svg>\n </div>\n <h3 className=\"font-medium text-[var(--color-text-primary)]\">\n {tr(\"auth.profile.apiKeys\", \"API Keys\")}\n </h3>\n <p className=\"text-sm text-[var(--color-text-tertiary)] mt-1\">\n {tr(\n \"auth.profile.manageApiKeys\",\n \"Manage your API access credentials\",\n )}\n </p>\n </button>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"UserProfilePage.js","names":[],"sources":["../../../src/auth/pages/UserProfilePage.tsx"],"sourcesContent":["import { useState, useEffect, useRef, useId } from \"react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell\";\nimport { useAuth as useShellAuth } from \"@burdenoff/fe-libs/shared/providers/shell/AuthProvider\";\nimport { useNavigate } from \"react-router-dom\";\nimport { useUserOperations } from \"../hooks\";\nimport { useAuthStore } from \"../store/authStore\";\nimport { AuthLayout } from \"../components/AuthLayout\";\nimport {\n SpinnerIcon,\n AlertIcon,\n UserIcon,\n EmailIcon,\n CheckIcon,\n} from \"../components/AuthIcons\";\nimport {\n useInitiateAvatarUploadMutation,\n useCompleteAvatarUploadMutation,\n} from \"../../generated/wspace-operations\";\nimport { useGatewayClient } from \"@burdenoff/fe-libs/shared/graphql\";\n\ninterface ProfileFormData {\n username: string;\n firstName: string;\n lastName: string;\n name: string;\n phoneNumber: string;\n}\n\n/**\n * User Profile page for viewing and editing own profile\n */\nexport function UserProfilePage() {\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n\n const navigate = useNavigate();\n const shellAuth = useShellAuth();\n const isAuthenticated = useAuthStore((state) => state.isAuthenticated);\n const currentUser = useAuthStore((state) => state.user);\n const setStoreUser = useAuthStore((state) => state.setUser);\n const { updateCurrentUserProfile, isLoading } = useUserOperations();\n\n const usernameId = useId();\n const displayNameId = useId();\n const firstNameId = useId();\n const lastNameId = useId();\n const phoneNumberId = useId();\n\n const currentWorkspaceId = useAuthStore((state) => state.currentWorkspaceId);\n const wspaceClient = useGatewayClient(\"workspace\");\n const [initiateUpload] = useInitiateAvatarUploadMutation({\n client: wspaceClient,\n });\n const [completeUpload] = useCompleteAvatarUploadMutation({\n client: wspaceClient,\n });\n const fileInputRef = useRef<HTMLInputElement>(null);\n const [isUploadingAvatar, setIsUploadingAvatar] = useState(false);\n\n const handleAvatarUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n if (!file.type.startsWith(\"image/\")) {\n setError(\n tr(\"auth.profile.invalidImageType\", \"Please select an image file\"),\n );\n return;\n }\n if (!currentWorkspaceId) {\n setError(\n tr(\n \"auth.profile.noWorkspace\",\n \"Please select a workspace before uploading a profile picture\",\n ),\n );\n return;\n }\n setIsUploadingAvatar(true);\n setError(null);\n const wsHeaders = { \"x-workspace-id\": currentWorkspaceId };\n try {\n const extension = file.name.split(\".\").pop()?.toLowerCase() ?? \"\";\n const initiateResult = await initiateUpload({\n variables: {\n input: {\n fileName: file.name,\n fileSize: file.size.toString(),\n mimeType: file.type,\n extension,\n },\n },\n context: { headers: wsHeaders },\n });\n const session = initiateResult.data?.initiateUpload.session;\n const uploadUrl = initiateResult.data?.initiateUpload.uploadUrl;\n if (!session || !uploadUrl) throw new Error(\"Failed to initiate upload\");\n\n const uploadResp = await fetch(uploadUrl, {\n method: \"PUT\",\n headers: { \"Content-Type\": file.type },\n body: file,\n });\n if (!uploadResp.ok) throw new Error(\"Failed to upload file\");\n\n const completeResult = await completeUpload({\n variables: { input: { sessionId: session.id } },\n context: { headers: wsHeaders },\n });\n const avatarUrl = completeResult.data?.completeUpload.file?.downloadUrl;\n if (!avatarUrl) throw new Error(\"Upload succeeded but no URL returned\");\n\n await updateCurrentUserProfile({ avatar: avatarUrl });\n // Update both the local authStore and the shell AuthProvider so the nav\n // bar avatar reflects the change immediately without a page reload.\n if (currentUser) {\n setStoreUser({ ...currentUser, avatar: avatarUrl });\n }\n shellAuth.updateUser({ avatar: avatarUrl });\n setSuccessMessage(\n tr(\"auth.profile.avatarUpdated\", \"Profile picture updated!\"),\n );\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : tr(\"auth.profile.avatarFailed\", \"Failed to upload picture\"),\n );\n } finally {\n setIsUploadingAvatar(false);\n if (fileInputRef.current) fileInputRef.current.value = \"\";\n }\n };\n\n const [isEditing, setIsEditing] = useState(false);\n const [formData, setFormData] = useState<ProfileFormData>({\n username: \"\",\n firstName: \"\",\n lastName: \"\",\n name: \"\",\n phoneNumber: \"\",\n });\n const [error, setError] = useState<string | null>(null);\n const [successMessage, setSuccessMessage] = useState<string | null>(null);\n\n // Populate form with current user data\n useEffect(() => {\n if (currentUser) {\n setFormData({\n username: currentUser.username || \"\",\n firstName: currentUser.firstName || \"\",\n lastName: currentUser.lastName || \"\",\n name: currentUser.name || \"\",\n phoneNumber: currentUser.phoneNumber || \"\",\n });\n }\n }, [currentUser]);\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n setSuccessMessage(null);\n\n try {\n await updateCurrentUserProfile({\n username: formData.username || undefined,\n firstName: formData.firstName || undefined,\n lastName: formData.lastName || undefined,\n name: formData.name || undefined,\n phoneNumber: formData.phoneNumber || undefined,\n });\n setSuccessMessage(\n tr(\"auth.profile.updateSuccess\", \"Profile updated successfully!\"),\n );\n setIsEditing(false);\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : tr(\"auth.profile.updateFailed\", \"Failed to update profile\"),\n );\n }\n };\n\n const cancelEdit = () => {\n if (currentUser) {\n setFormData({\n username: currentUser.username || \"\",\n firstName: currentUser.firstName || \"\",\n lastName: currentUser.lastName || \"\",\n name: currentUser.name || \"\",\n phoneNumber: currentUser.phoneNumber || \"\",\n });\n }\n setIsEditing(false);\n setError(null);\n };\n\n // Not authenticated\n if (!isAuthenticated || !currentUser) {\n return (\n <AuthLayout\n title={tr(\"auth.profile.title\", \"Profile\")}\n subtitle={tr(\"auth.profile.subtitle\", \"View and manage your profile\")}\n >\n <div className=\"text-center py-12\">\n <div className=\"w-16 h-16 mx-auto mb-4 rounded-full bg-[var(--color-status-warning-bg-subtle)] flex items-center justify-center\">\n <AlertIcon className=\"w-8 h-8 text-[var(--color-status-warning-text)]\" />\n </div>\n <h2 className=\"text-xl font-semibold text-[var(--color-text-primary)] mb-2\">\n {tr(\"auth.profile.authRequired\", \"Authentication Required\")}\n </h2>\n <p className=\"text-[var(--color-text-secondary)] mb-6\">\n {tr(\n \"auth.profile.signInToView\",\n \"Please sign in to view your profile\",\n )}\n </p>\n <button\n onClick={() => navigate(\"/auth/login\")}\n className=\"auth-primary-button px-6 py-3 font-semibold\"\n >\n {tr(\"auth.profile.signIn\", \"Sign In\")}\n </button>\n </div>\n </AuthLayout>\n );\n }\n\n return (\n <div className=\"max-w-4xl mx-auto p-6\">\n {/* Header */}\n <div className=\"mb-8\">\n <h1 className=\"text-3xl font-semibold text-[var(--color-text-primary)]\">\n {tr(\"auth.profile.myProfile\", \"My Profile\")}\n </h1>\n <p className=\"text-[var(--color-text-secondary)] mt-2\">\n {tr(\n \"auth.profile.viewAndManage\",\n \"View and manage your account information\",\n )}\n </p>\n </div>\n\n {/* Success Message */}\n {successMessage && (\n <div className=\"mb-6 flex items-center gap-3 p-4 rounded-xl bg-[var(--color-status-success-bg-subtle)] border border-[var(--color-status-success-border)]\">\n <CheckIcon className=\"w-5 h-5 text-[var(--color-status-success-text)] flex-shrink-0\" />\n <p className=\"text-[var(--color-status-success-text)]\">\n {successMessage}\n </p>\n <button\n onClick={() => setSuccessMessage(null)}\n className=\"ml-auto text-sm text-[var(--color-status-success-text)] hover:underline transition-colors duration-200\"\n >\n {tr(\"auth.profile.dismiss\", \"Dismiss\")}\n </button>\n </div>\n )}\n\n {/* Error Message */}\n {error && (\n <div className=\"mb-6 flex items-start gap-3 p-4 rounded-xl bg-[var(--color-status-error-bg-subtle)] border border-[var(--color-status-error-border)]\">\n <AlertIcon className=\"w-5 h-5 text-[var(--color-status-error-text)] flex-shrink-0 mt-0.5\" />\n <div className=\"flex-1\">\n <p className=\"text-sm text-[var(--color-status-error-text)]\">\n {error}\n </p>\n </div>\n <button\n onClick={() => setError(null)}\n className=\"text-sm text-[var(--color-status-error-text)] hover:underline transition-colors duration-200\"\n >\n {tr(\"auth.profile.dismiss\", \"Dismiss\")}\n </button>\n </div>\n )}\n\n {/* Profile Card */}\n <div className=\"rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] shadow-sm overflow-hidden\">\n {/* Profile Header */}\n <div className=\"auth-hero-card p-6\">\n <div className=\"flex items-center gap-4\">\n <div className=\"relative group\">\n {currentUser.avatar ? (\n <img\n src={currentUser.avatar}\n alt={tr(\"auth.profile.avatarAlt\", \"Profile picture\")}\n className=\"w-20 h-20 rounded-full object-cover shadow-lg\"\n />\n ) : (\n <div className=\"w-20 h-20 rounded-full bg-bg-surface/20 backdrop-blur-sm flex items-center justify-center text-white text-3xl font-semibold shadow-lg\">\n {(\n currentUser.name ||\n currentUser.username ||\n currentUser.email\n )\n .charAt(0)\n .toUpperCase()}\n </div>\n )}\n <button\n type=\"button\"\n onClick={() => fileInputRef.current?.click()}\n disabled={isUploadingAvatar}\n aria-label={tr(\n \"auth.profile.changeAvatar\",\n \"Change profile picture\",\n )}\n className=\"absolute inset-0 rounded-full flex items-center justify-center bg-black/40 opacity-0 group-hover:opacity-100 transition-opacity duration-200 cursor-pointer\"\n >\n {isUploadingAvatar ? (\n <SpinnerIcon className=\"w-6 h-6 text-white animate-spin\" />\n ) : (\n <svg\n className=\"w-6 h-6 text-white\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M3 9a2 2 0 012-2h.93a2 2 0 001.664-.89l.812-1.22A2 2 0 0110.07 4h3.86a2 2 0 011.664.89l.812 1.22A2 2 0 0018.07 7H19a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2V9z\"\n />\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M15 13a3 3 0 11-6 0 3 3 0 016 0z\"\n />\n </svg>\n )}\n </button>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/*\"\n className=\"hidden\"\n onChange={(e) => void handleAvatarUpload(e)}\n aria-hidden=\"true\"\n />\n </div>\n <div className=\"text-white\">\n <h2 className=\"text-2xl font-semibold\">\n {currentUser.name ||\n `${currentUser.firstName || \"\"} ${currentUser.lastName || \"\"}`.trim() ||\n currentUser.username}\n </h2>\n <p className=\"text-white/80 flex items-center gap-2\">\n <EmailIcon className=\"w-4 h-4\" />\n {currentUser.email}\n </p>\n <div className=\"flex items-center gap-2 mt-2\">\n <span className=\"px-2.5 py-1 rounded-full text-xs font-medium bg-bg-surface/20 backdrop-blur-sm\">\n {currentUser.role?.replace(\"_\", \" \") ||\n tr(\"auth.profile.member\", \"Member\")}\n </span>\n {currentUser.emailVerified && (\n <span className=\"px-2.5 py-1 rounded-full text-xs font-medium bg-status-success-text/30 flex items-center gap-1\">\n <CheckIcon className=\"w-3 h-3\" />\n {tr(\"auth.profile.verified\", \"Verified\")}\n </span>\n )}\n </div>\n </div>\n </div>\n </div>\n\n {/* Profile Body */}\n <div className=\"p-6\">\n {isEditing ? (\n /* Edit Form */\n <form onSubmit={handleSubmit} className=\"space-y-6\">\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\n <div>\n <label\n htmlFor={usernameId}\n className=\"block text-sm font-medium text-[var(--color-text-primary)] mb-2\"\n >\n {tr(\"auth.profile.username\", \"Username\")}\n </label>\n <div className=\"relative\">\n <div className=\"absolute inset-y-0 left-0 pl-3.5 flex items-center pointer-events-none\">\n <UserIcon\n className=\"w-5 h-5 text-[var(--color-text-tertiary)]\"\n aria-hidden=\"true\"\n />\n </div>\n <input\n id={usernameId}\n type=\"text\"\n value={formData.username}\n onChange={(e) =>\n setFormData({ ...formData, username: e.target.value })\n }\n className=\"block w-full pl-[3.5rem] pr-4 py-3 border border-[var(--color-border-default)] rounded-xl bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all duration-300\"\n placeholder={tr(\n \"auth.profile.usernamePlaceholder\",\n \"Enter username\",\n )}\n />\n </div>\n </div>\n\n <div>\n <label\n htmlFor={displayNameId}\n className=\"block text-sm font-medium text-[var(--color-text-primary)] mb-2\"\n >\n {tr(\"auth.profile.displayName\", \"Display Name\")}\n </label>\n <input\n id={displayNameId}\n type=\"text\"\n value={formData.name}\n onChange={(e) =>\n setFormData({ ...formData, name: e.target.value })\n }\n className=\"block w-full px-4 py-3 border border-[var(--color-border-default)] rounded-xl bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all duration-300\"\n placeholder={tr(\n \"auth.profile.displayNamePlaceholder\",\n \"Enter display name\",\n )}\n />\n </div>\n\n <div>\n <label\n htmlFor={firstNameId}\n className=\"block text-sm font-medium text-[var(--color-text-primary)] mb-2\"\n >\n {tr(\"auth.profile.firstName\", \"First Name\")}\n </label>\n <input\n id={firstNameId}\n type=\"text\"\n value={formData.firstName}\n onChange={(e) =>\n setFormData({ ...formData, firstName: e.target.value })\n }\n className=\"block w-full px-4 py-3 border border-[var(--color-border-default)] rounded-xl bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all duration-300\"\n placeholder={tr(\n \"auth.profile.firstNamePlaceholder\",\n \"Enter first name\",\n )}\n />\n </div>\n\n <div>\n <label\n htmlFor={lastNameId}\n className=\"block text-sm font-medium text-[var(--color-text-primary)] mb-2\"\n >\n {tr(\"auth.profile.lastName\", \"Last Name\")}\n </label>\n <input\n id={lastNameId}\n type=\"text\"\n value={formData.lastName}\n onChange={(e) =>\n setFormData({ ...formData, lastName: e.target.value })\n }\n className=\"block w-full px-4 py-3 border border-[var(--color-border-default)] rounded-xl bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all duration-300\"\n placeholder={tr(\n \"auth.profile.lastNamePlaceholder\",\n \"Enter last name\",\n )}\n />\n </div>\n\n <div className=\"md:col-span-2\">\n <label\n htmlFor={phoneNumberId}\n className=\"block text-sm font-medium text-[var(--color-text-primary)] mb-2\"\n >\n {tr(\"auth.profile.phoneNumber\", \"Phone Number\")}\n </label>\n <input\n id={phoneNumberId}\n type=\"tel\"\n value={formData.phoneNumber}\n onChange={(e) =>\n setFormData({ ...formData, phoneNumber: e.target.value })\n }\n className=\"block w-full px-4 py-3 border border-[var(--color-border-default)] rounded-xl bg-[var(--color-bg-surface)] text-[var(--color-text-primary)] focus:outline-none focus:ring-2 focus:ring-action-primary-bg/20 focus:border-action-primary-bg transition-all duration-300\"\n placeholder={tr(\n \"auth.profile.phonePlaceholder\",\n \"Enter phone number\",\n )}\n />\n </div>\n </div>\n\n <div className=\"flex gap-3 pt-4 border-t border-[var(--color-border-default)]\">\n <button\n type=\"submit\"\n disabled={isLoading}\n className=\"auth-primary-button flex items-center gap-2 px-6 py-3 font-medium\"\n >\n {isLoading ? (\n <>\n <SpinnerIcon className=\"w-4 h-4 animate-spin\" />\n {tr(\"auth.profile.saving\", \"Saving...\")}\n </>\n ) : (\n tr(\"auth.profile.saveChanges\", \"Save Changes\")\n )}\n </button>\n <button\n type=\"button\"\n onClick={cancelEdit}\n className=\"px-6 py-3 rounded-xl border border-[var(--color-border-default)] text-[var(--color-text-secondary)] font-medium hover:bg-[var(--color-bg-muted)] transition-colors duration-200\"\n >\n {tr(\"auth.profile.cancel\", \"Cancel\")}\n </button>\n </div>\n </form>\n ) : (\n /* View Mode */\n <>\n <div className=\"grid grid-cols-1 md:grid-cols-2 gap-6\">\n <div className=\"p-4 rounded-xl bg-[var(--color-bg-muted)]\">\n <label className=\"block text-sm font-medium text-[var(--color-text-tertiary)] mb-1\">\n {tr(\"auth.profile.username\", \"Username\")}\n </label>\n <p className=\"text-[var(--color-text-primary)] font-medium\">\n {currentUser.username || \"-\"}\n </p>\n </div>\n\n <div className=\"p-4 rounded-xl bg-[var(--color-bg-muted)]\">\n <label className=\"block text-sm font-medium text-[var(--color-text-tertiary)] mb-1\">\n {tr(\"auth.profile.displayName\", \"Display Name\")}\n </label>\n <p className=\"text-[var(--color-text-primary)] font-medium\">\n {currentUser.name || \"-\"}\n </p>\n </div>\n\n <div className=\"p-4 rounded-xl bg-[var(--color-bg-muted)]\">\n <label className=\"block text-sm font-medium text-[var(--color-text-tertiary)] mb-1\">\n {tr(\"auth.profile.firstName\", \"First Name\")}\n </label>\n <p className=\"text-[var(--color-text-primary)] font-medium\">\n {currentUser.firstName || \"-\"}\n </p>\n </div>\n\n <div className=\"p-4 rounded-xl bg-[var(--color-bg-muted)]\">\n <label className=\"block text-sm font-medium text-[var(--color-text-tertiary)] mb-1\">\n {tr(\"auth.profile.lastName\", \"Last Name\")}\n </label>\n <p className=\"text-[var(--color-text-primary)] font-medium\">\n {currentUser.lastName || \"-\"}\n </p>\n </div>\n\n <div className=\"p-4 rounded-xl bg-[var(--color-bg-muted)]\">\n <label className=\"block text-sm font-medium text-[var(--color-text-tertiary)] mb-1\">\n {tr(\"auth.profile.email\", \"Email\")}\n </label>\n <p className=\"text-[var(--color-text-primary)] font-medium flex items-center gap-2\">\n {currentUser.email}\n {currentUser.emailVerified && (\n <span className=\"inline-flex items-center gap-1 text-[var(--color-status-success-text)] text-xs\">\n <CheckIcon className=\"w-3 h-3\" />\n {tr(\"auth.profile.verified\", \"Verified\")}\n </span>\n )}\n </p>\n </div>\n\n <div className=\"p-4 rounded-xl bg-[var(--color-bg-muted)]\">\n <label className=\"block text-sm font-medium text-[var(--color-text-tertiary)] mb-1\">\n {tr(\"auth.profile.phoneNumber\", \"Phone Number\")}\n </label>\n <p className=\"text-[var(--color-text-primary)] font-medium\">\n {currentUser.phoneNumber || \"-\"}\n </p>\n </div>\n\n <div className=\"p-4 rounded-xl bg-[var(--color-bg-muted)]\">\n <label className=\"block text-sm font-medium text-[var(--color-text-tertiary)] mb-1\">\n {tr(\"auth.profile.role\", \"Role\")}\n </label>\n <p className=\"text-[var(--color-text-primary)] font-medium\">\n {currentUser.role?.replace(\"_\", \" \") ||\n tr(\"auth.profile.member\", \"Member\")}\n </p>\n </div>\n\n <div className=\"p-4 rounded-xl bg-[var(--color-bg-muted)]\">\n <label className=\"block text-sm font-medium text-[var(--color-text-tertiary)] mb-1\">\n {tr(\"auth.profile.mfaStatus\", \"MFA Status\")}\n </label>\n <p className=\"text-[var(--color-text-primary)] font-medium\">\n {currentUser.mfaEnabled ? (\n <span className=\"text-[var(--color-status-success-text)] flex items-center gap-1\">\n <CheckIcon className=\"w-4 h-4\" />\n {tr(\"auth.profile.enabled\", \"Enabled\")}\n </span>\n ) : (\n <span className=\"text-[var(--color-status-warning-text)]\">\n {tr(\"auth.profile.notEnabled\", \"Not Enabled\")}\n </span>\n )}\n </p>\n </div>\n\n <div className=\"p-4 rounded-xl bg-[var(--color-bg-muted)]\">\n <label className=\"block text-sm font-medium text-[var(--color-text-tertiary)] mb-1\">\n {tr(\"auth.profile.lastLogin\", \"Last Login\")}\n </label>\n <p className=\"text-[var(--color-text-primary)] font-medium\">\n {currentUser.lastLoginAt\n ? new Date(currentUser.lastLoginAt).toLocaleString()\n : tr(\"auth.profile.never\", \"Never\")}\n </p>\n </div>\n\n <div className=\"p-4 rounded-xl bg-[var(--color-bg-muted)]\">\n <label className=\"block text-sm font-medium text-[var(--color-text-tertiary)] mb-1\">\n {tr(\"auth.profile.accountCreated\", \"Account Created\")}\n </label>\n <p className=\"text-[var(--color-text-primary)] font-medium\">\n {currentUser.createdAt\n ? new Date(currentUser.createdAt).toLocaleString()\n : \"-\"}\n </p>\n </div>\n </div>\n\n <div className=\"flex gap-3 pt-6 mt-6 border-t border-[var(--color-border-default)]\">\n <button\n onClick={() => setIsEditing(true)}\n className=\"auth-primary-button px-6 py-3 font-medium\"\n >\n {tr(\"auth.profile.editProfile\", \"Edit Profile\")}\n </button>\n <button\n onClick={() => navigate(\"/auth/security\")}\n className=\"px-6 py-3 rounded-xl border border-[var(--color-border-default)] text-[var(--color-text-secondary)] font-medium hover:bg-[var(--color-bg-muted)] transition-colors duration-200\"\n >\n {tr(\"auth.profile.securitySettings\", \"Security Settings\")}\n </button>\n </div>\n </>\n )}\n </div>\n </div>\n\n {/* Quick Links */}\n <div className=\"mt-8 grid grid-cols-1 md:grid-cols-3 gap-4\">\n <button\n onClick={() => navigate(\"/auth/mfa\")}\n className=\"p-4 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] hover:border-[var(--color-action-primary-border)] transition-colors duration-200 text-left group\"\n >\n <div className=\"w-10 h-10 rounded-lg bg-[var(--color-bg-accent)] flex items-center justify-center mb-3 group-hover:bg-[var(--color-action-primary-bg-subtle)] transition-colors duration-200\">\n <svg\n className=\"w-5 h-5 text-[var(--color-text-link)]\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z\"\n />\n </svg>\n </div>\n <h3 className=\"font-medium text-[var(--color-text-primary)]\">\n {tr(\"auth.profile.twoFactorAuth\", \"Two-Factor Auth\")}\n </h3>\n <p className=\"text-sm text-[var(--color-text-tertiary)] mt-1\">\n {currentUser.mfaEnabled\n ? tr(\"auth.profile.manageMfa\", \"Manage MFA settings\")\n : tr(\"auth.profile.enableMfa\", \"Enable MFA for extra security\")}\n </p>\n </button>\n\n <button\n onClick={() => navigate(\"/auth/api-keys\")}\n className=\"p-4 rounded-xl border border-[var(--color-border-default)] bg-[var(--color-bg-surface)] hover:border-[var(--color-action-secondary-border)] transition-colors duration-200 text-left group\"\n >\n <div className=\"w-10 h-10 rounded-lg bg-[var(--color-action-secondary-bg-subtle)] flex items-center justify-center mb-3 group-hover:bg-[var(--color-action-secondary-bg-subtle)] transition-colors duration-200\">\n <svg\n className=\"w-5 h-5 text-[var(--color-action-secondary-text)]\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z\"\n />\n </svg>\n </div>\n <h3 className=\"font-medium text-[var(--color-text-primary)]\">\n {tr(\"auth.profile.apiKeys\", \"API Keys\")}\n </h3>\n <p className=\"text-sm text-[var(--color-text-tertiary)] mt-1\">\n {tr(\n \"auth.profile.manageApiKeys\",\n \"Manage your API access credentials\",\n )}\n </p>\n </button>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|