dauth-context-react 6.0.0 → 6.2.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 +27 -2
- package/dist/index.d.ts +27 -2
- package/dist/index.js +1086 -158
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1086 -158
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/DauthProfileModal.tsx +1102 -238
- 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 +31 -0
- package/src/reducer/dauth.actions.ts +91 -0
- package/src/webauthn.ts +111 -0
package/dist/index.js
CHANGED
|
@@ -40,7 +40,10 @@ var initialDauthState = {
|
|
|
40
40
|
logout: () => {
|
|
41
41
|
},
|
|
42
42
|
updateUser: () => Promise.resolve(false),
|
|
43
|
-
deleteAccount: () => Promise.resolve(false)
|
|
43
|
+
deleteAccount: () => Promise.resolve(false),
|
|
44
|
+
getPasskeyCredentials: () => Promise.resolve([]),
|
|
45
|
+
registerPasskey: () => Promise.resolve(null),
|
|
46
|
+
deletePasskeyCredential: () => Promise.resolve(false)
|
|
44
47
|
};
|
|
45
48
|
var initialDauthState_default = initialDauthState;
|
|
46
49
|
|
|
@@ -147,6 +150,134 @@ async function deleteAccountAPI(basePath) {
|
|
|
147
150
|
const data = await response.json();
|
|
148
151
|
return { response, data };
|
|
149
152
|
}
|
|
153
|
+
async function getPasskeyCredentialsAPI(basePath) {
|
|
154
|
+
const response = await fetch(
|
|
155
|
+
`${basePath}/passkey/credentials`,
|
|
156
|
+
{
|
|
157
|
+
method: "GET",
|
|
158
|
+
headers: { "X-CSRF-Token": getCsrfToken() },
|
|
159
|
+
credentials: "include"
|
|
160
|
+
}
|
|
161
|
+
);
|
|
162
|
+
const data = await response.json();
|
|
163
|
+
return { response, data };
|
|
164
|
+
}
|
|
165
|
+
async function startPasskeyRegistrationAPI(basePath) {
|
|
166
|
+
const response = await fetch(
|
|
167
|
+
`${basePath}/passkey/register/start`,
|
|
168
|
+
{
|
|
169
|
+
method: "POST",
|
|
170
|
+
headers: {
|
|
171
|
+
"Content-Type": "application/json",
|
|
172
|
+
"X-CSRF-Token": getCsrfToken()
|
|
173
|
+
},
|
|
174
|
+
credentials: "include"
|
|
175
|
+
}
|
|
176
|
+
);
|
|
177
|
+
const data = await response.json();
|
|
178
|
+
return { response, data };
|
|
179
|
+
}
|
|
180
|
+
async function finishPasskeyRegistrationAPI(basePath, body) {
|
|
181
|
+
const response = await fetch(
|
|
182
|
+
`${basePath}/passkey/register/finish`,
|
|
183
|
+
{
|
|
184
|
+
method: "POST",
|
|
185
|
+
headers: {
|
|
186
|
+
"Content-Type": "application/json",
|
|
187
|
+
"X-CSRF-Token": getCsrfToken()
|
|
188
|
+
},
|
|
189
|
+
credentials: "include",
|
|
190
|
+
body: JSON.stringify(body)
|
|
191
|
+
}
|
|
192
|
+
);
|
|
193
|
+
const data = await response.json();
|
|
194
|
+
return { response, data };
|
|
195
|
+
}
|
|
196
|
+
async function deletePasskeyCredentialAPI(basePath, credentialId) {
|
|
197
|
+
const response = await fetch(
|
|
198
|
+
`${basePath}/passkey/credentials/${credentialId}`,
|
|
199
|
+
{
|
|
200
|
+
method: "DELETE",
|
|
201
|
+
headers: { "X-CSRF-Token": getCsrfToken() },
|
|
202
|
+
credentials: "include"
|
|
203
|
+
}
|
|
204
|
+
);
|
|
205
|
+
const data = await response.json();
|
|
206
|
+
return { response, data };
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// src/webauthn.ts
|
|
210
|
+
function base64urlToBuffer(base64url) {
|
|
211
|
+
const base64 = base64url.replace(/-/g, "+").replace(/_/g, "/");
|
|
212
|
+
const pad = base64.length % 4;
|
|
213
|
+
const padded = pad ? base64 + "=".repeat(4 - pad) : base64;
|
|
214
|
+
const binary = atob(padded);
|
|
215
|
+
const bytes = new Uint8Array(binary.length);
|
|
216
|
+
for (let i = 0; i < binary.length; i++) {
|
|
217
|
+
bytes[i] = binary.charCodeAt(i);
|
|
218
|
+
}
|
|
219
|
+
return bytes.buffer;
|
|
220
|
+
}
|
|
221
|
+
function bufferToBase64url(buffer) {
|
|
222
|
+
const bytes = new Uint8Array(buffer);
|
|
223
|
+
let binary = "";
|
|
224
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
225
|
+
binary += String.fromCharCode(bytes[i]);
|
|
226
|
+
}
|
|
227
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
228
|
+
}
|
|
229
|
+
async function createPasskeyCredential(options) {
|
|
230
|
+
const publicKey = {
|
|
231
|
+
...options,
|
|
232
|
+
challenge: base64urlToBuffer(options.challenge),
|
|
233
|
+
user: {
|
|
234
|
+
...options.user,
|
|
235
|
+
id: base64urlToBuffer(options.user.id)
|
|
236
|
+
},
|
|
237
|
+
excludeCredentials: (options.excludeCredentials ?? []).map(
|
|
238
|
+
(c) => ({
|
|
239
|
+
...c,
|
|
240
|
+
id: base64urlToBuffer(c.id)
|
|
241
|
+
})
|
|
242
|
+
)
|
|
243
|
+
};
|
|
244
|
+
const credential = await navigator.credentials.create({
|
|
245
|
+
publicKey
|
|
246
|
+
});
|
|
247
|
+
if (!credential) {
|
|
248
|
+
throw new Error("Passkey registration was cancelled");
|
|
249
|
+
}
|
|
250
|
+
const attestation = credential.response;
|
|
251
|
+
return {
|
|
252
|
+
id: credential.id,
|
|
253
|
+
rawId: bufferToBase64url(credential.rawId),
|
|
254
|
+
type: credential.type,
|
|
255
|
+
response: {
|
|
256
|
+
clientDataJSON: bufferToBase64url(
|
|
257
|
+
attestation.clientDataJSON
|
|
258
|
+
),
|
|
259
|
+
attestationObject: bufferToBase64url(
|
|
260
|
+
attestation.attestationObject
|
|
261
|
+
),
|
|
262
|
+
...attestation.getTransports ? { transports: attestation.getTransports() } : {},
|
|
263
|
+
...attestation.getPublicKeyAlgorithm ? {
|
|
264
|
+
publicKeyAlgorithm: attestation.getPublicKeyAlgorithm()
|
|
265
|
+
} : {},
|
|
266
|
+
...attestation.getPublicKey ? {
|
|
267
|
+
publicKey: bufferToBase64url(
|
|
268
|
+
attestation.getPublicKey()
|
|
269
|
+
)
|
|
270
|
+
} : {},
|
|
271
|
+
...attestation.getAuthenticatorData ? {
|
|
272
|
+
authenticatorData: bufferToBase64url(
|
|
273
|
+
attestation.getAuthenticatorData()
|
|
274
|
+
)
|
|
275
|
+
} : {}
|
|
276
|
+
},
|
|
277
|
+
clientExtensionResults: credential.getClientExtensionResults(),
|
|
278
|
+
authenticatorAttachment: credential.authenticatorAttachment ?? void 0
|
|
279
|
+
};
|
|
280
|
+
}
|
|
150
281
|
|
|
151
282
|
// src/reducer/dauth.actions.ts
|
|
152
283
|
async function exchangeCodeAction(ctx, code) {
|
|
@@ -270,6 +401,65 @@ async function deleteAccountAction(ctx) {
|
|
|
270
401
|
return false;
|
|
271
402
|
}
|
|
272
403
|
}
|
|
404
|
+
async function getPasskeyCredentialsAction(ctx) {
|
|
405
|
+
const { authProxyPath, onError } = ctx;
|
|
406
|
+
try {
|
|
407
|
+
const result = await getPasskeyCredentialsAPI(authProxyPath);
|
|
408
|
+
if (result.response.status === 200) {
|
|
409
|
+
return result.data.credentials ?? [];
|
|
410
|
+
}
|
|
411
|
+
return [];
|
|
412
|
+
} catch (error) {
|
|
413
|
+
onError(
|
|
414
|
+
error instanceof Error ? error : new Error("Get passkey credentials error")
|
|
415
|
+
);
|
|
416
|
+
return [];
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
async function registerPasskeyAction(ctx, name) {
|
|
420
|
+
const { authProxyPath, onError } = ctx;
|
|
421
|
+
try {
|
|
422
|
+
const startResult = await startPasskeyRegistrationAPI(authProxyPath);
|
|
423
|
+
if (startResult.response.status !== 200) {
|
|
424
|
+
onError(new Error("Failed to start passkey registration"));
|
|
425
|
+
return null;
|
|
426
|
+
}
|
|
427
|
+
const credential = await createPasskeyCredential(
|
|
428
|
+
startResult.data
|
|
429
|
+
);
|
|
430
|
+
const finishResult = await finishPasskeyRegistrationAPI(
|
|
431
|
+
authProxyPath,
|
|
432
|
+
{ credential, name }
|
|
433
|
+
);
|
|
434
|
+
if (finishResult.response.status === 200 || finishResult.response.status === 201) {
|
|
435
|
+
return finishResult.data.credential;
|
|
436
|
+
}
|
|
437
|
+
onError(
|
|
438
|
+
new Error("Failed to finish passkey registration")
|
|
439
|
+
);
|
|
440
|
+
return null;
|
|
441
|
+
} catch (error) {
|
|
442
|
+
onError(
|
|
443
|
+
error instanceof Error ? error : new Error("Passkey registration error")
|
|
444
|
+
);
|
|
445
|
+
return null;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
async function deletePasskeyCredentialAction(ctx, credentialId) {
|
|
449
|
+
const { authProxyPath, onError } = ctx;
|
|
450
|
+
try {
|
|
451
|
+
const result = await deletePasskeyCredentialAPI(
|
|
452
|
+
authProxyPath,
|
|
453
|
+
credentialId
|
|
454
|
+
);
|
|
455
|
+
return result.response.status === 200;
|
|
456
|
+
} catch (error) {
|
|
457
|
+
onError(
|
|
458
|
+
error instanceof Error ? error : new Error("Delete passkey error")
|
|
459
|
+
);
|
|
460
|
+
return false;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
273
463
|
var resetUser = (dispatch) => {
|
|
274
464
|
return dispatch({
|
|
275
465
|
type: LOGIN,
|
|
@@ -361,6 +551,107 @@ function IconBack() {
|
|
|
361
551
|
}
|
|
362
552
|
);
|
|
363
553
|
}
|
|
554
|
+
function IconFingerprint() {
|
|
555
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
556
|
+
"svg",
|
|
557
|
+
{
|
|
558
|
+
width: "16",
|
|
559
|
+
height: "16",
|
|
560
|
+
viewBox: "0 0 24 24",
|
|
561
|
+
fill: "none",
|
|
562
|
+
stroke: "currentColor",
|
|
563
|
+
strokeWidth: "2",
|
|
564
|
+
strokeLinecap: "round",
|
|
565
|
+
strokeLinejoin: "round",
|
|
566
|
+
children: [
|
|
567
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 10a2 2 0 0 0-2 2c0 1.02-.1 2.51-.26 4" }),
|
|
568
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M14 13.12c0 2.38 0 6.38-1 8.88" }),
|
|
569
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M17.29 21.02c.12-.6.43-2.3.5-3.02" }),
|
|
570
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M2 12a10 10 0 0 1 18-6" }),
|
|
571
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M2 16h.01" }),
|
|
572
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M21.8 16c.2-2 .131-5.354 0-6" }),
|
|
573
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M5 19.5C5.5 18 6 15 6 12a6 6 0 0 1 .34-2" }),
|
|
574
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M8.65 22c.21-.66.45-1.32.57-2" }),
|
|
575
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M9 6.8a6 6 0 0 1 9 5.2v2" })
|
|
576
|
+
]
|
|
577
|
+
}
|
|
578
|
+
);
|
|
579
|
+
}
|
|
580
|
+
function IconShield() {
|
|
581
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
582
|
+
"svg",
|
|
583
|
+
{
|
|
584
|
+
width: "20",
|
|
585
|
+
height: "20",
|
|
586
|
+
viewBox: "0 0 24 24",
|
|
587
|
+
fill: "none",
|
|
588
|
+
stroke: "currentColor",
|
|
589
|
+
strokeWidth: "2",
|
|
590
|
+
strokeLinecap: "round",
|
|
591
|
+
strokeLinejoin: "round",
|
|
592
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.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" })
|
|
593
|
+
}
|
|
594
|
+
);
|
|
595
|
+
}
|
|
596
|
+
function IconTrash() {
|
|
597
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
598
|
+
"svg",
|
|
599
|
+
{
|
|
600
|
+
width: "14",
|
|
601
|
+
height: "14",
|
|
602
|
+
viewBox: "0 0 24 24",
|
|
603
|
+
fill: "none",
|
|
604
|
+
stroke: "currentColor",
|
|
605
|
+
strokeWidth: "2",
|
|
606
|
+
strokeLinecap: "round",
|
|
607
|
+
strokeLinejoin: "round",
|
|
608
|
+
children: [
|
|
609
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M3 6h18" }),
|
|
610
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" }),
|
|
611
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" })
|
|
612
|
+
]
|
|
613
|
+
}
|
|
614
|
+
);
|
|
615
|
+
}
|
|
616
|
+
function IconLogOut() {
|
|
617
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
618
|
+
"svg",
|
|
619
|
+
{
|
|
620
|
+
width: "16",
|
|
621
|
+
height: "16",
|
|
622
|
+
viewBox: "0 0 24 24",
|
|
623
|
+
fill: "none",
|
|
624
|
+
stroke: "currentColor",
|
|
625
|
+
strokeWidth: "2",
|
|
626
|
+
strokeLinecap: "round",
|
|
627
|
+
strokeLinejoin: "round",
|
|
628
|
+
children: [
|
|
629
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" }),
|
|
630
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("polyline", { points: "16 17 21 12 16 7" }),
|
|
631
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "21", y1: "12", x2: "9", y2: "12" })
|
|
632
|
+
]
|
|
633
|
+
}
|
|
634
|
+
);
|
|
635
|
+
}
|
|
636
|
+
function IconCamera() {
|
|
637
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
638
|
+
"svg",
|
|
639
|
+
{
|
|
640
|
+
width: "14",
|
|
641
|
+
height: "14",
|
|
642
|
+
viewBox: "0 0 24 24",
|
|
643
|
+
fill: "none",
|
|
644
|
+
stroke: "currentColor",
|
|
645
|
+
strokeWidth: "2",
|
|
646
|
+
strokeLinecap: "round",
|
|
647
|
+
strokeLinejoin: "round",
|
|
648
|
+
children: [
|
|
649
|
+
/* @__PURE__ */ (0, import_jsx_runtime.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" }),
|
|
650
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12", cy: "13", r: "3" })
|
|
651
|
+
]
|
|
652
|
+
}
|
|
653
|
+
);
|
|
654
|
+
}
|
|
364
655
|
function Spinner() {
|
|
365
656
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: spinnerStyle, "aria-hidden": "true" });
|
|
366
657
|
}
|
|
@@ -388,7 +679,10 @@ function useModalAnimation(open) {
|
|
|
388
679
|
}
|
|
389
680
|
if (phase === "entered" || phase === "entering") {
|
|
390
681
|
setPhase("exiting");
|
|
391
|
-
const timer = setTimeout(
|
|
682
|
+
const timer = setTimeout(
|
|
683
|
+
() => setPhase("exited"),
|
|
684
|
+
MOBILE_TRANSITION_MS
|
|
685
|
+
);
|
|
392
686
|
return () => clearTimeout(timer);
|
|
393
687
|
}
|
|
394
688
|
return void 0;
|
|
@@ -456,11 +750,27 @@ function useScrollLock(active) {
|
|
|
456
750
|
};
|
|
457
751
|
}, [active]);
|
|
458
752
|
}
|
|
459
|
-
function DauthProfileModal({
|
|
460
|
-
|
|
753
|
+
function DauthProfileModal({
|
|
754
|
+
open,
|
|
755
|
+
onClose,
|
|
756
|
+
onAvatarUpload
|
|
757
|
+
}) {
|
|
758
|
+
const {
|
|
759
|
+
user,
|
|
760
|
+
domain,
|
|
761
|
+
updateUser,
|
|
762
|
+
deleteAccount,
|
|
763
|
+
logout,
|
|
764
|
+
getPasskeyCredentials,
|
|
765
|
+
registerPasskey,
|
|
766
|
+
deletePasskeyCredential
|
|
767
|
+
} = useDauth();
|
|
461
768
|
const isDesktop = useMediaQuery("(min-width: 641px)");
|
|
462
769
|
const phase = useModalAnimation(open);
|
|
463
770
|
const modalRef = (0, import_react.useRef)(null);
|
|
771
|
+
const avatarInputRef = (0, import_react.useRef)(null);
|
|
772
|
+
const showSecurity = domain.authMethods?.passkey === true;
|
|
773
|
+
const [activeTab, setActiveTab] = (0, import_react.useState)("profile");
|
|
464
774
|
const [name, setName] = (0, import_react.useState)("");
|
|
465
775
|
const [lastname, setLastname] = (0, import_react.useState)("");
|
|
466
776
|
const [nickname, setNickname] = (0, import_react.useState)("");
|
|
@@ -471,6 +781,13 @@ function DauthProfileModal({ open, onClose }) {
|
|
|
471
781
|
const [showDelete, setShowDelete] = (0, import_react.useState)(false);
|
|
472
782
|
const [deleteText, setDeleteText] = (0, import_react.useState)("");
|
|
473
783
|
const [deleting, setDeleting] = (0, import_react.useState)(false);
|
|
784
|
+
const [credentials, setCredentials] = (0, import_react.useState)([]);
|
|
785
|
+
const [loadingCreds, setLoadingCreds] = (0, import_react.useState)(false);
|
|
786
|
+
const [showRegister, setShowRegister] = (0, import_react.useState)(false);
|
|
787
|
+
const [passkeyName, setPasskeyName] = (0, import_react.useState)("");
|
|
788
|
+
const [registering, setRegistering] = (0, import_react.useState)(false);
|
|
789
|
+
const [passkeyStatus, setPasskeyStatus] = (0, import_react.useState)(null);
|
|
790
|
+
const [uploadingAvatar, setUploadingAvatar] = (0, import_react.useState)(false);
|
|
474
791
|
(0, import_react.useEffect)(() => {
|
|
475
792
|
if (open && user?._id && !populated) {
|
|
476
793
|
setName(user.name || "");
|
|
@@ -484,13 +801,36 @@ function DauthProfileModal({ open, onClose }) {
|
|
|
484
801
|
setStatus(null);
|
|
485
802
|
setShowDelete(false);
|
|
486
803
|
setDeleteText("");
|
|
804
|
+
setActiveTab("profile");
|
|
805
|
+
setPasskeyStatus(null);
|
|
806
|
+
setShowRegister(false);
|
|
807
|
+
setPasskeyName("");
|
|
487
808
|
}
|
|
488
809
|
}, [open, user, populated]);
|
|
810
|
+
(0, import_react.useEffect)(() => {
|
|
811
|
+
if (activeTab !== "security" || !showSecurity) return;
|
|
812
|
+
setLoadingCreds(true);
|
|
813
|
+
getPasskeyCredentials().then((creds) => {
|
|
814
|
+
setCredentials(creds);
|
|
815
|
+
setLoadingCreds(false);
|
|
816
|
+
});
|
|
817
|
+
}, [activeTab, showSecurity, getPasskeyCredentials]);
|
|
489
818
|
(0, import_react.useEffect)(() => {
|
|
490
819
|
if (status?.type !== "success") return;
|
|
491
|
-
const timer = setTimeout(
|
|
820
|
+
const timer = setTimeout(
|
|
821
|
+
() => setStatus(null),
|
|
822
|
+
SUCCESS_TIMEOUT_MS
|
|
823
|
+
);
|
|
492
824
|
return () => clearTimeout(timer);
|
|
493
825
|
}, [status]);
|
|
826
|
+
(0, import_react.useEffect)(() => {
|
|
827
|
+
if (passkeyStatus?.type !== "success") return;
|
|
828
|
+
const timer = setTimeout(
|
|
829
|
+
() => setPasskeyStatus(null),
|
|
830
|
+
SUCCESS_TIMEOUT_MS
|
|
831
|
+
);
|
|
832
|
+
return () => clearTimeout(timer);
|
|
833
|
+
}, [passkeyStatus]);
|
|
494
834
|
useFocusTrap(modalRef, phase === "entered", onClose);
|
|
495
835
|
useScrollLock(phase !== "exited");
|
|
496
836
|
const hasField = (0, import_react.useCallback)(
|
|
@@ -542,6 +882,90 @@ function DauthProfileModal({ open, onClose }) {
|
|
|
542
882
|
setDeleteText("");
|
|
543
883
|
}
|
|
544
884
|
}, [deleteAccount, onClose]);
|
|
885
|
+
const handleLanguage = (0, import_react.useCallback)(
|
|
886
|
+
async (lang) => {
|
|
887
|
+
await updateUser({ language: lang });
|
|
888
|
+
},
|
|
889
|
+
[updateUser]
|
|
890
|
+
);
|
|
891
|
+
const handleRegisterPasskey = (0, import_react.useCallback)(async () => {
|
|
892
|
+
setRegistering(true);
|
|
893
|
+
setPasskeyStatus(null);
|
|
894
|
+
const cred = await registerPasskey(
|
|
895
|
+
passkeyName || void 0
|
|
896
|
+
);
|
|
897
|
+
setRegistering(false);
|
|
898
|
+
if (cred) {
|
|
899
|
+
setCredentials((prev) => [...prev, cred]);
|
|
900
|
+
setPasskeyName("");
|
|
901
|
+
setShowRegister(false);
|
|
902
|
+
setPasskeyStatus({
|
|
903
|
+
type: "success",
|
|
904
|
+
message: "Passkey registered successfully"
|
|
905
|
+
});
|
|
906
|
+
} else {
|
|
907
|
+
setPasskeyStatus({
|
|
908
|
+
type: "error",
|
|
909
|
+
message: "Failed to register passkey"
|
|
910
|
+
});
|
|
911
|
+
}
|
|
912
|
+
}, [passkeyName, registerPasskey]);
|
|
913
|
+
const handleDeletePasskey = (0, import_react.useCallback)(
|
|
914
|
+
async (credentialId) => {
|
|
915
|
+
const ok = await deletePasskeyCredential(credentialId);
|
|
916
|
+
if (ok) {
|
|
917
|
+
setCredentials(
|
|
918
|
+
(prev) => prev.filter((c) => c._id !== credentialId)
|
|
919
|
+
);
|
|
920
|
+
}
|
|
921
|
+
},
|
|
922
|
+
[deletePasskeyCredential]
|
|
923
|
+
);
|
|
924
|
+
const handleAvatarClick = (0, import_react.useCallback)(() => {
|
|
925
|
+
if (onAvatarUpload) {
|
|
926
|
+
avatarInputRef.current?.click();
|
|
927
|
+
}
|
|
928
|
+
}, [onAvatarUpload]);
|
|
929
|
+
const handleAvatarChange = (0, import_react.useCallback)(
|
|
930
|
+
async (e) => {
|
|
931
|
+
const file = e.target.files?.[0];
|
|
932
|
+
if (!file || !onAvatarUpload) return;
|
|
933
|
+
setUploadingAvatar(true);
|
|
934
|
+
try {
|
|
935
|
+
const url = await onAvatarUpload(file);
|
|
936
|
+
if (url) {
|
|
937
|
+
await updateUser({ avatar: url });
|
|
938
|
+
}
|
|
939
|
+
} catch {
|
|
940
|
+
}
|
|
941
|
+
setUploadingAvatar(false);
|
|
942
|
+
if (avatarInputRef.current) {
|
|
943
|
+
avatarInputRef.current.value = "";
|
|
944
|
+
}
|
|
945
|
+
},
|
|
946
|
+
[onAvatarUpload, updateUser]
|
|
947
|
+
);
|
|
948
|
+
const handleSignOut = (0, import_react.useCallback)(() => {
|
|
949
|
+
logout();
|
|
950
|
+
onClose();
|
|
951
|
+
}, [logout, onClose]);
|
|
952
|
+
const themeVars = (0, import_react.useMemo)(() => {
|
|
953
|
+
const t = domain.modalTheme;
|
|
954
|
+
if (!t) return {};
|
|
955
|
+
const vars = {};
|
|
956
|
+
if (t.accent) vars["--dauth-accent"] = t.accent;
|
|
957
|
+
if (t.accentHover)
|
|
958
|
+
vars["--dauth-accent-hover"] = t.accentHover;
|
|
959
|
+
if (t.surface) vars["--dauth-surface"] = t.surface;
|
|
960
|
+
if (t.surfaceHover)
|
|
961
|
+
vars["--dauth-surface-hover"] = t.surfaceHover;
|
|
962
|
+
if (t.textPrimary)
|
|
963
|
+
vars["--dauth-text-primary"] = t.textPrimary;
|
|
964
|
+
if (t.textSecondary)
|
|
965
|
+
vars["--dauth-text-secondary"] = t.textSecondary;
|
|
966
|
+
if (t.border) vars["--dauth-border"] = t.border;
|
|
967
|
+
return vars;
|
|
968
|
+
}, [domain.modalTheme]);
|
|
545
969
|
if (phase === "exited") return null;
|
|
546
970
|
const dur = isDesktop ? TRANSITION_MS : MOBILE_TRANSITION_MS;
|
|
547
971
|
const easing = "cubic-bezier(0.16, 1, 0.3, 1)";
|
|
@@ -589,6 +1013,11 @@ function DauthProfileModal({ open, onClose }) {
|
|
|
589
1013
|
transition: `transform ${dur}ms ${easing}`
|
|
590
1014
|
};
|
|
591
1015
|
const avatarInitial = (user.name || user.email || "?").charAt(0).toUpperCase();
|
|
1016
|
+
const tabs = [
|
|
1017
|
+
{ key: "profile", label: "Profile" },
|
|
1018
|
+
...showSecurity ? [{ key: "security", label: "Security" }] : [],
|
|
1019
|
+
{ key: "account", label: "Account" }
|
|
1020
|
+
];
|
|
592
1021
|
return (0, import_react_dom.createPortal)(
|
|
593
1022
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
594
1023
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
@@ -602,7 +1031,7 @@ function DauthProfileModal({ open, onClose }) {
|
|
|
602
1031
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
603
1032
|
"div",
|
|
604
1033
|
{
|
|
605
|
-
style: backdrop,
|
|
1034
|
+
style: { ...backdrop, ...themeVars },
|
|
606
1035
|
onClick: isDesktop ? onClose : void 0,
|
|
607
1036
|
"data-testid": "dauth-profile-backdrop",
|
|
608
1037
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
@@ -632,191 +1061,542 @@ function DauthProfileModal({ open, onClose }) {
|
|
|
632
1061
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { id: "dauth-profile-title", style: titleStyle, children: "Your Profile" }),
|
|
633
1062
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { width: 36 } })
|
|
634
1063
|
] }),
|
|
1064
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: tabBar, role: "tablist", children: tabs.map((t) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1065
|
+
"button",
|
|
1066
|
+
{
|
|
1067
|
+
role: "tab",
|
|
1068
|
+
type: "button",
|
|
1069
|
+
"aria-selected": activeTab === t.key,
|
|
1070
|
+
style: {
|
|
1071
|
+
...tabBtn,
|
|
1072
|
+
color: activeTab === t.key ? "var(--dauth-accent, #6366f1)" : "var(--dauth-text-secondary, #a1a1aa)",
|
|
1073
|
+
borderBottomColor: activeTab === t.key ? "var(--dauth-accent, #6366f1)" : "transparent"
|
|
1074
|
+
},
|
|
1075
|
+
onClick: () => setActiveTab(t.key),
|
|
1076
|
+
children: t.label
|
|
1077
|
+
},
|
|
1078
|
+
t.key
|
|
1079
|
+
)) }),
|
|
635
1080
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: bodyStyle, children: [
|
|
636
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
637
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
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__ */ (0, import_jsx_runtime.jsx)("div", { style: emailText, children: user.email })
|
|
650
|
-
] }),
|
|
651
|
-
status && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
652
|
-
"div",
|
|
653
|
-
{
|
|
654
|
-
role: "status",
|
|
655
|
-
"aria-live": "polite",
|
|
656
|
-
style: statusMsg(status.type),
|
|
657
|
-
children: status.message
|
|
658
|
-
}
|
|
659
|
-
),
|
|
660
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
661
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: fieldGroup, children: [
|
|
662
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { htmlFor: "dauth-name", style: label, children: "Name *" }),
|
|
663
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
664
|
-
"input",
|
|
1081
|
+
activeTab === "profile" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1082
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: avatarSection, children: [
|
|
1083
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1084
|
+
"div",
|
|
665
1085
|
{
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
1086
|
+
style: {
|
|
1087
|
+
...avatarCircle,
|
|
1088
|
+
cursor: onAvatarUpload ? "pointer" : "default",
|
|
1089
|
+
position: "relative"
|
|
1090
|
+
},
|
|
1091
|
+
onClick: handleAvatarClick,
|
|
1092
|
+
children: [
|
|
1093
|
+
uploadingAvatar ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {}) : user.avatar?.url ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1094
|
+
"img",
|
|
1095
|
+
{
|
|
1096
|
+
src: user.avatar.url,
|
|
1097
|
+
alt: "",
|
|
1098
|
+
style: {
|
|
1099
|
+
width: "100%",
|
|
1100
|
+
height: "100%",
|
|
1101
|
+
objectFit: "cover"
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
) : avatarInitial,
|
|
1105
|
+
onAvatarUpload && !uploadingAvatar && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: avatarOverlay, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconCamera, {}) })
|
|
1106
|
+
]
|
|
675
1107
|
}
|
|
676
|
-
)
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { htmlFor: "dauth-lastname", style: label, children: [
|
|
680
|
-
"Last name",
|
|
681
|
-
isRequired("lastname") ? " *" : ""
|
|
682
|
-
] }),
|
|
683
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1108
|
+
),
|
|
1109
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: emailText, children: user.email }),
|
|
1110
|
+
onAvatarUpload && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
684
1111
|
"input",
|
|
685
1112
|
{
|
|
686
|
-
|
|
687
|
-
type: "
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
disabled: saving,
|
|
692
|
-
style: input,
|
|
693
|
-
onFocus: inputFocusHandler,
|
|
694
|
-
onBlur: inputBlurHandler
|
|
1113
|
+
ref: avatarInputRef,
|
|
1114
|
+
type: "file",
|
|
1115
|
+
accept: "image/*",
|
|
1116
|
+
style: { display: "none" },
|
|
1117
|
+
onChange: handleAvatarChange
|
|
695
1118
|
}
|
|
696
1119
|
)
|
|
697
1120
|
] }),
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
1121
|
+
status && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1122
|
+
"div",
|
|
1123
|
+
{
|
|
1124
|
+
role: "status",
|
|
1125
|
+
"aria-live": "polite",
|
|
1126
|
+
style: statusMsg(status.type),
|
|
1127
|
+
children: status.message
|
|
1128
|
+
}
|
|
1129
|
+
),
|
|
1130
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
1131
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: fieldGroup, children: [
|
|
1132
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1133
|
+
"label",
|
|
1134
|
+
{
|
|
1135
|
+
htmlFor: "dauth-name",
|
|
1136
|
+
style: label,
|
|
1137
|
+
children: "Name *"
|
|
1138
|
+
}
|
|
1139
|
+
),
|
|
1140
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1141
|
+
"input",
|
|
1142
|
+
{
|
|
1143
|
+
id: "dauth-name",
|
|
1144
|
+
type: "text",
|
|
1145
|
+
value: name,
|
|
1146
|
+
onChange: (e) => setName(e.target.value),
|
|
1147
|
+
placeholder: "Your name",
|
|
1148
|
+
disabled: saving,
|
|
1149
|
+
style: input,
|
|
1150
|
+
onFocus: inputFocusHandler,
|
|
1151
|
+
onBlur: inputBlurHandler
|
|
1152
|
+
}
|
|
1153
|
+
)
|
|
702
1154
|
] }),
|
|
703
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
1155
|
+
hasField("lastname") && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: fieldGroup, children: [
|
|
1156
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1157
|
+
"label",
|
|
1158
|
+
{
|
|
1159
|
+
htmlFor: "dauth-lastname",
|
|
1160
|
+
style: label,
|
|
1161
|
+
children: [
|
|
1162
|
+
"Last name",
|
|
1163
|
+
isRequired("lastname") ? " *" : ""
|
|
1164
|
+
]
|
|
1165
|
+
}
|
|
1166
|
+
),
|
|
1167
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1168
|
+
"input",
|
|
1169
|
+
{
|
|
1170
|
+
id: "dauth-lastname",
|
|
1171
|
+
type: "text",
|
|
1172
|
+
value: lastname,
|
|
1173
|
+
onChange: (e) => setLastname(e.target.value),
|
|
1174
|
+
placeholder: "Your last name",
|
|
1175
|
+
disabled: saving,
|
|
1176
|
+
style: input,
|
|
1177
|
+
onFocus: inputFocusHandler,
|
|
1178
|
+
onBlur: inputBlurHandler
|
|
1179
|
+
}
|
|
1180
|
+
)
|
|
722
1181
|
] }),
|
|
723
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
724
|
-
|
|
1182
|
+
hasField("nickname") && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: fieldGroup, children: [
|
|
1183
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1184
|
+
"label",
|
|
1185
|
+
{
|
|
1186
|
+
htmlFor: "dauth-nickname",
|
|
1187
|
+
style: label,
|
|
1188
|
+
children: [
|
|
1189
|
+
"Nickname",
|
|
1190
|
+
isRequired("nickname") ? " *" : ""
|
|
1191
|
+
]
|
|
1192
|
+
}
|
|
1193
|
+
),
|
|
1194
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1195
|
+
"input",
|
|
1196
|
+
{
|
|
1197
|
+
id: "dauth-nickname",
|
|
1198
|
+
type: "text",
|
|
1199
|
+
value: nickname,
|
|
1200
|
+
onChange: (e) => setNickname(e.target.value),
|
|
1201
|
+
placeholder: "Choose a nickname",
|
|
1202
|
+
disabled: saving,
|
|
1203
|
+
style: input,
|
|
1204
|
+
onFocus: inputFocusHandler,
|
|
1205
|
+
onBlur: inputBlurHandler
|
|
1206
|
+
}
|
|
1207
|
+
)
|
|
1208
|
+
] }),
|
|
1209
|
+
hasField("country") && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: fieldGroup, children: [
|
|
1210
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1211
|
+
"label",
|
|
1212
|
+
{
|
|
1213
|
+
htmlFor: "dauth-country",
|
|
1214
|
+
style: label,
|
|
1215
|
+
children: [
|
|
1216
|
+
"Country",
|
|
1217
|
+
isRequired("country") ? " *" : ""
|
|
1218
|
+
]
|
|
1219
|
+
}
|
|
1220
|
+
),
|
|
1221
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1222
|
+
"input",
|
|
1223
|
+
{
|
|
1224
|
+
id: "dauth-country",
|
|
1225
|
+
type: "text",
|
|
1226
|
+
value: country,
|
|
1227
|
+
onChange: (e) => setCountry(e.target.value),
|
|
1228
|
+
placeholder: "Your country",
|
|
1229
|
+
disabled: saving,
|
|
1230
|
+
style: input,
|
|
1231
|
+
onFocus: inputFocusHandler,
|
|
1232
|
+
onBlur: inputBlurHandler
|
|
1233
|
+
}
|
|
1234
|
+
)
|
|
1235
|
+
] })
|
|
1236
|
+
] }),
|
|
1237
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("hr", { style: separator }),
|
|
1238
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: fieldGroup, children: [
|
|
1239
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: label, children: "Language" }),
|
|
1240
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { display: "flex", gap: 8 }, children: ["es", "en"].map((lang) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1241
|
+
"button",
|
|
725
1242
|
{
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
)
|
|
1243
|
+
type: "button",
|
|
1244
|
+
style: {
|
|
1245
|
+
...langBtn,
|
|
1246
|
+
backgroundColor: user.language === lang ? "var(--dauth-accent, #6366f1)" : "var(--dauth-surface-secondary, rgba(255, 255, 255, 0.04))",
|
|
1247
|
+
color: user.language === lang ? "#ffffff" : "var(--dauth-text-secondary, #a1a1aa)"
|
|
1248
|
+
},
|
|
1249
|
+
onClick: () => handleLanguage(lang),
|
|
1250
|
+
children: lang === "es" ? "Espa\xF1ol" : "English"
|
|
1251
|
+
},
|
|
1252
|
+
lang
|
|
1253
|
+
)) })
|
|
737
1254
|
] })
|
|
738
1255
|
] }),
|
|
739
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: dangerDesc, children: "Permanently delete your account and all associated data." }),
|
|
743
|
-
!showDelete ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
744
|
-
"button",
|
|
1256
|
+
activeTab === "security" && showSecurity && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1257
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1258
|
+
"div",
|
|
745
1259
|
{
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
1260
|
+
style: {
|
|
1261
|
+
display: "flex",
|
|
1262
|
+
alignItems: "center",
|
|
1263
|
+
justifyContent: "space-between",
|
|
1264
|
+
marginBottom: 16
|
|
1265
|
+
},
|
|
1266
|
+
children: [
|
|
1267
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1268
|
+
"div",
|
|
1269
|
+
{
|
|
1270
|
+
style: {
|
|
1271
|
+
...label,
|
|
1272
|
+
marginBottom: 0,
|
|
1273
|
+
fontWeight: 600
|
|
1274
|
+
},
|
|
1275
|
+
children: "Passkeys"
|
|
1276
|
+
}
|
|
1277
|
+
),
|
|
1278
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1279
|
+
"button",
|
|
1280
|
+
{
|
|
1281
|
+
type: "button",
|
|
1282
|
+
style: outlineBtn,
|
|
1283
|
+
onClick: () => setShowRegister(!showRegister),
|
|
1284
|
+
onMouseEnter: (e) => e.currentTarget.style.backgroundColor = "var(--dauth-surface-hover, #232340)",
|
|
1285
|
+
onMouseLeave: (e) => e.currentTarget.style.backgroundColor = "transparent",
|
|
1286
|
+
children: "+ Add passkey"
|
|
1287
|
+
}
|
|
1288
|
+
)
|
|
1289
|
+
]
|
|
752
1290
|
}
|
|
753
|
-
)
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
1291
|
+
),
|
|
1292
|
+
showRegister && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: registerPanel, children: [
|
|
1293
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: fieldGroup, children: [
|
|
1294
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1295
|
+
"label",
|
|
1296
|
+
{
|
|
1297
|
+
htmlFor: "dauth-passkey-name",
|
|
1298
|
+
style: label,
|
|
1299
|
+
children: "Passkey name (optional)"
|
|
1300
|
+
}
|
|
1301
|
+
),
|
|
1302
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1303
|
+
"input",
|
|
1304
|
+
{
|
|
1305
|
+
id: "dauth-passkey-name",
|
|
1306
|
+
type: "text",
|
|
1307
|
+
value: passkeyName,
|
|
1308
|
+
onChange: (e) => setPasskeyName(e.target.value),
|
|
1309
|
+
placeholder: "e.g. MacBook Touch ID",
|
|
1310
|
+
disabled: registering,
|
|
1311
|
+
style: input,
|
|
1312
|
+
onFocus: inputFocusHandler,
|
|
1313
|
+
onBlur: inputBlurHandler
|
|
1314
|
+
}
|
|
1315
|
+
)
|
|
759
1316
|
] }),
|
|
760
|
-
/* @__PURE__ */ (0, import_jsx_runtime.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
1317
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
774
1318
|
"div",
|
|
775
1319
|
{
|
|
776
1320
|
style: {
|
|
777
1321
|
display: "flex",
|
|
778
|
-
gap: 8
|
|
779
|
-
marginTop: 12
|
|
1322
|
+
gap: 8
|
|
780
1323
|
},
|
|
781
1324
|
children: [
|
|
782
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
1325
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
783
1326
|
"button",
|
|
784
1327
|
{
|
|
785
1328
|
type: "button",
|
|
786
|
-
style:
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
setDeleteText("");
|
|
1329
|
+
style: {
|
|
1330
|
+
...smallAccentBtn,
|
|
1331
|
+
opacity: registering ? 0.6 : 1
|
|
790
1332
|
},
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
children:
|
|
1333
|
+
disabled: registering,
|
|
1334
|
+
onClick: handleRegisterPasskey,
|
|
1335
|
+
children: [
|
|
1336
|
+
registering ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconFingerprint, {}),
|
|
1337
|
+
registering ? "Registering..." : "Register"
|
|
1338
|
+
]
|
|
794
1339
|
}
|
|
795
1340
|
),
|
|
796
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
1341
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
797
1342
|
"button",
|
|
798
1343
|
{
|
|
799
1344
|
type: "button",
|
|
800
|
-
style:
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
disabled: deleteText !== CONFIRM_WORD || deleting,
|
|
806
|
-
onClick: handleDelete,
|
|
807
|
-
children: [
|
|
808
|
-
deleting && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {}),
|
|
809
|
-
"Delete my account"
|
|
810
|
-
]
|
|
1345
|
+
style: cancelBtn,
|
|
1346
|
+
onClick: () => setShowRegister(false),
|
|
1347
|
+
onMouseEnter: (e) => e.currentTarget.style.backgroundColor = "var(--dauth-surface-hover, #232340)",
|
|
1348
|
+
onMouseLeave: (e) => e.currentTarget.style.backgroundColor = "transparent",
|
|
1349
|
+
children: "Cancel"
|
|
811
1350
|
}
|
|
812
1351
|
)
|
|
813
1352
|
]
|
|
814
1353
|
}
|
|
815
1354
|
)
|
|
816
|
-
] })
|
|
1355
|
+
] }),
|
|
1356
|
+
passkeyStatus && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1357
|
+
"div",
|
|
1358
|
+
{
|
|
1359
|
+
role: "status",
|
|
1360
|
+
"aria-live": "polite",
|
|
1361
|
+
style: {
|
|
1362
|
+
...statusMsg(passkeyStatus.type),
|
|
1363
|
+
marginTop: 12
|
|
1364
|
+
},
|
|
1365
|
+
children: passkeyStatus.message
|
|
1366
|
+
}
|
|
1367
|
+
),
|
|
1368
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { marginTop: 12 }, children: loadingCreds ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1369
|
+
"div",
|
|
1370
|
+
{
|
|
1371
|
+
style: {
|
|
1372
|
+
textAlign: "center",
|
|
1373
|
+
padding: 24
|
|
1374
|
+
},
|
|
1375
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {})
|
|
1376
|
+
}
|
|
1377
|
+
) : credentials.length > 0 ? credentials.map((cred) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1378
|
+
"div",
|
|
1379
|
+
{
|
|
1380
|
+
style: credentialRow,
|
|
1381
|
+
children: [
|
|
1382
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1383
|
+
"div",
|
|
1384
|
+
{
|
|
1385
|
+
style: {
|
|
1386
|
+
display: "flex",
|
|
1387
|
+
alignItems: "center",
|
|
1388
|
+
gap: 12,
|
|
1389
|
+
flex: 1,
|
|
1390
|
+
minWidth: 0
|
|
1391
|
+
},
|
|
1392
|
+
children: [
|
|
1393
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1394
|
+
"span",
|
|
1395
|
+
{
|
|
1396
|
+
style: {
|
|
1397
|
+
color: "var(--dauth-accent, #6366f1)",
|
|
1398
|
+
flexShrink: 0
|
|
1399
|
+
},
|
|
1400
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconFingerprint, {})
|
|
1401
|
+
}
|
|
1402
|
+
),
|
|
1403
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1404
|
+
"div",
|
|
1405
|
+
{
|
|
1406
|
+
style: {
|
|
1407
|
+
minWidth: 0,
|
|
1408
|
+
flex: 1
|
|
1409
|
+
},
|
|
1410
|
+
children: [
|
|
1411
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1412
|
+
"div",
|
|
1413
|
+
{
|
|
1414
|
+
style: {
|
|
1415
|
+
fontSize: "var(--dauth-font-size-sm, 0.875rem)",
|
|
1416
|
+
fontWeight: 500,
|
|
1417
|
+
color: "var(--dauth-text-primary, #e4e4e7)",
|
|
1418
|
+
overflow: "hidden",
|
|
1419
|
+
textOverflow: "ellipsis",
|
|
1420
|
+
whiteSpace: "nowrap"
|
|
1421
|
+
},
|
|
1422
|
+
children: cred.name || "Passkey"
|
|
1423
|
+
}
|
|
1424
|
+
),
|
|
1425
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1426
|
+
"div",
|
|
1427
|
+
{
|
|
1428
|
+
style: {
|
|
1429
|
+
fontSize: "var(--dauth-font-size-xs, 0.75rem)",
|
|
1430
|
+
color: "var(--dauth-text-muted, #71717a)"
|
|
1431
|
+
},
|
|
1432
|
+
children: [
|
|
1433
|
+
cred.deviceType === "multiDevice" ? "Synced" : "Device-bound",
|
|
1434
|
+
cred.createdAt && ` \xB7 Created ${new Date(cred.createdAt).toLocaleDateString()}`
|
|
1435
|
+
]
|
|
1436
|
+
}
|
|
1437
|
+
)
|
|
1438
|
+
]
|
|
1439
|
+
}
|
|
1440
|
+
)
|
|
1441
|
+
]
|
|
1442
|
+
}
|
|
1443
|
+
),
|
|
1444
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1445
|
+
"button",
|
|
1446
|
+
{
|
|
1447
|
+
type: "button",
|
|
1448
|
+
onClick: () => handleDeletePasskey(cred._id),
|
|
1449
|
+
style: trashBtn,
|
|
1450
|
+
onMouseEnter: (e) => e.currentTarget.style.color = "var(--dauth-error, #ef4444)",
|
|
1451
|
+
onMouseLeave: (e) => e.currentTarget.style.color = "var(--dauth-text-muted, #71717a)",
|
|
1452
|
+
"aria-label": `Delete passkey ${cred.name || ""}`,
|
|
1453
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconTrash, {})
|
|
1454
|
+
}
|
|
1455
|
+
)
|
|
1456
|
+
]
|
|
1457
|
+
},
|
|
1458
|
+
cred._id
|
|
1459
|
+
)) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: emptyState, children: [
|
|
1460
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1461
|
+
"span",
|
|
1462
|
+
{
|
|
1463
|
+
style: {
|
|
1464
|
+
color: "var(--dauth-accent, #6366f1)"
|
|
1465
|
+
},
|
|
1466
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconShield, {})
|
|
1467
|
+
}
|
|
1468
|
+
),
|
|
1469
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
1470
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1471
|
+
"div",
|
|
1472
|
+
{
|
|
1473
|
+
style: {
|
|
1474
|
+
fontSize: "var(--dauth-font-size-sm, 0.875rem)",
|
|
1475
|
+
fontWeight: 500,
|
|
1476
|
+
color: "var(--dauth-text-primary, #e4e4e7)"
|
|
1477
|
+
},
|
|
1478
|
+
children: "No passkeys registered"
|
|
1479
|
+
}
|
|
1480
|
+
),
|
|
1481
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1482
|
+
"div",
|
|
1483
|
+
{
|
|
1484
|
+
style: {
|
|
1485
|
+
fontSize: "var(--dauth-font-size-xs, 0.75rem)",
|
|
1486
|
+
color: "var(--dauth-text-secondary, #a1a1aa)"
|
|
1487
|
+
},
|
|
1488
|
+
children: "Add a passkey for faster, more secure sign-in."
|
|
1489
|
+
}
|
|
1490
|
+
)
|
|
1491
|
+
] })
|
|
1492
|
+
] }) })
|
|
1493
|
+
] }),
|
|
1494
|
+
activeTab === "account" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1495
|
+
status && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1496
|
+
"div",
|
|
1497
|
+
{
|
|
1498
|
+
role: "status",
|
|
1499
|
+
"aria-live": "polite",
|
|
1500
|
+
style: statusMsg(status.type),
|
|
1501
|
+
children: status.message
|
|
1502
|
+
}
|
|
1503
|
+
),
|
|
1504
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
1505
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: dangerTitle, children: "Delete account" }),
|
|
1506
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: dangerDesc, children: "Permanently delete your account and all associated data." }),
|
|
1507
|
+
!showDelete ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1508
|
+
"button",
|
|
1509
|
+
{
|
|
1510
|
+
type: "button",
|
|
1511
|
+
style: deleteBtn,
|
|
1512
|
+
onClick: () => setShowDelete(true),
|
|
1513
|
+
onMouseEnter: (e) => e.currentTarget.style.backgroundColor = "rgba(239, 68, 68, 0.2)",
|
|
1514
|
+
onMouseLeave: (e) => e.currentTarget.style.backgroundColor = "var(--dauth-error-bg, rgba(239, 68, 68, 0.1))",
|
|
1515
|
+
children: "Delete account"
|
|
1516
|
+
}
|
|
1517
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: deletePanel, children: [
|
|
1518
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: deletePanelText, children: [
|
|
1519
|
+
"This action is permanent and cannot be undone. Type",
|
|
1520
|
+
" ",
|
|
1521
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: CONFIRM_WORD }),
|
|
1522
|
+
" to confirm."
|
|
1523
|
+
] }),
|
|
1524
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1525
|
+
"input",
|
|
1526
|
+
{
|
|
1527
|
+
type: "text",
|
|
1528
|
+
value: deleteText,
|
|
1529
|
+
onChange: (e) => setDeleteText(e.target.value),
|
|
1530
|
+
placeholder: `Type ${CONFIRM_WORD}`,
|
|
1531
|
+
style: input,
|
|
1532
|
+
onFocus: inputFocusHandler,
|
|
1533
|
+
onBlur: inputBlurHandler,
|
|
1534
|
+
disabled: deleting
|
|
1535
|
+
}
|
|
1536
|
+
),
|
|
1537
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1538
|
+
"div",
|
|
1539
|
+
{
|
|
1540
|
+
style: {
|
|
1541
|
+
display: "flex",
|
|
1542
|
+
gap: 8,
|
|
1543
|
+
marginTop: 12
|
|
1544
|
+
},
|
|
1545
|
+
children: [
|
|
1546
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1547
|
+
"button",
|
|
1548
|
+
{
|
|
1549
|
+
type: "button",
|
|
1550
|
+
style: cancelBtn,
|
|
1551
|
+
onClick: () => {
|
|
1552
|
+
setShowDelete(false);
|
|
1553
|
+
setDeleteText("");
|
|
1554
|
+
},
|
|
1555
|
+
onMouseEnter: (e) => e.currentTarget.style.backgroundColor = "var(--dauth-surface-hover, #232340)",
|
|
1556
|
+
onMouseLeave: (e) => e.currentTarget.style.backgroundColor = "transparent",
|
|
1557
|
+
children: "Cancel"
|
|
1558
|
+
}
|
|
1559
|
+
),
|
|
1560
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1561
|
+
"button",
|
|
1562
|
+
{
|
|
1563
|
+
type: "button",
|
|
1564
|
+
style: {
|
|
1565
|
+
...deleteConfirmBtn,
|
|
1566
|
+
opacity: deleteText !== CONFIRM_WORD || deleting ? 0.5 : 1,
|
|
1567
|
+
cursor: deleteText !== CONFIRM_WORD || deleting ? "not-allowed" : "pointer"
|
|
1568
|
+
},
|
|
1569
|
+
disabled: deleteText !== CONFIRM_WORD || deleting,
|
|
1570
|
+
onClick: handleDelete,
|
|
1571
|
+
children: [
|
|
1572
|
+
deleting && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {}),
|
|
1573
|
+
"Delete my account"
|
|
1574
|
+
]
|
|
1575
|
+
}
|
|
1576
|
+
)
|
|
1577
|
+
]
|
|
1578
|
+
}
|
|
1579
|
+
)
|
|
1580
|
+
] })
|
|
1581
|
+
] }),
|
|
1582
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("hr", { style: separator }),
|
|
1583
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1584
|
+
"button",
|
|
1585
|
+
{
|
|
1586
|
+
type: "button",
|
|
1587
|
+
style: signOutBtn,
|
|
1588
|
+
onClick: handleSignOut,
|
|
1589
|
+
onMouseEnter: (e) => e.currentTarget.style.backgroundColor = "rgba(239, 68, 68, 0.2)",
|
|
1590
|
+
onMouseLeave: (e) => e.currentTarget.style.backgroundColor = "var(--dauth-error-bg, rgba(239, 68, 68, 0.1))",
|
|
1591
|
+
children: [
|
|
1592
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconLogOut, {}),
|
|
1593
|
+
"Sign out"
|
|
1594
|
+
]
|
|
1595
|
+
}
|
|
1596
|
+
)
|
|
817
1597
|
] })
|
|
818
1598
|
] }),
|
|
819
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: footerStyle(isDesktop), children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1599
|
+
activeTab === "profile" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: footerStyle(isDesktop), children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
820
1600
|
"button",
|
|
821
1601
|
{
|
|
822
1602
|
type: "button",
|
|
@@ -854,8 +1634,7 @@ var headerStyle = (isDesktop) => ({
|
|
|
854
1634
|
display: "flex",
|
|
855
1635
|
alignItems: "center",
|
|
856
1636
|
justifyContent: "space-between",
|
|
857
|
-
padding: "16px 24px",
|
|
858
|
-
borderBottom: "1px solid var(--dauth-border, rgba(255, 255, 255, 0.08))",
|
|
1637
|
+
padding: "16px 24px 0",
|
|
859
1638
|
flexShrink: 0,
|
|
860
1639
|
...!isDesktop ? {
|
|
861
1640
|
position: "sticky",
|
|
@@ -886,6 +1665,25 @@ var closeBtn = {
|
|
|
886
1665
|
transition: "background-color 150ms, color 150ms",
|
|
887
1666
|
padding: 0
|
|
888
1667
|
};
|
|
1668
|
+
var tabBar = {
|
|
1669
|
+
display: "flex",
|
|
1670
|
+
padding: "0 24px",
|
|
1671
|
+
borderBottom: "1px solid var(--dauth-border, rgba(255, 255, 255, 0.08))",
|
|
1672
|
+
flexShrink: 0
|
|
1673
|
+
};
|
|
1674
|
+
var tabBtn = {
|
|
1675
|
+
flex: 1,
|
|
1676
|
+
padding: "12px 4px",
|
|
1677
|
+
fontSize: "var(--dauth-font-size-sm, 0.875rem)",
|
|
1678
|
+
fontWeight: 500,
|
|
1679
|
+
border: "none",
|
|
1680
|
+
borderBottom: "2px solid transparent",
|
|
1681
|
+
backgroundColor: "transparent",
|
|
1682
|
+
cursor: "pointer",
|
|
1683
|
+
transition: "color 150ms, border-color 150ms",
|
|
1684
|
+
fontFamily: "inherit",
|
|
1685
|
+
textAlign: "center"
|
|
1686
|
+
};
|
|
889
1687
|
var bodyStyle = {
|
|
890
1688
|
flex: 1,
|
|
891
1689
|
overflowY: "auto",
|
|
@@ -912,6 +1710,18 @@ var avatarCircle = {
|
|
|
912
1710
|
fontSize: "1.5rem",
|
|
913
1711
|
fontWeight: 600
|
|
914
1712
|
};
|
|
1713
|
+
var avatarOverlay = {
|
|
1714
|
+
position: "absolute",
|
|
1715
|
+
inset: 0,
|
|
1716
|
+
backgroundColor: "rgba(0, 0, 0, 0.4)",
|
|
1717
|
+
display: "flex",
|
|
1718
|
+
alignItems: "center",
|
|
1719
|
+
justifyContent: "center",
|
|
1720
|
+
borderRadius: "50%",
|
|
1721
|
+
opacity: 0.7,
|
|
1722
|
+
transition: "opacity 150ms",
|
|
1723
|
+
color: "#ffffff"
|
|
1724
|
+
};
|
|
915
1725
|
var emailText = {
|
|
916
1726
|
fontSize: "var(--dauth-font-size-sm, 0.875rem)",
|
|
917
1727
|
color: "var(--dauth-text-secondary, #a1a1aa)"
|
|
@@ -926,7 +1736,9 @@ var statusMsg = (type) => ({
|
|
|
926
1736
|
textAlign: "center",
|
|
927
1737
|
lineHeight: 1.5
|
|
928
1738
|
});
|
|
929
|
-
var fieldGroup = {
|
|
1739
|
+
var fieldGroup = {
|
|
1740
|
+
marginBottom: 16
|
|
1741
|
+
};
|
|
930
1742
|
var label = {
|
|
931
1743
|
display: "block",
|
|
932
1744
|
fontSize: "var(--dauth-font-size-sm, 0.875rem)",
|
|
@@ -956,12 +1768,88 @@ var inputBlurHandler = (e) => {
|
|
|
956
1768
|
e.currentTarget.style.borderColor = "var(--dauth-border, rgba(255, 255, 255, 0.08))";
|
|
957
1769
|
e.currentTarget.style.boxShadow = "none";
|
|
958
1770
|
};
|
|
1771
|
+
var langBtn = {
|
|
1772
|
+
padding: "8px 16px",
|
|
1773
|
+
fontSize: "var(--dauth-font-size-sm, 0.875rem)",
|
|
1774
|
+
fontWeight: 500,
|
|
1775
|
+
border: "none",
|
|
1776
|
+
borderRadius: "var(--dauth-radius-sm, 8px)",
|
|
1777
|
+
cursor: "pointer",
|
|
1778
|
+
transition: "background-color 150ms, color 150ms",
|
|
1779
|
+
fontFamily: "inherit"
|
|
1780
|
+
};
|
|
959
1781
|
var separator = {
|
|
960
1782
|
height: 1,
|
|
961
1783
|
backgroundColor: "var(--dauth-border, rgba(255, 255, 255, 0.08))",
|
|
962
1784
|
margin: "24px 0",
|
|
963
1785
|
border: "none"
|
|
964
1786
|
};
|
|
1787
|
+
var outlineBtn = {
|
|
1788
|
+
padding: "6px 12px",
|
|
1789
|
+
fontSize: "var(--dauth-font-size-xs, 0.75rem)",
|
|
1790
|
+
fontWeight: 500,
|
|
1791
|
+
color: "var(--dauth-text-secondary, #a1a1aa)",
|
|
1792
|
+
backgroundColor: "transparent",
|
|
1793
|
+
border: "1px solid var(--dauth-border, rgba(255, 255, 255, 0.08))",
|
|
1794
|
+
borderRadius: "var(--dauth-radius-sm, 8px)",
|
|
1795
|
+
cursor: "pointer",
|
|
1796
|
+
transition: "background-color 150ms",
|
|
1797
|
+
fontFamily: "inherit"
|
|
1798
|
+
};
|
|
1799
|
+
var registerPanel = {
|
|
1800
|
+
padding: 16,
|
|
1801
|
+
borderRadius: "var(--dauth-radius-sm, 8px)",
|
|
1802
|
+
border: "1px solid var(--dauth-border, rgba(255, 255, 255, 0.08))",
|
|
1803
|
+
backgroundColor: "var(--dauth-surface-secondary, rgba(255, 255, 255, 0.04))",
|
|
1804
|
+
marginBottom: 12
|
|
1805
|
+
};
|
|
1806
|
+
var smallAccentBtn = {
|
|
1807
|
+
padding: "8px 16px",
|
|
1808
|
+
fontSize: "var(--dauth-font-size-sm, 0.875rem)",
|
|
1809
|
+
fontWeight: 500,
|
|
1810
|
+
color: "#ffffff",
|
|
1811
|
+
backgroundColor: "var(--dauth-accent, #6366f1)",
|
|
1812
|
+
border: "none",
|
|
1813
|
+
borderRadius: "var(--dauth-radius-sm, 8px)",
|
|
1814
|
+
cursor: "pointer",
|
|
1815
|
+
transition: "opacity 150ms",
|
|
1816
|
+
fontFamily: "inherit",
|
|
1817
|
+
display: "flex",
|
|
1818
|
+
alignItems: "center",
|
|
1819
|
+
gap: 6
|
|
1820
|
+
};
|
|
1821
|
+
var credentialRow = {
|
|
1822
|
+
display: "flex",
|
|
1823
|
+
alignItems: "center",
|
|
1824
|
+
justifyContent: "space-between",
|
|
1825
|
+
padding: 12,
|
|
1826
|
+
borderRadius: "var(--dauth-radius-sm, 8px)",
|
|
1827
|
+
backgroundColor: "var(--dauth-surface-secondary, rgba(255, 255, 255, 0.04))",
|
|
1828
|
+
marginBottom: 8
|
|
1829
|
+
};
|
|
1830
|
+
var trashBtn = {
|
|
1831
|
+
display: "flex",
|
|
1832
|
+
alignItems: "center",
|
|
1833
|
+
justifyContent: "center",
|
|
1834
|
+
width: 28,
|
|
1835
|
+
height: 28,
|
|
1836
|
+
border: "none",
|
|
1837
|
+
backgroundColor: "transparent",
|
|
1838
|
+
color: "var(--dauth-text-muted, #71717a)",
|
|
1839
|
+
cursor: "pointer",
|
|
1840
|
+
transition: "color 150ms",
|
|
1841
|
+
padding: 0,
|
|
1842
|
+
borderRadius: "var(--dauth-radius-sm, 8px)",
|
|
1843
|
+
flexShrink: 0
|
|
1844
|
+
};
|
|
1845
|
+
var emptyState = {
|
|
1846
|
+
display: "flex",
|
|
1847
|
+
alignItems: "center",
|
|
1848
|
+
gap: 12,
|
|
1849
|
+
padding: 16,
|
|
1850
|
+
borderRadius: "var(--dauth-radius-sm, 8px)",
|
|
1851
|
+
backgroundColor: "var(--dauth-surface-secondary, rgba(255, 255, 255, 0.04))"
|
|
1852
|
+
};
|
|
965
1853
|
var dangerTitle = {
|
|
966
1854
|
fontSize: "var(--dauth-font-size-sm, 0.875rem)",
|
|
967
1855
|
fontWeight: 600,
|
|
@@ -1000,7 +1888,6 @@ var deletePanelText = {
|
|
|
1000
1888
|
lineHeight: 1.5
|
|
1001
1889
|
};
|
|
1002
1890
|
var cancelBtn = {
|
|
1003
|
-
flex: 1,
|
|
1004
1891
|
padding: "8px 16px",
|
|
1005
1892
|
fontSize: "var(--dauth-font-size-sm, 0.875rem)",
|
|
1006
1893
|
fontWeight: 500,
|
|
@@ -1029,6 +1916,23 @@ var deleteConfirmBtn = {
|
|
|
1029
1916
|
justifyContent: "center",
|
|
1030
1917
|
gap: 8
|
|
1031
1918
|
};
|
|
1919
|
+
var signOutBtn = {
|
|
1920
|
+
width: "100%",
|
|
1921
|
+
padding: "12px 24px",
|
|
1922
|
+
fontSize: "var(--dauth-font-size-base, 1rem)",
|
|
1923
|
+
fontWeight: 500,
|
|
1924
|
+
color: "var(--dauth-error, #ef4444)",
|
|
1925
|
+
backgroundColor: "var(--dauth-error-bg, rgba(239, 68, 68, 0.1))",
|
|
1926
|
+
border: "1px solid rgba(239, 68, 68, 0.2)",
|
|
1927
|
+
borderRadius: "var(--dauth-radius-sm, 8px)",
|
|
1928
|
+
cursor: "pointer",
|
|
1929
|
+
transition: "background-color 150ms",
|
|
1930
|
+
fontFamily: "inherit",
|
|
1931
|
+
display: "flex",
|
|
1932
|
+
alignItems: "center",
|
|
1933
|
+
justifyContent: "center",
|
|
1934
|
+
gap: 8
|
|
1935
|
+
};
|
|
1032
1936
|
var footerStyle = (isDesktop) => ({
|
|
1033
1937
|
padding: "16px 24px",
|
|
1034
1938
|
borderTop: "1px solid var(--dauth-border, rgba(255, 255, 255, 0.08))",
|
|
@@ -1140,15 +2044,39 @@ var DauthProvider = (props) => {
|
|
|
1140
2044
|
() => deleteAccountAction(ctx),
|
|
1141
2045
|
[ctx]
|
|
1142
2046
|
);
|
|
2047
|
+
const getPasskeyCredentials = (0, import_react2.useCallback)(
|
|
2048
|
+
() => getPasskeyCredentialsAction(ctx),
|
|
2049
|
+
[ctx]
|
|
2050
|
+
);
|
|
2051
|
+
const registerPasskey = (0, import_react2.useCallback)(
|
|
2052
|
+
(name) => registerPasskeyAction(ctx, name),
|
|
2053
|
+
[ctx]
|
|
2054
|
+
);
|
|
2055
|
+
const deletePasskeyCredential = (0, import_react2.useCallback)(
|
|
2056
|
+
(credentialId) => deletePasskeyCredentialAction(ctx, credentialId),
|
|
2057
|
+
[ctx]
|
|
2058
|
+
);
|
|
1143
2059
|
const memoProvider = (0, import_react2.useMemo)(
|
|
1144
2060
|
() => ({
|
|
1145
2061
|
...dauthState,
|
|
1146
2062
|
loginWithRedirect,
|
|
1147
2063
|
logout,
|
|
1148
2064
|
updateUser,
|
|
1149
|
-
deleteAccount
|
|
2065
|
+
deleteAccount,
|
|
2066
|
+
getPasskeyCredentials,
|
|
2067
|
+
registerPasskey,
|
|
2068
|
+
deletePasskeyCredential
|
|
1150
2069
|
}),
|
|
1151
|
-
[
|
|
2070
|
+
[
|
|
2071
|
+
dauthState,
|
|
2072
|
+
loginWithRedirect,
|
|
2073
|
+
logout,
|
|
2074
|
+
updateUser,
|
|
2075
|
+
deleteAccount,
|
|
2076
|
+
getPasskeyCredentials,
|
|
2077
|
+
registerPasskey,
|
|
2078
|
+
deletePasskeyCredential
|
|
2079
|
+
]
|
|
1152
2080
|
);
|
|
1153
2081
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(DauthContext.Provider, { value: memoProvider, children });
|
|
1154
2082
|
};
|