dauth-context-react 6.1.0 → 6.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +24 -2
- package/dist/index.d.ts +24 -2
- package/dist/index.js +1249 -164
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1249 -164
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/DauthProfileModal.tsx +1285 -246
- package/src/api/dauth.api.ts +73 -0
- package/src/api/interfaces/dauth.api.responses.ts +36 -0
- package/src/index.tsx +33 -1
- package/src/initialDauthState.ts +3 -0
- package/src/interfaces.ts +28 -0
- package/src/reducer/dauth.actions.ts +91 -0
- package/src/webauthn.ts +111 -0
package/dist/index.mjs
CHANGED
|
@@ -21,7 +21,10 @@ var initialDauthState = {
|
|
|
21
21
|
logout: () => {
|
|
22
22
|
},
|
|
23
23
|
updateUser: () => Promise.resolve(false),
|
|
24
|
-
deleteAccount: () => Promise.resolve(false)
|
|
24
|
+
deleteAccount: () => Promise.resolve(false),
|
|
25
|
+
getPasskeyCredentials: () => Promise.resolve([]),
|
|
26
|
+
registerPasskey: () => Promise.resolve(null),
|
|
27
|
+
deletePasskeyCredential: () => Promise.resolve(false)
|
|
25
28
|
};
|
|
26
29
|
var initialDauthState_default = initialDauthState;
|
|
27
30
|
|
|
@@ -128,6 +131,134 @@ async function deleteAccountAPI(basePath) {
|
|
|
128
131
|
const data = await response.json();
|
|
129
132
|
return { response, data };
|
|
130
133
|
}
|
|
134
|
+
async function getPasskeyCredentialsAPI(basePath) {
|
|
135
|
+
const response = await fetch(
|
|
136
|
+
`${basePath}/passkey/credentials`,
|
|
137
|
+
{
|
|
138
|
+
method: "GET",
|
|
139
|
+
headers: { "X-CSRF-Token": getCsrfToken() },
|
|
140
|
+
credentials: "include"
|
|
141
|
+
}
|
|
142
|
+
);
|
|
143
|
+
const data = await response.json();
|
|
144
|
+
return { response, data };
|
|
145
|
+
}
|
|
146
|
+
async function startPasskeyRegistrationAPI(basePath) {
|
|
147
|
+
const response = await fetch(
|
|
148
|
+
`${basePath}/passkey/register/start`,
|
|
149
|
+
{
|
|
150
|
+
method: "POST",
|
|
151
|
+
headers: {
|
|
152
|
+
"Content-Type": "application/json",
|
|
153
|
+
"X-CSRF-Token": getCsrfToken()
|
|
154
|
+
},
|
|
155
|
+
credentials: "include"
|
|
156
|
+
}
|
|
157
|
+
);
|
|
158
|
+
const data = await response.json();
|
|
159
|
+
return { response, data };
|
|
160
|
+
}
|
|
161
|
+
async function finishPasskeyRegistrationAPI(basePath, body) {
|
|
162
|
+
const response = await fetch(
|
|
163
|
+
`${basePath}/passkey/register/finish`,
|
|
164
|
+
{
|
|
165
|
+
method: "POST",
|
|
166
|
+
headers: {
|
|
167
|
+
"Content-Type": "application/json",
|
|
168
|
+
"X-CSRF-Token": getCsrfToken()
|
|
169
|
+
},
|
|
170
|
+
credentials: "include",
|
|
171
|
+
body: JSON.stringify(body)
|
|
172
|
+
}
|
|
173
|
+
);
|
|
174
|
+
const data = await response.json();
|
|
175
|
+
return { response, data };
|
|
176
|
+
}
|
|
177
|
+
async function deletePasskeyCredentialAPI(basePath, credentialId) {
|
|
178
|
+
const response = await fetch(
|
|
179
|
+
`${basePath}/passkey/credentials/${credentialId}`,
|
|
180
|
+
{
|
|
181
|
+
method: "DELETE",
|
|
182
|
+
headers: { "X-CSRF-Token": getCsrfToken() },
|
|
183
|
+
credentials: "include"
|
|
184
|
+
}
|
|
185
|
+
);
|
|
186
|
+
const data = await response.json();
|
|
187
|
+
return { response, data };
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// src/webauthn.ts
|
|
191
|
+
function base64urlToBuffer(base64url) {
|
|
192
|
+
const base64 = base64url.replace(/-/g, "+").replace(/_/g, "/");
|
|
193
|
+
const pad = base64.length % 4;
|
|
194
|
+
const padded = pad ? base64 + "=".repeat(4 - pad) : base64;
|
|
195
|
+
const binary = atob(padded);
|
|
196
|
+
const bytes = new Uint8Array(binary.length);
|
|
197
|
+
for (let i = 0; i < binary.length; i++) {
|
|
198
|
+
bytes[i] = binary.charCodeAt(i);
|
|
199
|
+
}
|
|
200
|
+
return bytes.buffer;
|
|
201
|
+
}
|
|
202
|
+
function bufferToBase64url(buffer) {
|
|
203
|
+
const bytes = new Uint8Array(buffer);
|
|
204
|
+
let binary = "";
|
|
205
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
206
|
+
binary += String.fromCharCode(bytes[i]);
|
|
207
|
+
}
|
|
208
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
209
|
+
}
|
|
210
|
+
async function createPasskeyCredential(options) {
|
|
211
|
+
const publicKey = {
|
|
212
|
+
...options,
|
|
213
|
+
challenge: base64urlToBuffer(options.challenge),
|
|
214
|
+
user: {
|
|
215
|
+
...options.user,
|
|
216
|
+
id: base64urlToBuffer(options.user.id)
|
|
217
|
+
},
|
|
218
|
+
excludeCredentials: (options.excludeCredentials ?? []).map(
|
|
219
|
+
(c) => ({
|
|
220
|
+
...c,
|
|
221
|
+
id: base64urlToBuffer(c.id)
|
|
222
|
+
})
|
|
223
|
+
)
|
|
224
|
+
};
|
|
225
|
+
const credential = await navigator.credentials.create({
|
|
226
|
+
publicKey
|
|
227
|
+
});
|
|
228
|
+
if (!credential) {
|
|
229
|
+
throw new Error("Passkey registration was cancelled");
|
|
230
|
+
}
|
|
231
|
+
const attestation = credential.response;
|
|
232
|
+
return {
|
|
233
|
+
id: credential.id,
|
|
234
|
+
rawId: bufferToBase64url(credential.rawId),
|
|
235
|
+
type: credential.type,
|
|
236
|
+
response: {
|
|
237
|
+
clientDataJSON: bufferToBase64url(
|
|
238
|
+
attestation.clientDataJSON
|
|
239
|
+
),
|
|
240
|
+
attestationObject: bufferToBase64url(
|
|
241
|
+
attestation.attestationObject
|
|
242
|
+
),
|
|
243
|
+
...attestation.getTransports ? { transports: attestation.getTransports() } : {},
|
|
244
|
+
...attestation.getPublicKeyAlgorithm ? {
|
|
245
|
+
publicKeyAlgorithm: attestation.getPublicKeyAlgorithm()
|
|
246
|
+
} : {},
|
|
247
|
+
...attestation.getPublicKey ? {
|
|
248
|
+
publicKey: bufferToBase64url(
|
|
249
|
+
attestation.getPublicKey()
|
|
250
|
+
)
|
|
251
|
+
} : {},
|
|
252
|
+
...attestation.getAuthenticatorData ? {
|
|
253
|
+
authenticatorData: bufferToBase64url(
|
|
254
|
+
attestation.getAuthenticatorData()
|
|
255
|
+
)
|
|
256
|
+
} : {}
|
|
257
|
+
},
|
|
258
|
+
clientExtensionResults: credential.getClientExtensionResults(),
|
|
259
|
+
authenticatorAttachment: credential.authenticatorAttachment ?? void 0
|
|
260
|
+
};
|
|
261
|
+
}
|
|
131
262
|
|
|
132
263
|
// src/reducer/dauth.actions.ts
|
|
133
264
|
async function exchangeCodeAction(ctx, code) {
|
|
@@ -251,6 +382,65 @@ async function deleteAccountAction(ctx) {
|
|
|
251
382
|
return false;
|
|
252
383
|
}
|
|
253
384
|
}
|
|
385
|
+
async function getPasskeyCredentialsAction(ctx) {
|
|
386
|
+
const { authProxyPath, onError } = ctx;
|
|
387
|
+
try {
|
|
388
|
+
const result = await getPasskeyCredentialsAPI(authProxyPath);
|
|
389
|
+
if (result.response.status === 200) {
|
|
390
|
+
return result.data.credentials ?? [];
|
|
391
|
+
}
|
|
392
|
+
return [];
|
|
393
|
+
} catch (error) {
|
|
394
|
+
onError(
|
|
395
|
+
error instanceof Error ? error : new Error("Get passkey credentials error")
|
|
396
|
+
);
|
|
397
|
+
return [];
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
async function registerPasskeyAction(ctx, name) {
|
|
401
|
+
const { authProxyPath, onError } = ctx;
|
|
402
|
+
try {
|
|
403
|
+
const startResult = await startPasskeyRegistrationAPI(authProxyPath);
|
|
404
|
+
if (startResult.response.status !== 200) {
|
|
405
|
+
onError(new Error("Failed to start passkey registration"));
|
|
406
|
+
return null;
|
|
407
|
+
}
|
|
408
|
+
const credential = await createPasskeyCredential(
|
|
409
|
+
startResult.data
|
|
410
|
+
);
|
|
411
|
+
const finishResult = await finishPasskeyRegistrationAPI(
|
|
412
|
+
authProxyPath,
|
|
413
|
+
{ credential, name }
|
|
414
|
+
);
|
|
415
|
+
if (finishResult.response.status === 200 || finishResult.response.status === 201) {
|
|
416
|
+
return finishResult.data.credential;
|
|
417
|
+
}
|
|
418
|
+
onError(
|
|
419
|
+
new Error("Failed to finish passkey registration")
|
|
420
|
+
);
|
|
421
|
+
return null;
|
|
422
|
+
} catch (error) {
|
|
423
|
+
onError(
|
|
424
|
+
error instanceof Error ? error : new Error("Passkey registration error")
|
|
425
|
+
);
|
|
426
|
+
return null;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
async function deletePasskeyCredentialAction(ctx, credentialId) {
|
|
430
|
+
const { authProxyPath, onError } = ctx;
|
|
431
|
+
try {
|
|
432
|
+
const result = await deletePasskeyCredentialAPI(
|
|
433
|
+
authProxyPath,
|
|
434
|
+
credentialId
|
|
435
|
+
);
|
|
436
|
+
return result.response.status === 200;
|
|
437
|
+
} catch (error) {
|
|
438
|
+
onError(
|
|
439
|
+
error instanceof Error ? error : new Error("Delete passkey error")
|
|
440
|
+
);
|
|
441
|
+
return false;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
254
444
|
var resetUser = (dispatch) => {
|
|
255
445
|
return dispatch({
|
|
256
446
|
type: LOGIN,
|
|
@@ -348,6 +538,107 @@ function IconBack() {
|
|
|
348
538
|
}
|
|
349
539
|
);
|
|
350
540
|
}
|
|
541
|
+
function IconFingerprint() {
|
|
542
|
+
return /* @__PURE__ */ jsxs(
|
|
543
|
+
"svg",
|
|
544
|
+
{
|
|
545
|
+
width: "16",
|
|
546
|
+
height: "16",
|
|
547
|
+
viewBox: "0 0 24 24",
|
|
548
|
+
fill: "none",
|
|
549
|
+
stroke: "currentColor",
|
|
550
|
+
strokeWidth: "2",
|
|
551
|
+
strokeLinecap: "round",
|
|
552
|
+
strokeLinejoin: "round",
|
|
553
|
+
children: [
|
|
554
|
+
/* @__PURE__ */ jsx("path", { d: "M12 10a2 2 0 0 0-2 2c0 1.02-.1 2.51-.26 4" }),
|
|
555
|
+
/* @__PURE__ */ jsx("path", { d: "M14 13.12c0 2.38 0 6.38-1 8.88" }),
|
|
556
|
+
/* @__PURE__ */ jsx("path", { d: "M17.29 21.02c.12-.6.43-2.3.5-3.02" }),
|
|
557
|
+
/* @__PURE__ */ jsx("path", { d: "M2 12a10 10 0 0 1 18-6" }),
|
|
558
|
+
/* @__PURE__ */ jsx("path", { d: "M2 16h.01" }),
|
|
559
|
+
/* @__PURE__ */ jsx("path", { d: "M21.8 16c.2-2 .131-5.354 0-6" }),
|
|
560
|
+
/* @__PURE__ */ jsx("path", { d: "M5 19.5C5.5 18 6 15 6 12a6 6 0 0 1 .34-2" }),
|
|
561
|
+
/* @__PURE__ */ jsx("path", { d: "M8.65 22c.21-.66.45-1.32.57-2" }),
|
|
562
|
+
/* @__PURE__ */ jsx("path", { d: "M9 6.8a6 6 0 0 1 9 5.2v2" })
|
|
563
|
+
]
|
|
564
|
+
}
|
|
565
|
+
);
|
|
566
|
+
}
|
|
567
|
+
function IconShield() {
|
|
568
|
+
return /* @__PURE__ */ jsx(
|
|
569
|
+
"svg",
|
|
570
|
+
{
|
|
571
|
+
width: "20",
|
|
572
|
+
height: "20",
|
|
573
|
+
viewBox: "0 0 24 24",
|
|
574
|
+
fill: "none",
|
|
575
|
+
stroke: "currentColor",
|
|
576
|
+
strokeWidth: "2",
|
|
577
|
+
strokeLinecap: "round",
|
|
578
|
+
strokeLinejoin: "round",
|
|
579
|
+
children: /* @__PURE__ */ jsx("path", { d: "M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z" })
|
|
580
|
+
}
|
|
581
|
+
);
|
|
582
|
+
}
|
|
583
|
+
function IconTrash() {
|
|
584
|
+
return /* @__PURE__ */ jsxs(
|
|
585
|
+
"svg",
|
|
586
|
+
{
|
|
587
|
+
width: "14",
|
|
588
|
+
height: "14",
|
|
589
|
+
viewBox: "0 0 24 24",
|
|
590
|
+
fill: "none",
|
|
591
|
+
stroke: "currentColor",
|
|
592
|
+
strokeWidth: "2",
|
|
593
|
+
strokeLinecap: "round",
|
|
594
|
+
strokeLinejoin: "round",
|
|
595
|
+
children: [
|
|
596
|
+
/* @__PURE__ */ jsx("path", { d: "M3 6h18" }),
|
|
597
|
+
/* @__PURE__ */ jsx("path", { d: "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" }),
|
|
598
|
+
/* @__PURE__ */ jsx("path", { d: "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" })
|
|
599
|
+
]
|
|
600
|
+
}
|
|
601
|
+
);
|
|
602
|
+
}
|
|
603
|
+
function IconLogOut() {
|
|
604
|
+
return /* @__PURE__ */ jsxs(
|
|
605
|
+
"svg",
|
|
606
|
+
{
|
|
607
|
+
width: "16",
|
|
608
|
+
height: "16",
|
|
609
|
+
viewBox: "0 0 24 24",
|
|
610
|
+
fill: "none",
|
|
611
|
+
stroke: "currentColor",
|
|
612
|
+
strokeWidth: "2",
|
|
613
|
+
strokeLinecap: "round",
|
|
614
|
+
strokeLinejoin: "round",
|
|
615
|
+
children: [
|
|
616
|
+
/* @__PURE__ */ jsx("path", { d: "M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" }),
|
|
617
|
+
/* @__PURE__ */ jsx("polyline", { points: "16 17 21 12 16 7" }),
|
|
618
|
+
/* @__PURE__ */ jsx("line", { x1: "21", y1: "12", x2: "9", y2: "12" })
|
|
619
|
+
]
|
|
620
|
+
}
|
|
621
|
+
);
|
|
622
|
+
}
|
|
623
|
+
function IconCamera() {
|
|
624
|
+
return /* @__PURE__ */ jsxs(
|
|
625
|
+
"svg",
|
|
626
|
+
{
|
|
627
|
+
width: "14",
|
|
628
|
+
height: "14",
|
|
629
|
+
viewBox: "0 0 24 24",
|
|
630
|
+
fill: "none",
|
|
631
|
+
stroke: "currentColor",
|
|
632
|
+
strokeWidth: "2",
|
|
633
|
+
strokeLinecap: "round",
|
|
634
|
+
strokeLinejoin: "round",
|
|
635
|
+
children: [
|
|
636
|
+
/* @__PURE__ */ jsx("path", { d: "M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z" }),
|
|
637
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "13", r: "3" })
|
|
638
|
+
]
|
|
639
|
+
}
|
|
640
|
+
);
|
|
641
|
+
}
|
|
351
642
|
function Spinner() {
|
|
352
643
|
return /* @__PURE__ */ jsx("span", { style: spinnerStyle, "aria-hidden": "true" });
|
|
353
644
|
}
|
|
@@ -375,7 +666,10 @@ function useModalAnimation(open) {
|
|
|
375
666
|
}
|
|
376
667
|
if (phase === "entered" || phase === "entering") {
|
|
377
668
|
setPhase("exiting");
|
|
378
|
-
const timer = setTimeout(
|
|
669
|
+
const timer = setTimeout(
|
|
670
|
+
() => setPhase("exited"),
|
|
671
|
+
MOBILE_TRANSITION_MS
|
|
672
|
+
);
|
|
379
673
|
return () => clearTimeout(timer);
|
|
380
674
|
}
|
|
381
675
|
return void 0;
|
|
@@ -443,27 +737,64 @@ function useScrollLock(active) {
|
|
|
443
737
|
};
|
|
444
738
|
}, [active]);
|
|
445
739
|
}
|
|
446
|
-
function DauthProfileModal({
|
|
447
|
-
|
|
740
|
+
function DauthProfileModal({
|
|
741
|
+
open,
|
|
742
|
+
onClose,
|
|
743
|
+
onAvatarUpload
|
|
744
|
+
}) {
|
|
745
|
+
const {
|
|
746
|
+
user,
|
|
747
|
+
domain,
|
|
748
|
+
updateUser,
|
|
749
|
+
deleteAccount,
|
|
750
|
+
logout,
|
|
751
|
+
getPasskeyCredentials,
|
|
752
|
+
registerPasskey,
|
|
753
|
+
deletePasskeyCredential
|
|
754
|
+
} = useDauth();
|
|
448
755
|
const isDesktop = useMediaQuery("(min-width: 641px)");
|
|
449
756
|
const phase = useModalAnimation(open);
|
|
450
757
|
const modalRef = useRef(null);
|
|
758
|
+
const avatarInputRef = useRef(null);
|
|
759
|
+
const showSecurity = domain.authMethods?.passkey === true;
|
|
760
|
+
const [activeTab, setActiveTab] = useState("profile");
|
|
451
761
|
const [name, setName] = useState("");
|
|
452
762
|
const [lastname, setLastname] = useState("");
|
|
453
763
|
const [nickname, setNickname] = useState("");
|
|
454
764
|
const [country, setCountry] = useState("");
|
|
765
|
+
const [telPrefix, setTelPrefix] = useState("");
|
|
766
|
+
const [telSuffix, setTelSuffix] = useState("");
|
|
767
|
+
const [birthDate, setBirthDate] = useState("");
|
|
768
|
+
const [customFieldValues, setCustomFieldValues] = useState({});
|
|
455
769
|
const [populated, setPopulated] = useState(false);
|
|
456
770
|
const [saving, setSaving] = useState(false);
|
|
457
771
|
const [status, setStatus] = useState(null);
|
|
458
772
|
const [showDelete, setShowDelete] = useState(false);
|
|
459
773
|
const [deleteText, setDeleteText] = useState("");
|
|
460
774
|
const [deleting, setDeleting] = useState(false);
|
|
775
|
+
const [credentials, setCredentials] = useState([]);
|
|
776
|
+
const [loadingCreds, setLoadingCreds] = useState(false);
|
|
777
|
+
const [showRegister, setShowRegister] = useState(false);
|
|
778
|
+
const [passkeyName, setPasskeyName] = useState("");
|
|
779
|
+
const [registering, setRegistering] = useState(false);
|
|
780
|
+
const [passkeyStatus, setPasskeyStatus] = useState(null);
|
|
781
|
+
const [uploadingAvatar, setUploadingAvatar] = useState(false);
|
|
461
782
|
useEffect(() => {
|
|
462
783
|
if (open && user?._id && !populated) {
|
|
463
784
|
setName(user.name || "");
|
|
464
785
|
setLastname(user.lastname || "");
|
|
465
786
|
setNickname(user.nickname || "");
|
|
466
787
|
setCountry(user.country || "");
|
|
788
|
+
setTelPrefix(user.telPrefix || "");
|
|
789
|
+
setTelSuffix(user.telSuffix || "");
|
|
790
|
+
setBirthDate(
|
|
791
|
+
user.birthDate ? new Date(user.birthDate).toISOString().split("T")[0] : ""
|
|
792
|
+
);
|
|
793
|
+
const cf = {};
|
|
794
|
+
for (const f of domain.customFields ?? []) {
|
|
795
|
+
cf[f.key] = user.customFields?.[f.key] ?? "";
|
|
796
|
+
}
|
|
797
|
+
setCustomFieldValues(cf);
|
|
467
798
|
setPopulated(true);
|
|
468
799
|
}
|
|
469
800
|
if (!open) {
|
|
@@ -471,13 +802,36 @@ function DauthProfileModal({ open, onClose }) {
|
|
|
471
802
|
setStatus(null);
|
|
472
803
|
setShowDelete(false);
|
|
473
804
|
setDeleteText("");
|
|
805
|
+
setActiveTab("profile");
|
|
806
|
+
setPasskeyStatus(null);
|
|
807
|
+
setShowRegister(false);
|
|
808
|
+
setPasskeyName("");
|
|
474
809
|
}
|
|
475
810
|
}, [open, user, populated]);
|
|
811
|
+
useEffect(() => {
|
|
812
|
+
if (activeTab !== "security" || !showSecurity) return;
|
|
813
|
+
setLoadingCreds(true);
|
|
814
|
+
getPasskeyCredentials().then((creds) => {
|
|
815
|
+
setCredentials(creds);
|
|
816
|
+
setLoadingCreds(false);
|
|
817
|
+
});
|
|
818
|
+
}, [activeTab, showSecurity, getPasskeyCredentials]);
|
|
476
819
|
useEffect(() => {
|
|
477
820
|
if (status?.type !== "success") return;
|
|
478
|
-
const timer = setTimeout(
|
|
821
|
+
const timer = setTimeout(
|
|
822
|
+
() => setStatus(null),
|
|
823
|
+
SUCCESS_TIMEOUT_MS
|
|
824
|
+
);
|
|
479
825
|
return () => clearTimeout(timer);
|
|
480
826
|
}, [status]);
|
|
827
|
+
useEffect(() => {
|
|
828
|
+
if (passkeyStatus?.type !== "success") return;
|
|
829
|
+
const timer = setTimeout(
|
|
830
|
+
() => setPasskeyStatus(null),
|
|
831
|
+
SUCCESS_TIMEOUT_MS
|
|
832
|
+
);
|
|
833
|
+
return () => clearTimeout(timer);
|
|
834
|
+
}, [passkeyStatus]);
|
|
481
835
|
useFocusTrap(modalRef, phase === "entered", onClose);
|
|
482
836
|
useScrollLock(phase !== "exited");
|
|
483
837
|
const hasField = useCallback(
|
|
@@ -490,8 +844,23 @@ function DauthProfileModal({ open, onClose }) {
|
|
|
490
844
|
);
|
|
491
845
|
const hasChanges = useMemo(() => {
|
|
492
846
|
if (!user?._id) return false;
|
|
493
|
-
|
|
494
|
-
|
|
847
|
+
const origBirthDate = user.birthDate ? new Date(user.birthDate).toISOString().split("T")[0] : "";
|
|
848
|
+
const cfChanged = (domain.customFields ?? []).some(
|
|
849
|
+
(f) => (customFieldValues[f.key] ?? "") !== (user.customFields?.[f.key] ?? "")
|
|
850
|
+
);
|
|
851
|
+
return name !== (user.name || "") || lastname !== (user.lastname || "") || nickname !== (user.nickname || "") || country !== (user.country || "") || telPrefix !== (user.telPrefix || "") || telSuffix !== (user.telSuffix || "") || birthDate !== origBirthDate || cfChanged;
|
|
852
|
+
}, [
|
|
853
|
+
name,
|
|
854
|
+
lastname,
|
|
855
|
+
nickname,
|
|
856
|
+
country,
|
|
857
|
+
telPrefix,
|
|
858
|
+
telSuffix,
|
|
859
|
+
birthDate,
|
|
860
|
+
customFieldValues,
|
|
861
|
+
user,
|
|
862
|
+
domain.customFields
|
|
863
|
+
]);
|
|
495
864
|
const canSave = name.trim().length > 0 && hasChanges && !saving;
|
|
496
865
|
const handleSave = useCallback(async () => {
|
|
497
866
|
setSaving(true);
|
|
@@ -500,6 +869,14 @@ function DauthProfileModal({ open, onClose }) {
|
|
|
500
869
|
if (hasField("lastname")) fields.lastname = lastname;
|
|
501
870
|
if (hasField("nickname")) fields.nickname = nickname;
|
|
502
871
|
if (hasField("country")) fields.country = country;
|
|
872
|
+
if (hasField("tel_prefix"))
|
|
873
|
+
fields.telPrefix = telPrefix;
|
|
874
|
+
if (hasField("tel_suffix"))
|
|
875
|
+
fields.telSuffix = telSuffix;
|
|
876
|
+
if (hasField("birth_date") && birthDate)
|
|
877
|
+
fields.birthDate = birthDate;
|
|
878
|
+
if ((domain.customFields ?? []).length > 0)
|
|
879
|
+
fields.customFields = customFieldValues;
|
|
503
880
|
const ok = await updateUser(fields);
|
|
504
881
|
setSaving(false);
|
|
505
882
|
if (ok) {
|
|
@@ -513,7 +890,19 @@ function DauthProfileModal({ open, onClose }) {
|
|
|
513
890
|
message: "Something went wrong. Please try again."
|
|
514
891
|
});
|
|
515
892
|
}
|
|
516
|
-
}, [
|
|
893
|
+
}, [
|
|
894
|
+
name,
|
|
895
|
+
lastname,
|
|
896
|
+
nickname,
|
|
897
|
+
country,
|
|
898
|
+
telPrefix,
|
|
899
|
+
telSuffix,
|
|
900
|
+
birthDate,
|
|
901
|
+
customFieldValues,
|
|
902
|
+
hasField,
|
|
903
|
+
updateUser,
|
|
904
|
+
domain.customFields
|
|
905
|
+
]);
|
|
517
906
|
const handleDelete = useCallback(async () => {
|
|
518
907
|
setDeleting(true);
|
|
519
908
|
const ok = await deleteAccount();
|
|
@@ -529,16 +918,87 @@ function DauthProfileModal({ open, onClose }) {
|
|
|
529
918
|
setDeleteText("");
|
|
530
919
|
}
|
|
531
920
|
}, [deleteAccount, onClose]);
|
|
921
|
+
const handleLanguage = useCallback(
|
|
922
|
+
async (lang) => {
|
|
923
|
+
await updateUser({ language: lang });
|
|
924
|
+
},
|
|
925
|
+
[updateUser]
|
|
926
|
+
);
|
|
927
|
+
const handleRegisterPasskey = useCallback(async () => {
|
|
928
|
+
setRegistering(true);
|
|
929
|
+
setPasskeyStatus(null);
|
|
930
|
+
const cred = await registerPasskey(
|
|
931
|
+
passkeyName || void 0
|
|
932
|
+
);
|
|
933
|
+
setRegistering(false);
|
|
934
|
+
if (cred) {
|
|
935
|
+
setCredentials((prev) => [...prev, cred]);
|
|
936
|
+
setPasskeyName("");
|
|
937
|
+
setShowRegister(false);
|
|
938
|
+
setPasskeyStatus({
|
|
939
|
+
type: "success",
|
|
940
|
+
message: "Passkey registered successfully"
|
|
941
|
+
});
|
|
942
|
+
} else {
|
|
943
|
+
setPasskeyStatus({
|
|
944
|
+
type: "error",
|
|
945
|
+
message: "Failed to register passkey"
|
|
946
|
+
});
|
|
947
|
+
}
|
|
948
|
+
}, [passkeyName, registerPasskey]);
|
|
949
|
+
const handleDeletePasskey = useCallback(
|
|
950
|
+
async (credentialId) => {
|
|
951
|
+
const ok = await deletePasskeyCredential(credentialId);
|
|
952
|
+
if (ok) {
|
|
953
|
+
setCredentials(
|
|
954
|
+
(prev) => prev.filter((c) => c._id !== credentialId)
|
|
955
|
+
);
|
|
956
|
+
}
|
|
957
|
+
},
|
|
958
|
+
[deletePasskeyCredential]
|
|
959
|
+
);
|
|
960
|
+
const handleAvatarClick = useCallback(() => {
|
|
961
|
+
if (onAvatarUpload) {
|
|
962
|
+
avatarInputRef.current?.click();
|
|
963
|
+
}
|
|
964
|
+
}, [onAvatarUpload]);
|
|
965
|
+
const handleAvatarChange = useCallback(
|
|
966
|
+
async (e) => {
|
|
967
|
+
const file = e.target.files?.[0];
|
|
968
|
+
if (!file || !onAvatarUpload) return;
|
|
969
|
+
setUploadingAvatar(true);
|
|
970
|
+
try {
|
|
971
|
+
const url = await onAvatarUpload(file);
|
|
972
|
+
if (url) {
|
|
973
|
+
await updateUser({ avatar: url });
|
|
974
|
+
}
|
|
975
|
+
} catch {
|
|
976
|
+
}
|
|
977
|
+
setUploadingAvatar(false);
|
|
978
|
+
if (avatarInputRef.current) {
|
|
979
|
+
avatarInputRef.current.value = "";
|
|
980
|
+
}
|
|
981
|
+
},
|
|
982
|
+
[onAvatarUpload, updateUser]
|
|
983
|
+
);
|
|
984
|
+
const handleSignOut = useCallback(() => {
|
|
985
|
+
logout();
|
|
986
|
+
onClose();
|
|
987
|
+
}, [logout, onClose]);
|
|
532
988
|
const themeVars = useMemo(() => {
|
|
533
989
|
const t = domain.modalTheme;
|
|
534
990
|
if (!t) return {};
|
|
535
991
|
const vars = {};
|
|
536
992
|
if (t.accent) vars["--dauth-accent"] = t.accent;
|
|
537
|
-
if (t.accentHover)
|
|
993
|
+
if (t.accentHover)
|
|
994
|
+
vars["--dauth-accent-hover"] = t.accentHover;
|
|
538
995
|
if (t.surface) vars["--dauth-surface"] = t.surface;
|
|
539
|
-
if (t.surfaceHover)
|
|
540
|
-
|
|
541
|
-
if (t.
|
|
996
|
+
if (t.surfaceHover)
|
|
997
|
+
vars["--dauth-surface-hover"] = t.surfaceHover;
|
|
998
|
+
if (t.textPrimary)
|
|
999
|
+
vars["--dauth-text-primary"] = t.textPrimary;
|
|
1000
|
+
if (t.textSecondary)
|
|
1001
|
+
vars["--dauth-text-secondary"] = t.textSecondary;
|
|
542
1002
|
if (t.border) vars["--dauth-border"] = t.border;
|
|
543
1003
|
return vars;
|
|
544
1004
|
}, [domain.modalTheme]);
|
|
@@ -589,6 +1049,11 @@ function DauthProfileModal({ open, onClose }) {
|
|
|
589
1049
|
transition: `transform ${dur}ms ${easing}`
|
|
590
1050
|
};
|
|
591
1051
|
const avatarInitial = (user.name || user.email || "?").charAt(0).toUpperCase();
|
|
1052
|
+
const tabs = [
|
|
1053
|
+
{ key: "profile", label: "Profile" },
|
|
1054
|
+
...showSecurity ? [{ key: "security", label: "Security" }] : [],
|
|
1055
|
+
{ key: "account", label: "Account" }
|
|
1056
|
+
];
|
|
592
1057
|
return createPortal(
|
|
593
1058
|
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
594
1059
|
/* @__PURE__ */ jsx(
|
|
@@ -632,191 +1097,663 @@ function DauthProfileModal({ open, onClose }) {
|
|
|
632
1097
|
/* @__PURE__ */ jsx("h2", { id: "dauth-profile-title", style: titleStyle, children: "Your Profile" }),
|
|
633
1098
|
/* @__PURE__ */ jsx("div", { style: { width: 36 } })
|
|
634
1099
|
] }),
|
|
1100
|
+
/* @__PURE__ */ jsx("div", { style: tabBar, role: "tablist", children: tabs.map((t) => /* @__PURE__ */ jsx(
|
|
1101
|
+
"button",
|
|
1102
|
+
{
|
|
1103
|
+
role: "tab",
|
|
1104
|
+
type: "button",
|
|
1105
|
+
"aria-selected": activeTab === t.key,
|
|
1106
|
+
style: {
|
|
1107
|
+
...tabBtn,
|
|
1108
|
+
color: activeTab === t.key ? "var(--dauth-accent, #6366f1)" : "var(--dauth-text-secondary, #a1a1aa)",
|
|
1109
|
+
borderBottomColor: activeTab === t.key ? "var(--dauth-accent, #6366f1)" : "transparent"
|
|
1110
|
+
},
|
|
1111
|
+
onClick: () => setActiveTab(t.key),
|
|
1112
|
+
children: t.label
|
|
1113
|
+
},
|
|
1114
|
+
t.key
|
|
1115
|
+
)) }),
|
|
635
1116
|
/* @__PURE__ */ jsxs("div", { style: bodyStyle, children: [
|
|
636
|
-
/* @__PURE__ */ jsxs(
|
|
637
|
-
/* @__PURE__ */
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
src: user.avatar.url,
|
|
641
|
-
alt: "",
|
|
642
|
-
style: {
|
|
643
|
-
width: "100%",
|
|
644
|
-
height: "100%",
|
|
645
|
-
objectFit: "cover"
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
) : avatarInitial }),
|
|
649
|
-
/* @__PURE__ */ jsx("div", { style: emailText, children: user.email })
|
|
650
|
-
] }),
|
|
651
|
-
status && /* @__PURE__ */ jsx(
|
|
652
|
-
"div",
|
|
653
|
-
{
|
|
654
|
-
role: "status",
|
|
655
|
-
"aria-live": "polite",
|
|
656
|
-
style: statusMsg(status.type),
|
|
657
|
-
children: status.message
|
|
658
|
-
}
|
|
659
|
-
),
|
|
660
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
661
|
-
/* @__PURE__ */ jsxs("div", { style: fieldGroup, children: [
|
|
662
|
-
/* @__PURE__ */ jsx("label", { htmlFor: "dauth-name", style: label, children: "Name *" }),
|
|
663
|
-
/* @__PURE__ */ jsx(
|
|
664
|
-
"input",
|
|
1117
|
+
activeTab === "profile" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1118
|
+
/* @__PURE__ */ jsxs("div", { style: avatarSection, children: [
|
|
1119
|
+
/* @__PURE__ */ jsxs(
|
|
1120
|
+
"div",
|
|
665
1121
|
{
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
1122
|
+
style: {
|
|
1123
|
+
...avatarCircle,
|
|
1124
|
+
cursor: onAvatarUpload ? "pointer" : "default",
|
|
1125
|
+
position: "relative"
|
|
1126
|
+
},
|
|
1127
|
+
onClick: handleAvatarClick,
|
|
1128
|
+
children: [
|
|
1129
|
+
uploadingAvatar ? /* @__PURE__ */ jsx(Spinner, {}) : user.avatar?.url ? /* @__PURE__ */ jsx(
|
|
1130
|
+
"img",
|
|
1131
|
+
{
|
|
1132
|
+
src: user.avatar.url,
|
|
1133
|
+
alt: "",
|
|
1134
|
+
style: {
|
|
1135
|
+
width: "100%",
|
|
1136
|
+
height: "100%",
|
|
1137
|
+
objectFit: "cover"
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
) : avatarInitial,
|
|
1141
|
+
onAvatarUpload && !uploadingAvatar && /* @__PURE__ */ jsx("div", { style: avatarOverlay, children: /* @__PURE__ */ jsx(IconCamera, {}) })
|
|
1142
|
+
]
|
|
675
1143
|
}
|
|
676
|
-
)
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
/* @__PURE__ */ jsxs("label", { htmlFor: "dauth-lastname", style: label, children: [
|
|
680
|
-
"Last name",
|
|
681
|
-
isRequired("lastname") ? " *" : ""
|
|
682
|
-
] }),
|
|
683
|
-
/* @__PURE__ */ jsx(
|
|
1144
|
+
),
|
|
1145
|
+
/* @__PURE__ */ jsx("div", { style: emailText, children: user.email }),
|
|
1146
|
+
onAvatarUpload && /* @__PURE__ */ jsx(
|
|
684
1147
|
"input",
|
|
685
1148
|
{
|
|
686
|
-
|
|
687
|
-
type: "
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
disabled: saving,
|
|
692
|
-
style: input,
|
|
693
|
-
onFocus: inputFocusHandler,
|
|
694
|
-
onBlur: inputBlurHandler
|
|
1149
|
+
ref: avatarInputRef,
|
|
1150
|
+
type: "file",
|
|
1151
|
+
accept: "image/*",
|
|
1152
|
+
style: { display: "none" },
|
|
1153
|
+
onChange: handleAvatarChange
|
|
695
1154
|
}
|
|
696
1155
|
)
|
|
697
1156
|
] }),
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
1157
|
+
status && /* @__PURE__ */ jsx(
|
|
1158
|
+
"div",
|
|
1159
|
+
{
|
|
1160
|
+
role: "status",
|
|
1161
|
+
"aria-live": "polite",
|
|
1162
|
+
style: statusMsg(status.type),
|
|
1163
|
+
children: status.message
|
|
1164
|
+
}
|
|
1165
|
+
),
|
|
1166
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1167
|
+
/* @__PURE__ */ jsxs("div", { style: fieldGroup, children: [
|
|
1168
|
+
/* @__PURE__ */ jsx(
|
|
1169
|
+
"label",
|
|
1170
|
+
{
|
|
1171
|
+
htmlFor: "dauth-name",
|
|
1172
|
+
style: label,
|
|
1173
|
+
children: "Name *"
|
|
1174
|
+
}
|
|
1175
|
+
),
|
|
1176
|
+
/* @__PURE__ */ jsx(
|
|
1177
|
+
"input",
|
|
1178
|
+
{
|
|
1179
|
+
id: "dauth-name",
|
|
1180
|
+
type: "text",
|
|
1181
|
+
value: name,
|
|
1182
|
+
onChange: (e) => setName(e.target.value),
|
|
1183
|
+
placeholder: "Your name",
|
|
1184
|
+
disabled: saving,
|
|
1185
|
+
style: input,
|
|
1186
|
+
onFocus: inputFocusHandler,
|
|
1187
|
+
onBlur: inputBlurHandler
|
|
1188
|
+
}
|
|
1189
|
+
)
|
|
702
1190
|
] }),
|
|
703
|
-
/* @__PURE__ */
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
1191
|
+
hasField("lastname") && /* @__PURE__ */ jsxs("div", { style: fieldGroup, children: [
|
|
1192
|
+
/* @__PURE__ */ jsxs(
|
|
1193
|
+
"label",
|
|
1194
|
+
{
|
|
1195
|
+
htmlFor: "dauth-lastname",
|
|
1196
|
+
style: label,
|
|
1197
|
+
children: [
|
|
1198
|
+
"Last name",
|
|
1199
|
+
isRequired("lastname") ? " *" : ""
|
|
1200
|
+
]
|
|
1201
|
+
}
|
|
1202
|
+
),
|
|
1203
|
+
/* @__PURE__ */ jsx(
|
|
1204
|
+
"input",
|
|
1205
|
+
{
|
|
1206
|
+
id: "dauth-lastname",
|
|
1207
|
+
type: "text",
|
|
1208
|
+
value: lastname,
|
|
1209
|
+
onChange: (e) => setLastname(e.target.value),
|
|
1210
|
+
placeholder: "Your last name",
|
|
1211
|
+
disabled: saving,
|
|
1212
|
+
style: input,
|
|
1213
|
+
onFocus: inputFocusHandler,
|
|
1214
|
+
onBlur: inputBlurHandler
|
|
1215
|
+
}
|
|
1216
|
+
)
|
|
722
1217
|
] }),
|
|
723
|
-
/* @__PURE__ */
|
|
724
|
-
|
|
1218
|
+
hasField("nickname") && /* @__PURE__ */ jsxs("div", { style: fieldGroup, children: [
|
|
1219
|
+
/* @__PURE__ */ jsxs(
|
|
1220
|
+
"label",
|
|
1221
|
+
{
|
|
1222
|
+
htmlFor: "dauth-nickname",
|
|
1223
|
+
style: label,
|
|
1224
|
+
children: [
|
|
1225
|
+
"Nickname",
|
|
1226
|
+
isRequired("nickname") ? " *" : ""
|
|
1227
|
+
]
|
|
1228
|
+
}
|
|
1229
|
+
),
|
|
1230
|
+
/* @__PURE__ */ jsx(
|
|
1231
|
+
"input",
|
|
1232
|
+
{
|
|
1233
|
+
id: "dauth-nickname",
|
|
1234
|
+
type: "text",
|
|
1235
|
+
value: nickname,
|
|
1236
|
+
onChange: (e) => setNickname(e.target.value),
|
|
1237
|
+
placeholder: "Choose a nickname",
|
|
1238
|
+
disabled: saving,
|
|
1239
|
+
style: input,
|
|
1240
|
+
onFocus: inputFocusHandler,
|
|
1241
|
+
onBlur: inputBlurHandler
|
|
1242
|
+
}
|
|
1243
|
+
)
|
|
1244
|
+
] }),
|
|
1245
|
+
hasField("country") && /* @__PURE__ */ jsxs("div", { style: fieldGroup, children: [
|
|
1246
|
+
/* @__PURE__ */ jsxs(
|
|
1247
|
+
"label",
|
|
1248
|
+
{
|
|
1249
|
+
htmlFor: "dauth-country",
|
|
1250
|
+
style: label,
|
|
1251
|
+
children: [
|
|
1252
|
+
"Country",
|
|
1253
|
+
isRequired("country") ? " *" : ""
|
|
1254
|
+
]
|
|
1255
|
+
}
|
|
1256
|
+
),
|
|
1257
|
+
/* @__PURE__ */ jsx(
|
|
1258
|
+
"input",
|
|
1259
|
+
{
|
|
1260
|
+
id: "dauth-country",
|
|
1261
|
+
type: "text",
|
|
1262
|
+
value: country,
|
|
1263
|
+
onChange: (e) => setCountry(e.target.value),
|
|
1264
|
+
placeholder: "Your country",
|
|
1265
|
+
disabled: saving,
|
|
1266
|
+
style: input,
|
|
1267
|
+
onFocus: inputFocusHandler,
|
|
1268
|
+
onBlur: inputBlurHandler
|
|
1269
|
+
}
|
|
1270
|
+
)
|
|
1271
|
+
] }),
|
|
1272
|
+
(hasField("tel_prefix") || hasField("tel_suffix")) && /* @__PURE__ */ jsxs("div", { style: fieldGroup, children: [
|
|
1273
|
+
/* @__PURE__ */ jsxs("div", { style: label, children: [
|
|
1274
|
+
"Phone",
|
|
1275
|
+
isRequired("tel_prefix") || isRequired("tel_suffix") ? " *" : ""
|
|
1276
|
+
] }),
|
|
1277
|
+
/* @__PURE__ */ jsxs(
|
|
1278
|
+
"div",
|
|
1279
|
+
{
|
|
1280
|
+
style: {
|
|
1281
|
+
display: "flex",
|
|
1282
|
+
gap: 8
|
|
1283
|
+
},
|
|
1284
|
+
children: [
|
|
1285
|
+
hasField("tel_prefix") && /* @__PURE__ */ jsx(
|
|
1286
|
+
"input",
|
|
1287
|
+
{
|
|
1288
|
+
id: "dauth-tel-prefix",
|
|
1289
|
+
type: "text",
|
|
1290
|
+
value: telPrefix,
|
|
1291
|
+
onChange: (e) => setTelPrefix(e.target.value),
|
|
1292
|
+
placeholder: "+34",
|
|
1293
|
+
disabled: saving,
|
|
1294
|
+
style: {
|
|
1295
|
+
...input,
|
|
1296
|
+
width: 80,
|
|
1297
|
+
flexShrink: 0
|
|
1298
|
+
},
|
|
1299
|
+
onFocus: inputFocusHandler,
|
|
1300
|
+
onBlur: inputBlurHandler,
|
|
1301
|
+
"aria-label": "Phone prefix"
|
|
1302
|
+
}
|
|
1303
|
+
),
|
|
1304
|
+
hasField("tel_suffix") && /* @__PURE__ */ jsx(
|
|
1305
|
+
"input",
|
|
1306
|
+
{
|
|
1307
|
+
id: "dauth-tel-suffix",
|
|
1308
|
+
type: "tel",
|
|
1309
|
+
value: telSuffix,
|
|
1310
|
+
onChange: (e) => setTelSuffix(e.target.value),
|
|
1311
|
+
placeholder: "612 345 678",
|
|
1312
|
+
disabled: saving,
|
|
1313
|
+
style: {
|
|
1314
|
+
...input,
|
|
1315
|
+
flex: 1
|
|
1316
|
+
},
|
|
1317
|
+
onFocus: inputFocusHandler,
|
|
1318
|
+
onBlur: inputBlurHandler,
|
|
1319
|
+
"aria-label": "Phone number"
|
|
1320
|
+
}
|
|
1321
|
+
)
|
|
1322
|
+
]
|
|
1323
|
+
}
|
|
1324
|
+
)
|
|
1325
|
+
] }),
|
|
1326
|
+
hasField("birth_date") && /* @__PURE__ */ jsxs("div", { style: fieldGroup, children: [
|
|
1327
|
+
/* @__PURE__ */ jsxs(
|
|
1328
|
+
"label",
|
|
1329
|
+
{
|
|
1330
|
+
htmlFor: "dauth-birthdate",
|
|
1331
|
+
style: label,
|
|
1332
|
+
children: [
|
|
1333
|
+
"Birth date",
|
|
1334
|
+
isRequired("birth_date") ? " *" : ""
|
|
1335
|
+
]
|
|
1336
|
+
}
|
|
1337
|
+
),
|
|
1338
|
+
/* @__PURE__ */ jsx(
|
|
1339
|
+
"input",
|
|
1340
|
+
{
|
|
1341
|
+
id: "dauth-birthdate",
|
|
1342
|
+
type: "date",
|
|
1343
|
+
value: birthDate,
|
|
1344
|
+
onChange: (e) => setBirthDate(e.target.value),
|
|
1345
|
+
disabled: saving,
|
|
1346
|
+
style: input,
|
|
1347
|
+
onFocus: inputFocusHandler,
|
|
1348
|
+
onBlur: inputBlurHandler
|
|
1349
|
+
}
|
|
1350
|
+
)
|
|
1351
|
+
] }),
|
|
1352
|
+
(domain.customFields ?? []).length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1353
|
+
/* @__PURE__ */ jsx("hr", { style: separator }),
|
|
1354
|
+
domain.customFields.map((cf) => /* @__PURE__ */ jsxs(
|
|
1355
|
+
"div",
|
|
1356
|
+
{
|
|
1357
|
+
style: fieldGroup,
|
|
1358
|
+
children: [
|
|
1359
|
+
/* @__PURE__ */ jsxs(
|
|
1360
|
+
"label",
|
|
1361
|
+
{
|
|
1362
|
+
htmlFor: `dauth-cf-${cf.key}`,
|
|
1363
|
+
style: label,
|
|
1364
|
+
children: [
|
|
1365
|
+
cf.label,
|
|
1366
|
+
cf.required ? " *" : ""
|
|
1367
|
+
]
|
|
1368
|
+
}
|
|
1369
|
+
),
|
|
1370
|
+
/* @__PURE__ */ jsx(
|
|
1371
|
+
"input",
|
|
1372
|
+
{
|
|
1373
|
+
id: `dauth-cf-${cf.key}`,
|
|
1374
|
+
type: "text",
|
|
1375
|
+
value: customFieldValues[cf.key] ?? "",
|
|
1376
|
+
onChange: (e) => setCustomFieldValues(
|
|
1377
|
+
(prev) => ({
|
|
1378
|
+
...prev,
|
|
1379
|
+
[cf.key]: e.target.value
|
|
1380
|
+
})
|
|
1381
|
+
),
|
|
1382
|
+
disabled: saving,
|
|
1383
|
+
style: input,
|
|
1384
|
+
onFocus: inputFocusHandler,
|
|
1385
|
+
onBlur: inputBlurHandler
|
|
1386
|
+
}
|
|
1387
|
+
)
|
|
1388
|
+
]
|
|
1389
|
+
},
|
|
1390
|
+
cf.key
|
|
1391
|
+
))
|
|
1392
|
+
] })
|
|
1393
|
+
] }),
|
|
1394
|
+
/* @__PURE__ */ jsx("hr", { style: separator }),
|
|
1395
|
+
/* @__PURE__ */ jsxs("div", { style: fieldGroup, children: [
|
|
1396
|
+
/* @__PURE__ */ jsx("div", { style: label, children: "Language" }),
|
|
1397
|
+
/* @__PURE__ */ jsx("div", { style: { display: "flex", gap: 8 }, children: ["es", "en"].map((lang) => /* @__PURE__ */ jsx(
|
|
1398
|
+
"button",
|
|
725
1399
|
{
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
)
|
|
1400
|
+
type: "button",
|
|
1401
|
+
style: {
|
|
1402
|
+
...langBtn,
|
|
1403
|
+
backgroundColor: user.language === lang ? "var(--dauth-accent, #6366f1)" : "var(--dauth-surface-secondary, rgba(255, 255, 255, 0.04))",
|
|
1404
|
+
color: user.language === lang ? "#ffffff" : "var(--dauth-text-secondary, #a1a1aa)"
|
|
1405
|
+
},
|
|
1406
|
+
onClick: () => handleLanguage(lang),
|
|
1407
|
+
children: lang === "es" ? "Espa\xF1ol" : "English"
|
|
1408
|
+
},
|
|
1409
|
+
lang
|
|
1410
|
+
)) })
|
|
737
1411
|
] })
|
|
738
1412
|
] }),
|
|
739
|
-
/* @__PURE__ */
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
/* @__PURE__ */ jsx("div", { style: dangerDesc, children: "Permanently delete your account and all associated data." }),
|
|
743
|
-
!showDelete ? /* @__PURE__ */ jsx(
|
|
744
|
-
"button",
|
|
1413
|
+
activeTab === "security" && showSecurity && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1414
|
+
/* @__PURE__ */ jsxs(
|
|
1415
|
+
"div",
|
|
745
1416
|
{
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
1417
|
+
style: {
|
|
1418
|
+
display: "flex",
|
|
1419
|
+
alignItems: "center",
|
|
1420
|
+
justifyContent: "space-between",
|
|
1421
|
+
marginBottom: 16
|
|
1422
|
+
},
|
|
1423
|
+
children: [
|
|
1424
|
+
/* @__PURE__ */ jsx(
|
|
1425
|
+
"div",
|
|
1426
|
+
{
|
|
1427
|
+
style: {
|
|
1428
|
+
...label,
|
|
1429
|
+
marginBottom: 0,
|
|
1430
|
+
fontWeight: 600
|
|
1431
|
+
},
|
|
1432
|
+
children: "Passkeys"
|
|
1433
|
+
}
|
|
1434
|
+
),
|
|
1435
|
+
/* @__PURE__ */ jsx(
|
|
1436
|
+
"button",
|
|
1437
|
+
{
|
|
1438
|
+
type: "button",
|
|
1439
|
+
style: outlineBtn,
|
|
1440
|
+
onClick: () => setShowRegister(!showRegister),
|
|
1441
|
+
onMouseEnter: (e) => e.currentTarget.style.backgroundColor = "var(--dauth-surface-hover, #232340)",
|
|
1442
|
+
onMouseLeave: (e) => e.currentTarget.style.backgroundColor = "transparent",
|
|
1443
|
+
children: "+ Add passkey"
|
|
1444
|
+
}
|
|
1445
|
+
)
|
|
1446
|
+
]
|
|
752
1447
|
}
|
|
753
|
-
)
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
1448
|
+
),
|
|
1449
|
+
showRegister && /* @__PURE__ */ jsxs("div", { style: registerPanel, children: [
|
|
1450
|
+
/* @__PURE__ */ jsxs("div", { style: fieldGroup, children: [
|
|
1451
|
+
/* @__PURE__ */ jsx(
|
|
1452
|
+
"label",
|
|
1453
|
+
{
|
|
1454
|
+
htmlFor: "dauth-passkey-name",
|
|
1455
|
+
style: label,
|
|
1456
|
+
children: "Passkey name (optional)"
|
|
1457
|
+
}
|
|
1458
|
+
),
|
|
1459
|
+
/* @__PURE__ */ jsx(
|
|
1460
|
+
"input",
|
|
1461
|
+
{
|
|
1462
|
+
id: "dauth-passkey-name",
|
|
1463
|
+
type: "text",
|
|
1464
|
+
value: passkeyName,
|
|
1465
|
+
onChange: (e) => setPasskeyName(e.target.value),
|
|
1466
|
+
placeholder: "e.g. MacBook Touch ID",
|
|
1467
|
+
disabled: registering,
|
|
1468
|
+
style: input,
|
|
1469
|
+
onFocus: inputFocusHandler,
|
|
1470
|
+
onBlur: inputBlurHandler
|
|
1471
|
+
}
|
|
1472
|
+
)
|
|
759
1473
|
] }),
|
|
760
|
-
/* @__PURE__ */ jsx(
|
|
761
|
-
"input",
|
|
762
|
-
{
|
|
763
|
-
type: "text",
|
|
764
|
-
value: deleteText,
|
|
765
|
-
onChange: (e) => setDeleteText(e.target.value),
|
|
766
|
-
placeholder: `Type ${CONFIRM_WORD}`,
|
|
767
|
-
style: input,
|
|
768
|
-
onFocus: inputFocusHandler,
|
|
769
|
-
onBlur: inputBlurHandler,
|
|
770
|
-
disabled: deleting
|
|
771
|
-
}
|
|
772
|
-
),
|
|
773
1474
|
/* @__PURE__ */ jsxs(
|
|
774
1475
|
"div",
|
|
775
1476
|
{
|
|
776
1477
|
style: {
|
|
777
1478
|
display: "flex",
|
|
778
|
-
gap: 8
|
|
779
|
-
marginTop: 12
|
|
1479
|
+
gap: 8
|
|
780
1480
|
},
|
|
781
1481
|
children: [
|
|
782
|
-
/* @__PURE__ */
|
|
1482
|
+
/* @__PURE__ */ jsxs(
|
|
783
1483
|
"button",
|
|
784
1484
|
{
|
|
785
1485
|
type: "button",
|
|
786
|
-
style:
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
setDeleteText("");
|
|
1486
|
+
style: {
|
|
1487
|
+
...smallAccentBtn,
|
|
1488
|
+
opacity: registering ? 0.6 : 1
|
|
790
1489
|
},
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
children:
|
|
1490
|
+
disabled: registering,
|
|
1491
|
+
onClick: handleRegisterPasskey,
|
|
1492
|
+
children: [
|
|
1493
|
+
registering ? /* @__PURE__ */ jsx(Spinner, {}) : /* @__PURE__ */ jsx(IconFingerprint, {}),
|
|
1494
|
+
registering ? "Registering..." : "Register"
|
|
1495
|
+
]
|
|
794
1496
|
}
|
|
795
1497
|
),
|
|
796
|
-
/* @__PURE__ */
|
|
1498
|
+
/* @__PURE__ */ jsx(
|
|
797
1499
|
"button",
|
|
798
1500
|
{
|
|
799
1501
|
type: "button",
|
|
800
|
-
style:
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
disabled: deleteText !== CONFIRM_WORD || deleting,
|
|
806
|
-
onClick: handleDelete,
|
|
807
|
-
children: [
|
|
808
|
-
deleting && /* @__PURE__ */ jsx(Spinner, {}),
|
|
809
|
-
"Delete my account"
|
|
810
|
-
]
|
|
1502
|
+
style: cancelBtn,
|
|
1503
|
+
onClick: () => setShowRegister(false),
|
|
1504
|
+
onMouseEnter: (e) => e.currentTarget.style.backgroundColor = "var(--dauth-surface-hover, #232340)",
|
|
1505
|
+
onMouseLeave: (e) => e.currentTarget.style.backgroundColor = "transparent",
|
|
1506
|
+
children: "Cancel"
|
|
811
1507
|
}
|
|
812
1508
|
)
|
|
813
1509
|
]
|
|
814
1510
|
}
|
|
815
1511
|
)
|
|
816
|
-
] })
|
|
1512
|
+
] }),
|
|
1513
|
+
passkeyStatus && /* @__PURE__ */ jsx(
|
|
1514
|
+
"div",
|
|
1515
|
+
{
|
|
1516
|
+
role: "status",
|
|
1517
|
+
"aria-live": "polite",
|
|
1518
|
+
style: {
|
|
1519
|
+
...statusMsg(passkeyStatus.type),
|
|
1520
|
+
marginTop: 12
|
|
1521
|
+
},
|
|
1522
|
+
children: passkeyStatus.message
|
|
1523
|
+
}
|
|
1524
|
+
),
|
|
1525
|
+
/* @__PURE__ */ jsx("div", { style: { marginTop: 12 }, children: loadingCreds ? /* @__PURE__ */ jsx(
|
|
1526
|
+
"div",
|
|
1527
|
+
{
|
|
1528
|
+
style: {
|
|
1529
|
+
textAlign: "center",
|
|
1530
|
+
padding: 24
|
|
1531
|
+
},
|
|
1532
|
+
children: /* @__PURE__ */ jsx(Spinner, {})
|
|
1533
|
+
}
|
|
1534
|
+
) : credentials.length > 0 ? credentials.map((cred) => /* @__PURE__ */ jsxs(
|
|
1535
|
+
"div",
|
|
1536
|
+
{
|
|
1537
|
+
style: credentialRow,
|
|
1538
|
+
children: [
|
|
1539
|
+
/* @__PURE__ */ jsxs(
|
|
1540
|
+
"div",
|
|
1541
|
+
{
|
|
1542
|
+
style: {
|
|
1543
|
+
display: "flex",
|
|
1544
|
+
alignItems: "center",
|
|
1545
|
+
gap: 12,
|
|
1546
|
+
flex: 1,
|
|
1547
|
+
minWidth: 0
|
|
1548
|
+
},
|
|
1549
|
+
children: [
|
|
1550
|
+
/* @__PURE__ */ jsx(
|
|
1551
|
+
"span",
|
|
1552
|
+
{
|
|
1553
|
+
style: {
|
|
1554
|
+
color: "var(--dauth-accent, #6366f1)",
|
|
1555
|
+
flexShrink: 0
|
|
1556
|
+
},
|
|
1557
|
+
children: /* @__PURE__ */ jsx(IconFingerprint, {})
|
|
1558
|
+
}
|
|
1559
|
+
),
|
|
1560
|
+
/* @__PURE__ */ jsxs(
|
|
1561
|
+
"div",
|
|
1562
|
+
{
|
|
1563
|
+
style: {
|
|
1564
|
+
minWidth: 0,
|
|
1565
|
+
flex: 1
|
|
1566
|
+
},
|
|
1567
|
+
children: [
|
|
1568
|
+
/* @__PURE__ */ jsx(
|
|
1569
|
+
"div",
|
|
1570
|
+
{
|
|
1571
|
+
style: {
|
|
1572
|
+
fontSize: "var(--dauth-font-size-sm, 0.875rem)",
|
|
1573
|
+
fontWeight: 500,
|
|
1574
|
+
color: "var(--dauth-text-primary, #e4e4e7)",
|
|
1575
|
+
overflow: "hidden",
|
|
1576
|
+
textOverflow: "ellipsis",
|
|
1577
|
+
whiteSpace: "nowrap"
|
|
1578
|
+
},
|
|
1579
|
+
children: cred.name || "Passkey"
|
|
1580
|
+
}
|
|
1581
|
+
),
|
|
1582
|
+
/* @__PURE__ */ jsxs(
|
|
1583
|
+
"div",
|
|
1584
|
+
{
|
|
1585
|
+
style: {
|
|
1586
|
+
fontSize: "var(--dauth-font-size-xs, 0.75rem)",
|
|
1587
|
+
color: "var(--dauth-text-muted, #71717a)"
|
|
1588
|
+
},
|
|
1589
|
+
children: [
|
|
1590
|
+
cred.deviceType === "multiDevice" ? "Synced" : "Device-bound",
|
|
1591
|
+
cred.createdAt && ` \xB7 Created ${new Date(cred.createdAt).toLocaleDateString()}`
|
|
1592
|
+
]
|
|
1593
|
+
}
|
|
1594
|
+
)
|
|
1595
|
+
]
|
|
1596
|
+
}
|
|
1597
|
+
)
|
|
1598
|
+
]
|
|
1599
|
+
}
|
|
1600
|
+
),
|
|
1601
|
+
/* @__PURE__ */ jsx(
|
|
1602
|
+
"button",
|
|
1603
|
+
{
|
|
1604
|
+
type: "button",
|
|
1605
|
+
onClick: () => handleDeletePasskey(cred._id),
|
|
1606
|
+
style: trashBtn,
|
|
1607
|
+
onMouseEnter: (e) => e.currentTarget.style.color = "var(--dauth-error, #ef4444)",
|
|
1608
|
+
onMouseLeave: (e) => e.currentTarget.style.color = "var(--dauth-text-muted, #71717a)",
|
|
1609
|
+
"aria-label": `Delete passkey ${cred.name || ""}`,
|
|
1610
|
+
children: /* @__PURE__ */ jsx(IconTrash, {})
|
|
1611
|
+
}
|
|
1612
|
+
)
|
|
1613
|
+
]
|
|
1614
|
+
},
|
|
1615
|
+
cred._id
|
|
1616
|
+
)) : /* @__PURE__ */ jsxs("div", { style: emptyState, children: [
|
|
1617
|
+
/* @__PURE__ */ jsx(
|
|
1618
|
+
"span",
|
|
1619
|
+
{
|
|
1620
|
+
style: {
|
|
1621
|
+
color: "var(--dauth-accent, #6366f1)"
|
|
1622
|
+
},
|
|
1623
|
+
children: /* @__PURE__ */ jsx(IconShield, {})
|
|
1624
|
+
}
|
|
1625
|
+
),
|
|
1626
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1627
|
+
/* @__PURE__ */ jsx(
|
|
1628
|
+
"div",
|
|
1629
|
+
{
|
|
1630
|
+
style: {
|
|
1631
|
+
fontSize: "var(--dauth-font-size-sm, 0.875rem)",
|
|
1632
|
+
fontWeight: 500,
|
|
1633
|
+
color: "var(--dauth-text-primary, #e4e4e7)"
|
|
1634
|
+
},
|
|
1635
|
+
children: "No passkeys registered"
|
|
1636
|
+
}
|
|
1637
|
+
),
|
|
1638
|
+
/* @__PURE__ */ jsx(
|
|
1639
|
+
"div",
|
|
1640
|
+
{
|
|
1641
|
+
style: {
|
|
1642
|
+
fontSize: "var(--dauth-font-size-xs, 0.75rem)",
|
|
1643
|
+
color: "var(--dauth-text-secondary, #a1a1aa)"
|
|
1644
|
+
},
|
|
1645
|
+
children: "Add a passkey for faster, more secure sign-in."
|
|
1646
|
+
}
|
|
1647
|
+
)
|
|
1648
|
+
] })
|
|
1649
|
+
] }) })
|
|
1650
|
+
] }),
|
|
1651
|
+
activeTab === "account" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1652
|
+
status && /* @__PURE__ */ jsx(
|
|
1653
|
+
"div",
|
|
1654
|
+
{
|
|
1655
|
+
role: "status",
|
|
1656
|
+
"aria-live": "polite",
|
|
1657
|
+
style: statusMsg(status.type),
|
|
1658
|
+
children: status.message
|
|
1659
|
+
}
|
|
1660
|
+
),
|
|
1661
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1662
|
+
/* @__PURE__ */ jsx("div", { style: dangerTitle, children: "Delete account" }),
|
|
1663
|
+
/* @__PURE__ */ jsx("div", { style: dangerDesc, children: "Permanently delete your account and all associated data." }),
|
|
1664
|
+
!showDelete ? /* @__PURE__ */ jsx(
|
|
1665
|
+
"button",
|
|
1666
|
+
{
|
|
1667
|
+
type: "button",
|
|
1668
|
+
style: deleteBtn,
|
|
1669
|
+
onClick: () => setShowDelete(true),
|
|
1670
|
+
onMouseEnter: (e) => e.currentTarget.style.backgroundColor = "rgba(239, 68, 68, 0.2)",
|
|
1671
|
+
onMouseLeave: (e) => e.currentTarget.style.backgroundColor = "var(--dauth-error-bg, rgba(239, 68, 68, 0.1))",
|
|
1672
|
+
children: "Delete account"
|
|
1673
|
+
}
|
|
1674
|
+
) : /* @__PURE__ */ jsxs("div", { style: deletePanel, children: [
|
|
1675
|
+
/* @__PURE__ */ jsxs("div", { style: deletePanelText, children: [
|
|
1676
|
+
"This action is permanent and cannot be undone. Type",
|
|
1677
|
+
" ",
|
|
1678
|
+
/* @__PURE__ */ jsx("strong", { children: CONFIRM_WORD }),
|
|
1679
|
+
" to confirm."
|
|
1680
|
+
] }),
|
|
1681
|
+
/* @__PURE__ */ jsx(
|
|
1682
|
+
"input",
|
|
1683
|
+
{
|
|
1684
|
+
type: "text",
|
|
1685
|
+
value: deleteText,
|
|
1686
|
+
onChange: (e) => setDeleteText(e.target.value),
|
|
1687
|
+
placeholder: `Type ${CONFIRM_WORD}`,
|
|
1688
|
+
style: input,
|
|
1689
|
+
onFocus: inputFocusHandler,
|
|
1690
|
+
onBlur: inputBlurHandler,
|
|
1691
|
+
disabled: deleting
|
|
1692
|
+
}
|
|
1693
|
+
),
|
|
1694
|
+
/* @__PURE__ */ jsxs(
|
|
1695
|
+
"div",
|
|
1696
|
+
{
|
|
1697
|
+
style: {
|
|
1698
|
+
display: "flex",
|
|
1699
|
+
gap: 8,
|
|
1700
|
+
marginTop: 12
|
|
1701
|
+
},
|
|
1702
|
+
children: [
|
|
1703
|
+
/* @__PURE__ */ jsx(
|
|
1704
|
+
"button",
|
|
1705
|
+
{
|
|
1706
|
+
type: "button",
|
|
1707
|
+
style: cancelBtn,
|
|
1708
|
+
onClick: () => {
|
|
1709
|
+
setShowDelete(false);
|
|
1710
|
+
setDeleteText("");
|
|
1711
|
+
},
|
|
1712
|
+
onMouseEnter: (e) => e.currentTarget.style.backgroundColor = "var(--dauth-surface-hover, #232340)",
|
|
1713
|
+
onMouseLeave: (e) => e.currentTarget.style.backgroundColor = "transparent",
|
|
1714
|
+
children: "Cancel"
|
|
1715
|
+
}
|
|
1716
|
+
),
|
|
1717
|
+
/* @__PURE__ */ jsxs(
|
|
1718
|
+
"button",
|
|
1719
|
+
{
|
|
1720
|
+
type: "button",
|
|
1721
|
+
style: {
|
|
1722
|
+
...deleteConfirmBtn,
|
|
1723
|
+
opacity: deleteText !== CONFIRM_WORD || deleting ? 0.5 : 1,
|
|
1724
|
+
cursor: deleteText !== CONFIRM_WORD || deleting ? "not-allowed" : "pointer"
|
|
1725
|
+
},
|
|
1726
|
+
disabled: deleteText !== CONFIRM_WORD || deleting,
|
|
1727
|
+
onClick: handleDelete,
|
|
1728
|
+
children: [
|
|
1729
|
+
deleting && /* @__PURE__ */ jsx(Spinner, {}),
|
|
1730
|
+
"Delete my account"
|
|
1731
|
+
]
|
|
1732
|
+
}
|
|
1733
|
+
)
|
|
1734
|
+
]
|
|
1735
|
+
}
|
|
1736
|
+
)
|
|
1737
|
+
] })
|
|
1738
|
+
] }),
|
|
1739
|
+
/* @__PURE__ */ jsx("hr", { style: separator }),
|
|
1740
|
+
/* @__PURE__ */ jsxs(
|
|
1741
|
+
"button",
|
|
1742
|
+
{
|
|
1743
|
+
type: "button",
|
|
1744
|
+
style: signOutBtn,
|
|
1745
|
+
onClick: handleSignOut,
|
|
1746
|
+
onMouseEnter: (e) => e.currentTarget.style.backgroundColor = "rgba(239, 68, 68, 0.2)",
|
|
1747
|
+
onMouseLeave: (e) => e.currentTarget.style.backgroundColor = "var(--dauth-error-bg, rgba(239, 68, 68, 0.1))",
|
|
1748
|
+
children: [
|
|
1749
|
+
/* @__PURE__ */ jsx(IconLogOut, {}),
|
|
1750
|
+
"Sign out"
|
|
1751
|
+
]
|
|
1752
|
+
}
|
|
1753
|
+
)
|
|
817
1754
|
] })
|
|
818
1755
|
] }),
|
|
819
|
-
/* @__PURE__ */ jsx("div", { style: footerStyle(isDesktop), children: /* @__PURE__ */ jsxs(
|
|
1756
|
+
activeTab === "profile" && /* @__PURE__ */ jsx("div", { style: footerStyle(isDesktop), children: /* @__PURE__ */ jsxs(
|
|
820
1757
|
"button",
|
|
821
1758
|
{
|
|
822
1759
|
type: "button",
|
|
@@ -854,8 +1791,7 @@ var headerStyle = (isDesktop) => ({
|
|
|
854
1791
|
display: "flex",
|
|
855
1792
|
alignItems: "center",
|
|
856
1793
|
justifyContent: "space-between",
|
|
857
|
-
padding: "16px 24px",
|
|
858
|
-
borderBottom: "1px solid var(--dauth-border, rgba(255, 255, 255, 0.08))",
|
|
1794
|
+
padding: "16px 24px 0",
|
|
859
1795
|
flexShrink: 0,
|
|
860
1796
|
...!isDesktop ? {
|
|
861
1797
|
position: "sticky",
|
|
@@ -886,6 +1822,25 @@ var closeBtn = {
|
|
|
886
1822
|
transition: "background-color 150ms, color 150ms",
|
|
887
1823
|
padding: 0
|
|
888
1824
|
};
|
|
1825
|
+
var tabBar = {
|
|
1826
|
+
display: "flex",
|
|
1827
|
+
padding: "0 24px",
|
|
1828
|
+
borderBottom: "1px solid var(--dauth-border, rgba(255, 255, 255, 0.08))",
|
|
1829
|
+
flexShrink: 0
|
|
1830
|
+
};
|
|
1831
|
+
var tabBtn = {
|
|
1832
|
+
flex: 1,
|
|
1833
|
+
padding: "12px 4px",
|
|
1834
|
+
fontSize: "var(--dauth-font-size-sm, 0.875rem)",
|
|
1835
|
+
fontWeight: 500,
|
|
1836
|
+
border: "none",
|
|
1837
|
+
borderBottom: "2px solid transparent",
|
|
1838
|
+
backgroundColor: "transparent",
|
|
1839
|
+
cursor: "pointer",
|
|
1840
|
+
transition: "color 150ms, border-color 150ms",
|
|
1841
|
+
fontFamily: "inherit",
|
|
1842
|
+
textAlign: "center"
|
|
1843
|
+
};
|
|
889
1844
|
var bodyStyle = {
|
|
890
1845
|
flex: 1,
|
|
891
1846
|
overflowY: "auto",
|
|
@@ -912,6 +1867,18 @@ var avatarCircle = {
|
|
|
912
1867
|
fontSize: "1.5rem",
|
|
913
1868
|
fontWeight: 600
|
|
914
1869
|
};
|
|
1870
|
+
var avatarOverlay = {
|
|
1871
|
+
position: "absolute",
|
|
1872
|
+
inset: 0,
|
|
1873
|
+
backgroundColor: "rgba(0, 0, 0, 0.4)",
|
|
1874
|
+
display: "flex",
|
|
1875
|
+
alignItems: "center",
|
|
1876
|
+
justifyContent: "center",
|
|
1877
|
+
borderRadius: "50%",
|
|
1878
|
+
opacity: 0.7,
|
|
1879
|
+
transition: "opacity 150ms",
|
|
1880
|
+
color: "#ffffff"
|
|
1881
|
+
};
|
|
915
1882
|
var emailText = {
|
|
916
1883
|
fontSize: "var(--dauth-font-size-sm, 0.875rem)",
|
|
917
1884
|
color: "var(--dauth-text-secondary, #a1a1aa)"
|
|
@@ -926,7 +1893,9 @@ var statusMsg = (type) => ({
|
|
|
926
1893
|
textAlign: "center",
|
|
927
1894
|
lineHeight: 1.5
|
|
928
1895
|
});
|
|
929
|
-
var fieldGroup = {
|
|
1896
|
+
var fieldGroup = {
|
|
1897
|
+
marginBottom: 16
|
|
1898
|
+
};
|
|
930
1899
|
var label = {
|
|
931
1900
|
display: "block",
|
|
932
1901
|
fontSize: "var(--dauth-font-size-sm, 0.875rem)",
|
|
@@ -956,12 +1925,88 @@ var inputBlurHandler = (e) => {
|
|
|
956
1925
|
e.currentTarget.style.borderColor = "var(--dauth-border, rgba(255, 255, 255, 0.08))";
|
|
957
1926
|
e.currentTarget.style.boxShadow = "none";
|
|
958
1927
|
};
|
|
1928
|
+
var langBtn = {
|
|
1929
|
+
padding: "8px 16px",
|
|
1930
|
+
fontSize: "var(--dauth-font-size-sm, 0.875rem)",
|
|
1931
|
+
fontWeight: 500,
|
|
1932
|
+
border: "none",
|
|
1933
|
+
borderRadius: "var(--dauth-radius-sm, 8px)",
|
|
1934
|
+
cursor: "pointer",
|
|
1935
|
+
transition: "background-color 150ms, color 150ms",
|
|
1936
|
+
fontFamily: "inherit"
|
|
1937
|
+
};
|
|
959
1938
|
var separator = {
|
|
960
1939
|
height: 1,
|
|
961
1940
|
backgroundColor: "var(--dauth-border, rgba(255, 255, 255, 0.08))",
|
|
962
1941
|
margin: "24px 0",
|
|
963
1942
|
border: "none"
|
|
964
1943
|
};
|
|
1944
|
+
var outlineBtn = {
|
|
1945
|
+
padding: "6px 12px",
|
|
1946
|
+
fontSize: "var(--dauth-font-size-xs, 0.75rem)",
|
|
1947
|
+
fontWeight: 500,
|
|
1948
|
+
color: "var(--dauth-text-secondary, #a1a1aa)",
|
|
1949
|
+
backgroundColor: "transparent",
|
|
1950
|
+
border: "1px solid var(--dauth-border, rgba(255, 255, 255, 0.08))",
|
|
1951
|
+
borderRadius: "var(--dauth-radius-sm, 8px)",
|
|
1952
|
+
cursor: "pointer",
|
|
1953
|
+
transition: "background-color 150ms",
|
|
1954
|
+
fontFamily: "inherit"
|
|
1955
|
+
};
|
|
1956
|
+
var registerPanel = {
|
|
1957
|
+
padding: 16,
|
|
1958
|
+
borderRadius: "var(--dauth-radius-sm, 8px)",
|
|
1959
|
+
border: "1px solid var(--dauth-border, rgba(255, 255, 255, 0.08))",
|
|
1960
|
+
backgroundColor: "var(--dauth-surface-secondary, rgba(255, 255, 255, 0.04))",
|
|
1961
|
+
marginBottom: 12
|
|
1962
|
+
};
|
|
1963
|
+
var smallAccentBtn = {
|
|
1964
|
+
padding: "8px 16px",
|
|
1965
|
+
fontSize: "var(--dauth-font-size-sm, 0.875rem)",
|
|
1966
|
+
fontWeight: 500,
|
|
1967
|
+
color: "#ffffff",
|
|
1968
|
+
backgroundColor: "var(--dauth-accent, #6366f1)",
|
|
1969
|
+
border: "none",
|
|
1970
|
+
borderRadius: "var(--dauth-radius-sm, 8px)",
|
|
1971
|
+
cursor: "pointer",
|
|
1972
|
+
transition: "opacity 150ms",
|
|
1973
|
+
fontFamily: "inherit",
|
|
1974
|
+
display: "flex",
|
|
1975
|
+
alignItems: "center",
|
|
1976
|
+
gap: 6
|
|
1977
|
+
};
|
|
1978
|
+
var credentialRow = {
|
|
1979
|
+
display: "flex",
|
|
1980
|
+
alignItems: "center",
|
|
1981
|
+
justifyContent: "space-between",
|
|
1982
|
+
padding: 12,
|
|
1983
|
+
borderRadius: "var(--dauth-radius-sm, 8px)",
|
|
1984
|
+
backgroundColor: "var(--dauth-surface-secondary, rgba(255, 255, 255, 0.04))",
|
|
1985
|
+
marginBottom: 8
|
|
1986
|
+
};
|
|
1987
|
+
var trashBtn = {
|
|
1988
|
+
display: "flex",
|
|
1989
|
+
alignItems: "center",
|
|
1990
|
+
justifyContent: "center",
|
|
1991
|
+
width: 28,
|
|
1992
|
+
height: 28,
|
|
1993
|
+
border: "none",
|
|
1994
|
+
backgroundColor: "transparent",
|
|
1995
|
+
color: "var(--dauth-text-muted, #71717a)",
|
|
1996
|
+
cursor: "pointer",
|
|
1997
|
+
transition: "color 150ms",
|
|
1998
|
+
padding: 0,
|
|
1999
|
+
borderRadius: "var(--dauth-radius-sm, 8px)",
|
|
2000
|
+
flexShrink: 0
|
|
2001
|
+
};
|
|
2002
|
+
var emptyState = {
|
|
2003
|
+
display: "flex",
|
|
2004
|
+
alignItems: "center",
|
|
2005
|
+
gap: 12,
|
|
2006
|
+
padding: 16,
|
|
2007
|
+
borderRadius: "var(--dauth-radius-sm, 8px)",
|
|
2008
|
+
backgroundColor: "var(--dauth-surface-secondary, rgba(255, 255, 255, 0.04))"
|
|
2009
|
+
};
|
|
965
2010
|
var dangerTitle = {
|
|
966
2011
|
fontSize: "var(--dauth-font-size-sm, 0.875rem)",
|
|
967
2012
|
fontWeight: 600,
|
|
@@ -1000,7 +2045,6 @@ var deletePanelText = {
|
|
|
1000
2045
|
lineHeight: 1.5
|
|
1001
2046
|
};
|
|
1002
2047
|
var cancelBtn = {
|
|
1003
|
-
flex: 1,
|
|
1004
2048
|
padding: "8px 16px",
|
|
1005
2049
|
fontSize: "var(--dauth-font-size-sm, 0.875rem)",
|
|
1006
2050
|
fontWeight: 500,
|
|
@@ -1029,6 +2073,23 @@ var deleteConfirmBtn = {
|
|
|
1029
2073
|
justifyContent: "center",
|
|
1030
2074
|
gap: 8
|
|
1031
2075
|
};
|
|
2076
|
+
var signOutBtn = {
|
|
2077
|
+
width: "100%",
|
|
2078
|
+
padding: "12px 24px",
|
|
2079
|
+
fontSize: "var(--dauth-font-size-base, 1rem)",
|
|
2080
|
+
fontWeight: 500,
|
|
2081
|
+
color: "var(--dauth-error, #ef4444)",
|
|
2082
|
+
backgroundColor: "var(--dauth-error-bg, rgba(239, 68, 68, 0.1))",
|
|
2083
|
+
border: "1px solid rgba(239, 68, 68, 0.2)",
|
|
2084
|
+
borderRadius: "var(--dauth-radius-sm, 8px)",
|
|
2085
|
+
cursor: "pointer",
|
|
2086
|
+
transition: "background-color 150ms",
|
|
2087
|
+
fontFamily: "inherit",
|
|
2088
|
+
display: "flex",
|
|
2089
|
+
alignItems: "center",
|
|
2090
|
+
justifyContent: "center",
|
|
2091
|
+
gap: 8
|
|
2092
|
+
};
|
|
1032
2093
|
var footerStyle = (isDesktop) => ({
|
|
1033
2094
|
padding: "16px 24px",
|
|
1034
2095
|
borderTop: "1px solid var(--dauth-border, rgba(255, 255, 255, 0.08))",
|
|
@@ -1140,15 +2201,39 @@ var DauthProvider = (props) => {
|
|
|
1140
2201
|
() => deleteAccountAction(ctx),
|
|
1141
2202
|
[ctx]
|
|
1142
2203
|
);
|
|
2204
|
+
const getPasskeyCredentials = useCallback2(
|
|
2205
|
+
() => getPasskeyCredentialsAction(ctx),
|
|
2206
|
+
[ctx]
|
|
2207
|
+
);
|
|
2208
|
+
const registerPasskey = useCallback2(
|
|
2209
|
+
(name) => registerPasskeyAction(ctx, name),
|
|
2210
|
+
[ctx]
|
|
2211
|
+
);
|
|
2212
|
+
const deletePasskeyCredential = useCallback2(
|
|
2213
|
+
(credentialId) => deletePasskeyCredentialAction(ctx, credentialId),
|
|
2214
|
+
[ctx]
|
|
2215
|
+
);
|
|
1143
2216
|
const memoProvider = useMemo2(
|
|
1144
2217
|
() => ({
|
|
1145
2218
|
...dauthState,
|
|
1146
2219
|
loginWithRedirect,
|
|
1147
2220
|
logout,
|
|
1148
2221
|
updateUser,
|
|
1149
|
-
deleteAccount
|
|
2222
|
+
deleteAccount,
|
|
2223
|
+
getPasskeyCredentials,
|
|
2224
|
+
registerPasskey,
|
|
2225
|
+
deletePasskeyCredential
|
|
1150
2226
|
}),
|
|
1151
|
-
[
|
|
2227
|
+
[
|
|
2228
|
+
dauthState,
|
|
2229
|
+
loginWithRedirect,
|
|
2230
|
+
logout,
|
|
2231
|
+
updateUser,
|
|
2232
|
+
deleteAccount,
|
|
2233
|
+
getPasskeyCredentials,
|
|
2234
|
+
registerPasskey,
|
|
2235
|
+
deletePasskeyCredential
|
|
2236
|
+
]
|
|
1152
2237
|
);
|
|
1153
2238
|
return /* @__PURE__ */ jsx2(DauthContext.Provider, { value: memoProvider, children });
|
|
1154
2239
|
};
|