dauth-context-react 6.1.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 +17 -2
- package/dist/index.d.ts +17 -2
- package/dist/index.js +1076 -161
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1076 -161
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/DauthProfileModal.tsx +1090 -241
- package/src/api/dauth.api.ts +73 -0
- package/src/api/interfaces/dauth.api.responses.ts +36 -0
- package/src/index.tsx +31 -1
- package/src/initialDauthState.ts +3 -0
- package/src/interfaces.ts +20 -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,16 +882,87 @@ 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]);
|
|
545
952
|
const themeVars = (0, import_react.useMemo)(() => {
|
|
546
953
|
const t = domain.modalTheme;
|
|
547
954
|
if (!t) return {};
|
|
548
955
|
const vars = {};
|
|
549
956
|
if (t.accent) vars["--dauth-accent"] = t.accent;
|
|
550
|
-
if (t.accentHover)
|
|
957
|
+
if (t.accentHover)
|
|
958
|
+
vars["--dauth-accent-hover"] = t.accentHover;
|
|
551
959
|
if (t.surface) vars["--dauth-surface"] = t.surface;
|
|
552
|
-
if (t.surfaceHover)
|
|
553
|
-
|
|
554
|
-
if (t.
|
|
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;
|
|
555
966
|
if (t.border) vars["--dauth-border"] = t.border;
|
|
556
967
|
return vars;
|
|
557
968
|
}, [domain.modalTheme]);
|
|
@@ -602,6 +1013,11 @@ function DauthProfileModal({ open, onClose }) {
|
|
|
602
1013
|
transition: `transform ${dur}ms ${easing}`
|
|
603
1014
|
};
|
|
604
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
|
+
];
|
|
605
1021
|
return (0, import_react_dom.createPortal)(
|
|
606
1022
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
607
1023
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
@@ -645,191 +1061,542 @@ function DauthProfileModal({ open, onClose }) {
|
|
|
645
1061
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { id: "dauth-profile-title", style: titleStyle, children: "Your Profile" }),
|
|
646
1062
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { width: 36 } })
|
|
647
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
|
+
)) }),
|
|
648
1080
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: bodyStyle, children: [
|
|
649
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
650
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
src: user.avatar.url,
|
|
654
|
-
alt: "",
|
|
655
|
-
style: {
|
|
656
|
-
width: "100%",
|
|
657
|
-
height: "100%",
|
|
658
|
-
objectFit: "cover"
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
) : avatarInitial }),
|
|
662
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: emailText, children: user.email })
|
|
663
|
-
] }),
|
|
664
|
-
status && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
665
|
-
"div",
|
|
666
|
-
{
|
|
667
|
-
role: "status",
|
|
668
|
-
"aria-live": "polite",
|
|
669
|
-
style: statusMsg(status.type),
|
|
670
|
-
children: status.message
|
|
671
|
-
}
|
|
672
|
-
),
|
|
673
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
674
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: fieldGroup, children: [
|
|
675
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", { htmlFor: "dauth-name", style: label, children: "Name *" }),
|
|
676
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
677
|
-
"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",
|
|
678
1085
|
{
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
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
|
+
]
|
|
688
1107
|
}
|
|
689
|
-
)
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { htmlFor: "dauth-lastname", style: label, children: [
|
|
693
|
-
"Last name",
|
|
694
|
-
isRequired("lastname") ? " *" : ""
|
|
695
|
-
] }),
|
|
696
|
-
/* @__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)(
|
|
697
1111
|
"input",
|
|
698
1112
|
{
|
|
699
|
-
|
|
700
|
-
type: "
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
disabled: saving,
|
|
705
|
-
style: input,
|
|
706
|
-
onFocus: inputFocusHandler,
|
|
707
|
-
onBlur: inputBlurHandler
|
|
1113
|
+
ref: avatarInputRef,
|
|
1114
|
+
type: "file",
|
|
1115
|
+
accept: "image/*",
|
|
1116
|
+
style: { display: "none" },
|
|
1117
|
+
onChange: handleAvatarChange
|
|
708
1118
|
}
|
|
709
1119
|
)
|
|
710
1120
|
] }),
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
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
|
+
)
|
|
715
1154
|
] }),
|
|
716
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
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
|
+
)
|
|
735
1181
|
] }),
|
|
736
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
737
|
-
|
|
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",
|
|
738
1242
|
{
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
)
|
|
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
|
+
)) })
|
|
750
1254
|
] })
|
|
751
1255
|
] }),
|
|
752
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: dangerDesc, children: "Permanently delete your account and all associated data." }),
|
|
756
|
-
!showDelete ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
757
|
-
"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",
|
|
758
1259
|
{
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
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
|
+
]
|
|
765
1290
|
}
|
|
766
|
-
)
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
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
|
+
)
|
|
772
1316
|
] }),
|
|
773
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
774
|
-
"input",
|
|
775
|
-
{
|
|
776
|
-
type: "text",
|
|
777
|
-
value: deleteText,
|
|
778
|
-
onChange: (e) => setDeleteText(e.target.value),
|
|
779
|
-
placeholder: `Type ${CONFIRM_WORD}`,
|
|
780
|
-
style: input,
|
|
781
|
-
onFocus: inputFocusHandler,
|
|
782
|
-
onBlur: inputBlurHandler,
|
|
783
|
-
disabled: deleting
|
|
784
|
-
}
|
|
785
|
-
),
|
|
786
1317
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
787
1318
|
"div",
|
|
788
1319
|
{
|
|
789
1320
|
style: {
|
|
790
1321
|
display: "flex",
|
|
791
|
-
gap: 8
|
|
792
|
-
marginTop: 12
|
|
1322
|
+
gap: 8
|
|
793
1323
|
},
|
|
794
1324
|
children: [
|
|
795
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
1325
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
796
1326
|
"button",
|
|
797
1327
|
{
|
|
798
1328
|
type: "button",
|
|
799
|
-
style:
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
setDeleteText("");
|
|
1329
|
+
style: {
|
|
1330
|
+
...smallAccentBtn,
|
|
1331
|
+
opacity: registering ? 0.6 : 1
|
|
803
1332
|
},
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
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
|
+
]
|
|
807
1339
|
}
|
|
808
1340
|
),
|
|
809
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
1341
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
810
1342
|
"button",
|
|
811
1343
|
{
|
|
812
1344
|
type: "button",
|
|
813
|
-
style:
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
disabled: deleteText !== CONFIRM_WORD || deleting,
|
|
819
|
-
onClick: handleDelete,
|
|
820
|
-
children: [
|
|
821
|
-
deleting && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {}),
|
|
822
|
-
"Delete my account"
|
|
823
|
-
]
|
|
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"
|
|
824
1350
|
}
|
|
825
1351
|
)
|
|
826
1352
|
]
|
|
827
1353
|
}
|
|
828
1354
|
)
|
|
829
|
-
] })
|
|
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
|
+
)
|
|
830
1597
|
] })
|
|
831
1598
|
] }),
|
|
832
|
-
/* @__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)(
|
|
833
1600
|
"button",
|
|
834
1601
|
{
|
|
835
1602
|
type: "button",
|
|
@@ -867,8 +1634,7 @@ var headerStyle = (isDesktop) => ({
|
|
|
867
1634
|
display: "flex",
|
|
868
1635
|
alignItems: "center",
|
|
869
1636
|
justifyContent: "space-between",
|
|
870
|
-
padding: "16px 24px",
|
|
871
|
-
borderBottom: "1px solid var(--dauth-border, rgba(255, 255, 255, 0.08))",
|
|
1637
|
+
padding: "16px 24px 0",
|
|
872
1638
|
flexShrink: 0,
|
|
873
1639
|
...!isDesktop ? {
|
|
874
1640
|
position: "sticky",
|
|
@@ -899,6 +1665,25 @@ var closeBtn = {
|
|
|
899
1665
|
transition: "background-color 150ms, color 150ms",
|
|
900
1666
|
padding: 0
|
|
901
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
|
+
};
|
|
902
1687
|
var bodyStyle = {
|
|
903
1688
|
flex: 1,
|
|
904
1689
|
overflowY: "auto",
|
|
@@ -925,6 +1710,18 @@ var avatarCircle = {
|
|
|
925
1710
|
fontSize: "1.5rem",
|
|
926
1711
|
fontWeight: 600
|
|
927
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
|
+
};
|
|
928
1725
|
var emailText = {
|
|
929
1726
|
fontSize: "var(--dauth-font-size-sm, 0.875rem)",
|
|
930
1727
|
color: "var(--dauth-text-secondary, #a1a1aa)"
|
|
@@ -939,7 +1736,9 @@ var statusMsg = (type) => ({
|
|
|
939
1736
|
textAlign: "center",
|
|
940
1737
|
lineHeight: 1.5
|
|
941
1738
|
});
|
|
942
|
-
var fieldGroup = {
|
|
1739
|
+
var fieldGroup = {
|
|
1740
|
+
marginBottom: 16
|
|
1741
|
+
};
|
|
943
1742
|
var label = {
|
|
944
1743
|
display: "block",
|
|
945
1744
|
fontSize: "var(--dauth-font-size-sm, 0.875rem)",
|
|
@@ -969,12 +1768,88 @@ var inputBlurHandler = (e) => {
|
|
|
969
1768
|
e.currentTarget.style.borderColor = "var(--dauth-border, rgba(255, 255, 255, 0.08))";
|
|
970
1769
|
e.currentTarget.style.boxShadow = "none";
|
|
971
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
|
+
};
|
|
972
1781
|
var separator = {
|
|
973
1782
|
height: 1,
|
|
974
1783
|
backgroundColor: "var(--dauth-border, rgba(255, 255, 255, 0.08))",
|
|
975
1784
|
margin: "24px 0",
|
|
976
1785
|
border: "none"
|
|
977
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
|
+
};
|
|
978
1853
|
var dangerTitle = {
|
|
979
1854
|
fontSize: "var(--dauth-font-size-sm, 0.875rem)",
|
|
980
1855
|
fontWeight: 600,
|
|
@@ -1013,7 +1888,6 @@ var deletePanelText = {
|
|
|
1013
1888
|
lineHeight: 1.5
|
|
1014
1889
|
};
|
|
1015
1890
|
var cancelBtn = {
|
|
1016
|
-
flex: 1,
|
|
1017
1891
|
padding: "8px 16px",
|
|
1018
1892
|
fontSize: "var(--dauth-font-size-sm, 0.875rem)",
|
|
1019
1893
|
fontWeight: 500,
|
|
@@ -1042,6 +1916,23 @@ var deleteConfirmBtn = {
|
|
|
1042
1916
|
justifyContent: "center",
|
|
1043
1917
|
gap: 8
|
|
1044
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
|
+
};
|
|
1045
1936
|
var footerStyle = (isDesktop) => ({
|
|
1046
1937
|
padding: "16px 24px",
|
|
1047
1938
|
borderTop: "1px solid var(--dauth-border, rgba(255, 255, 255, 0.08))",
|
|
@@ -1153,15 +2044,39 @@ var DauthProvider = (props) => {
|
|
|
1153
2044
|
() => deleteAccountAction(ctx),
|
|
1154
2045
|
[ctx]
|
|
1155
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
|
+
);
|
|
1156
2059
|
const memoProvider = (0, import_react2.useMemo)(
|
|
1157
2060
|
() => ({
|
|
1158
2061
|
...dauthState,
|
|
1159
2062
|
loginWithRedirect,
|
|
1160
2063
|
logout,
|
|
1161
2064
|
updateUser,
|
|
1162
|
-
deleteAccount
|
|
2065
|
+
deleteAccount,
|
|
2066
|
+
getPasskeyCredentials,
|
|
2067
|
+
registerPasskey,
|
|
2068
|
+
deletePasskeyCredential
|
|
1163
2069
|
}),
|
|
1164
|
-
[
|
|
2070
|
+
[
|
|
2071
|
+
dauthState,
|
|
2072
|
+
loginWithRedirect,
|
|
2073
|
+
logout,
|
|
2074
|
+
updateUser,
|
|
2075
|
+
deleteAccount,
|
|
2076
|
+
getPasskeyCredentials,
|
|
2077
|
+
registerPasskey,
|
|
2078
|
+
deletePasskeyCredential
|
|
2079
|
+
]
|
|
1165
2080
|
);
|
|
1166
2081
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(DauthContext.Provider, { value: memoProvider, children });
|
|
1167
2082
|
};
|