cauthy-auth 0.36.1 → 0.38.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/README.md +6 -2
- package/dist/client.d.mts +2 -1
- package/dist/client.d.ts +2 -1
- package/dist/client.js.map +1 -1
- package/dist/client.mjs.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -1
- package/dist/index.mjs.map +1 -1
- package/dist/react.d.mts +16 -2
- package/dist/react.d.ts +16 -2
- package/dist/react.js +283 -48
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +283 -48
- package/dist/react.mjs.map +1 -1
- package/dist/styles.css +10 -0
- package/dist/svelte.js.map +1 -1
- package/dist/svelte.mjs.map +1 -1
- package/dist/vue.js.map +1 -1
- package/dist/vue.mjs.map +1 -1
- package/package.json +1 -1
package/dist/react.js
CHANGED
|
@@ -845,11 +845,19 @@ var TEXTS = {
|
|
|
845
845
|
secondStepOff: "Off: signing in asks only for your password.",
|
|
846
846
|
turnOn: "Turn on",
|
|
847
847
|
turnOff: "Turn off",
|
|
848
|
-
addToApp: "
|
|
848
|
+
addToApp: "Scan this code with your authenticator app, or add the key below by hand, then enter the code it shows.",
|
|
849
849
|
openInApp: "Open in an authenticator app",
|
|
850
|
+
qrAlt: "QR code to add this account to an authenticator app",
|
|
850
851
|
recoveryCodes: "Recovery codes",
|
|
851
852
|
newRecoveryCodes: "New recovery codes",
|
|
852
853
|
keepCodes: "Keep these codes somewhere safe. Each works once, and they are not shown again.",
|
|
854
|
+
copyCodes: "Copy all",
|
|
855
|
+
downloadCodes: "Download .txt",
|
|
856
|
+
codesCopied: "The codes were copied.",
|
|
857
|
+
codesNotCopied: "The codes could not be copied. Select them and copy them by hand.",
|
|
858
|
+
change: "Change",
|
|
859
|
+
passwordSet: "Your account has a password.",
|
|
860
|
+
addAnotherPasskey: "Add a passkey",
|
|
853
861
|
passkeys: "Passkeys",
|
|
854
862
|
managePasskeys: "Add or remove a passkey",
|
|
855
863
|
passkeysHelp: "Sign in with your fingerprint, your face or your device's lock, without a password.",
|
|
@@ -1029,11 +1037,19 @@ var TEXTS = {
|
|
|
1029
1037
|
secondStepOff: "Inactivo: al entrar solo se pide tu contrase\xF1a.",
|
|
1030
1038
|
turnOn: "Activar",
|
|
1031
1039
|
turnOff: "Desactivar",
|
|
1032
|
-
addToApp: "
|
|
1040
|
+
addToApp: "Escanea este c\xF3digo con tu aplicaci\xF3n de autenticaci\xF3n, o agrega a mano la clave de abajo, y escribe el c\xF3digo que muestra.",
|
|
1033
1041
|
openInApp: "Abrir en una aplicaci\xF3n de autenticaci\xF3n",
|
|
1042
|
+
qrAlt: "C\xF3digo QR para agregar esta cuenta a una aplicaci\xF3n de autenticaci\xF3n",
|
|
1034
1043
|
recoveryCodes: "C\xF3digos de recuperaci\xF3n",
|
|
1035
1044
|
newRecoveryCodes: "Nuevos c\xF3digos de recuperaci\xF3n",
|
|
1036
1045
|
keepCodes: "Guarda estos c\xF3digos en un lugar seguro. Cada uno sirve una vez y no se vuelven a mostrar.",
|
|
1046
|
+
copyCodes: "Copiar todos",
|
|
1047
|
+
downloadCodes: "Descargar .txt",
|
|
1048
|
+
codesCopied: "Los c\xF3digos quedaron copiados.",
|
|
1049
|
+
codesNotCopied: "No se pudieron copiar los c\xF3digos. Selecci\xF3nalos y c\xF3pialos a mano.",
|
|
1050
|
+
change: "Cambiar",
|
|
1051
|
+
passwordSet: "Tu cuenta tiene contrase\xF1a.",
|
|
1052
|
+
addAnotherPasskey: "Agregar una llave de acceso",
|
|
1037
1053
|
passkeys: "Llaves de acceso",
|
|
1038
1054
|
managePasskeys: "Agregar o quitar una llave de acceso",
|
|
1039
1055
|
passkeysHelp: "Entra con tu huella, tu rostro o el bloqueo de tu dispositivo, sin contrase\xF1a.",
|
|
@@ -2209,6 +2225,8 @@ function OrganizationMembers(props) {
|
|
|
2209
2225
|
const [role, setRole] = (0, import_react.useState)("");
|
|
2210
2226
|
const [name, setName] = (0, import_react.useState)("");
|
|
2211
2227
|
const [asking, setAsking] = (0, import_react.useState)(null);
|
|
2228
|
+
const [adding, setAdding] = (0, import_react.useState)(false);
|
|
2229
|
+
const [renamingOpen, setRenamingOpen] = (0, import_react.useState)(false);
|
|
2212
2230
|
const [gone, setGone] = (0, import_react.useState)(null);
|
|
2213
2231
|
const id = props.organizationId;
|
|
2214
2232
|
const when = props.formatDate ?? ((iso) => new Date(iso).toLocaleDateString());
|
|
@@ -2243,6 +2261,7 @@ function OrganizationMembers(props) {
|
|
|
2243
2261
|
const r = await run(() => auth.organizations.add(id, { email, role, locale: props.locale }), "add");
|
|
2244
2262
|
if (!r.ok) return;
|
|
2245
2263
|
setEmail("");
|
|
2264
|
+
setAdding(false);
|
|
2246
2265
|
setDone(f.t.memberAdded.replace("{email}", r.member.email));
|
|
2247
2266
|
saved({ kind: "member.added", organizationId: id, userId: r.member.userId, email: r.member.email, role: r.member.role || role });
|
|
2248
2267
|
await load();
|
|
@@ -2273,6 +2292,7 @@ function OrganizationMembers(props) {
|
|
|
2273
2292
|
if (!r.ok) return;
|
|
2274
2293
|
setSeat(r.organization);
|
|
2275
2294
|
setName(r.organization.name);
|
|
2295
|
+
setRenamingOpen(false);
|
|
2276
2296
|
setDone(f.t.organizationRenamed.replace("{name}", r.organization.name));
|
|
2277
2297
|
saved({ kind: "organization.renamed", organizationId: id, name: r.organization.name });
|
|
2278
2298
|
};
|
|
@@ -2302,6 +2322,24 @@ function OrganizationMembers(props) {
|
|
|
2302
2322
|
const archiving = seat.can.archive && !hidden("archive");
|
|
2303
2323
|
const deleting = seat.can.delete && !hidden("delete");
|
|
2304
2324
|
const renaming = seat.can.update && !hidden("rename");
|
|
2325
|
+
const alone = members !== null && members.every((m) => m.you);
|
|
2326
|
+
const addOpen = adding || alone;
|
|
2327
|
+
const open = (form) => {
|
|
2328
|
+
setDone(null);
|
|
2329
|
+
f.setError(null);
|
|
2330
|
+
if (form === "add") setAdding(true);
|
|
2331
|
+
else setRenamingOpen(true);
|
|
2332
|
+
};
|
|
2333
|
+
const cancelAdd = () => {
|
|
2334
|
+
setEmail("");
|
|
2335
|
+
f.setError(null);
|
|
2336
|
+
setAdding(false);
|
|
2337
|
+
};
|
|
2338
|
+
const cancelRename = () => {
|
|
2339
|
+
setName(seat.name);
|
|
2340
|
+
f.setError(null);
|
|
2341
|
+
setRenamingOpen(false);
|
|
2342
|
+
};
|
|
2305
2343
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Wrap, { f, as: "div", slot: "account", root, children: [
|
|
2306
2344
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Wrap, { f, as: "section", slot: "section", section: "members", children: [
|
|
2307
2345
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Heading, { f, children: [
|
|
@@ -2365,18 +2403,23 @@ function OrganizationMembers(props) {
|
|
|
2365
2403
|
}) }),
|
|
2366
2404
|
done && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Say, { f, tone: "success", children: done })
|
|
2367
2405
|
] }),
|
|
2368
|
-
manage && giveable.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Wrap, { f, as: "form", slot: "section", section: "add-member", onSubmit: add, noValidate: true, children: [
|
|
2406
|
+
manage && giveable.length > 0 && (addOpen ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Wrap, { f, as: "form", slot: "section", section: "add-member", onSubmit: add, noValidate: true, children: [
|
|
2369
2407
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Heading, { f, children: f.t.memberAdd }),
|
|
2370
2408
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { f, name: "email", type: "email", label: f.t.email, value: email, autoComplete: "off", required: true, onChange: setEmail }),
|
|
2371
2409
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AddRole, { f, value: role, options: giveable.map((c) => ({ value: c.role, label: roleName(c) })), onChange: setRole }),
|
|
2372
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "submit", variant: "primary", loading: f.loading("add"), disabled: f.busy, className: f.cx("button"), children: f.t.memberAdd })
|
|
2373
|
-
|
|
2410
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "submit", variant: "primary", loading: f.loading("add"), disabled: f.busy, className: f.cx("button"), children: f.t.memberAdd }),
|
|
2411
|
+
!alone && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Cancel, { f, onClick: cancelAdd })
|
|
2412
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Wrap, { f, as: "div", slot: "section", section: "add-member", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "button", variant: "secondary", disabled: f.busy, className: f.cx("providerButton"), onClick: () => open("add"), children: f.t.memberAdd }) })),
|
|
2374
2413
|
(renaming || archiving || deleting) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Wrap, { f, as: "section", slot: "section", section: "organization", children: [
|
|
2375
2414
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Heading, { f, children: f.t.organization }),
|
|
2376
|
-
renaming && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Wrap, { f, as: "form", section: "rename", onSubmit: rename, noValidate: true, children: [
|
|
2415
|
+
renaming && (renamingOpen ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Wrap, { f, as: "form", section: "rename", onSubmit: rename, noValidate: true, children: [
|
|
2377
2416
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { f, name: "name", type: "text", label: f.t.name, value: name, autoComplete: "organization", required: true, onChange: setName }),
|
|
2378
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "submit", variant: "primary", loading: f.loading("rename"), disabled: f.busy, className: f.cx("button"), children: f.t.organizationRename })
|
|
2379
|
-
|
|
2417
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "submit", variant: "primary", loading: f.loading("rename"), disabled: f.busy, className: f.cx("button"), children: f.t.organizationRename }),
|
|
2418
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Cancel, { f, onClick: cancelRename })
|
|
2419
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
2420
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Note, { f, children: seat.name }),
|
|
2421
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "button", variant: "secondary", disabled: f.busy, className: f.cx("providerButton"), onClick: () => open("rename"), children: f.t.organizationRename })
|
|
2422
|
+
] })),
|
|
2380
2423
|
asking === "archive" ? confirming(archiveQuestion, f.t.organizationArchive, () => void close("archive")) : asking === "delete" ? confirming(deleteQuestion, f.t.organizationDelete, () => void close("delete")) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
2381
2424
|
archiving && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "button", variant: "danger", loading: f.loading("archive"), disabled: f.busy, className: f.cx("providerButton"), onClick: () => ask("archive", f.t.organizationArchive, archiveQuestion, () => void close("archive")), children: f.t.organizationArchive }),
|
|
2382
2425
|
deleting && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "button", variant: "danger", loading: f.loading("delete"), disabled: f.busy, className: f.cx("providerButton"), onClick: () => ask("delete", f.t.organizationDelete, deleteQuestion, () => void close("delete")), children: f.t.organizationDelete })
|
|
@@ -2395,6 +2438,7 @@ function PasskeysPart({ props, account, accountUrl, when }) {
|
|
|
2395
2438
|
const [list, setList] = (0, import_react.useState)([]);
|
|
2396
2439
|
const [name, setName] = (0, import_react.useState)("");
|
|
2397
2440
|
const [password, setPassword] = (0, import_react.useState)("");
|
|
2441
|
+
const [adding, setAdding] = (0, import_react.useState)(false);
|
|
2398
2442
|
(0, import_react.useEffect)(() => {
|
|
2399
2443
|
void auth.methods().then((m) => {
|
|
2400
2444
|
const can2 = m.passkeyHere && canUsePasskeys();
|
|
@@ -2420,6 +2464,7 @@ function PasskeysPart({ props, account, accountUrl, when }) {
|
|
|
2420
2464
|
setList([...list, r.passkey]);
|
|
2421
2465
|
setName("");
|
|
2422
2466
|
setPassword("");
|
|
2467
|
+
setAdding(false);
|
|
2423
2468
|
setDone(f.t.passkeyAdded);
|
|
2424
2469
|
props.onSaved?.({ kind: "passkey.added", id: r.passkey.id });
|
|
2425
2470
|
};
|
|
@@ -2429,43 +2474,123 @@ function PasskeysPart({ props, account, accountUrl, when }) {
|
|
|
2429
2474
|
setList(list.filter((p) => p.id !== id));
|
|
2430
2475
|
props.onSaved?.({ kind: "passkey.removed", id });
|
|
2431
2476
|
};
|
|
2477
|
+
const cancel = () => {
|
|
2478
|
+
setName("");
|
|
2479
|
+
setPassword("");
|
|
2480
|
+
f.setError(null);
|
|
2481
|
+
setAdding(false);
|
|
2482
|
+
};
|
|
2483
|
+
const listed = list.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Note, { f, children: f.t.noPasskeys }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: f.cx("sessions"), children: list.map((p) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: f.cx("session"), children: [
|
|
2484
|
+
p.name || f.t.passkeyUnnamed,
|
|
2485
|
+
p.kind !== "unknown" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Tag, { f, plain: ` \xB7 ${f.t.passkeyKinds[p.kind]}`, children: f.t.passkeyKinds[p.kind] }),
|
|
2486
|
+
" \xB7 ",
|
|
2487
|
+
when(p.createdAt),
|
|
2488
|
+
" ",
|
|
2489
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "button", variant: "danger", loading: f.loading(`remove:${p.id}`), disabled: f.busy, className: f.cx("providerButton"), onClick: () => void remove(p.id), children: f.t.removePasskey })
|
|
2490
|
+
] }, p.id)) });
|
|
2491
|
+
if (list.length > 0 && !adding) {
|
|
2492
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Wrap, { f, as: "div", slot: "section", section: "passkeys", children: [
|
|
2493
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Heading, { f, children: f.t.passkeys }),
|
|
2494
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Note, { f, children: f.t.passkeysHelp }),
|
|
2495
|
+
general && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
|
|
2496
|
+
listed,
|
|
2497
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "button", variant: "secondary", disabled: f.busy, className: f.cx("providerButton"), onClick: () => {
|
|
2498
|
+
setDone(null);
|
|
2499
|
+
f.setError(null);
|
|
2500
|
+
setAdding(true);
|
|
2501
|
+
}, children: f.t.addAnotherPasskey }),
|
|
2502
|
+
done && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Say, { f, tone: "success", children: done })
|
|
2503
|
+
] });
|
|
2504
|
+
}
|
|
2432
2505
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Wrap, { f, as: "form", slot: "section", section: "passkeys", onSubmit: add, noValidate: true, children: [
|
|
2433
2506
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Heading, { f, children: f.t.passkeys }),
|
|
2434
2507
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Note, { f, children: f.t.passkeysHelp }),
|
|
2435
2508
|
general && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
|
|
2436
|
-
|
|
2437
|
-
p.name || f.t.passkeyUnnamed,
|
|
2438
|
-
p.kind !== "unknown" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Tag, { f, plain: ` \xB7 ${f.t.passkeyKinds[p.kind]}`, children: f.t.passkeyKinds[p.kind] }),
|
|
2439
|
-
" \xB7 ",
|
|
2440
|
-
when(p.createdAt),
|
|
2441
|
-
" ",
|
|
2442
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "button", variant: "danger", loading: f.loading(`remove:${p.id}`), disabled: f.busy, className: f.cx("providerButton"), onClick: () => void remove(p.id), children: f.t.removePasskey })
|
|
2443
|
-
] }, p.id)) }),
|
|
2509
|
+
listed,
|
|
2444
2510
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { f, name: "name", type: "text", label: f.t.passkeyName, value: name, autoComplete: "off", onChange: setName }),
|
|
2445
2511
|
account.hasPassword && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { f, name: "password", type: "password", label: f.t.currentPassword, value: password, autoComplete: "current-password", required: true, onChange: setPassword }),
|
|
2446
2512
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "submit", variant: "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.addPasskeyDevice }),
|
|
2447
2513
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "button", variant: "secondary", loading: f.loading("security_key"), disabled: f.busy, className: f.cx("providerButton"), onClick: () => void add(null, "security_key"), children: f.t.addSecurityKey }),
|
|
2514
|
+
list.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Cancel, { f, onClick: cancel }),
|
|
2448
2515
|
done && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Say, { f, tone: "success", children: done })
|
|
2449
2516
|
] });
|
|
2450
2517
|
}
|
|
2518
|
+
function Cancel({ f, onClick }) {
|
|
2519
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "button", variant: "secondary", disabled: f.busy, className: f.cx("providerButton"), onClick, children: f.t.cancel });
|
|
2520
|
+
}
|
|
2521
|
+
function RecoveryCodes({ f, codes }) {
|
|
2522
|
+
const [copied, setCopied] = (0, import_react.useState)(null);
|
|
2523
|
+
(0, import_react.useEffect)(() => setCopied(null), [codes]);
|
|
2524
|
+
const copy = async () => {
|
|
2525
|
+
try {
|
|
2526
|
+
await navigator.clipboard.writeText(codes.join("\n"));
|
|
2527
|
+
setCopied(true);
|
|
2528
|
+
} catch {
|
|
2529
|
+
setCopied(false);
|
|
2530
|
+
}
|
|
2531
|
+
};
|
|
2532
|
+
const download = () => {
|
|
2533
|
+
const file = new Blob([`${f.t.recoveryCodes}
|
|
2534
|
+
|
|
2535
|
+
${codes.join("\n")}
|
|
2536
|
+
`], { type: "text/plain;charset=utf-8" });
|
|
2537
|
+
const url = URL.createObjectURL(file);
|
|
2538
|
+
const a = document.createElement("a");
|
|
2539
|
+
a.href = url;
|
|
2540
|
+
a.download = "recovery-codes.txt";
|
|
2541
|
+
document.body.appendChild(a);
|
|
2542
|
+
a.click();
|
|
2543
|
+
a.remove();
|
|
2544
|
+
setTimeout(() => URL.revokeObjectURL(url), 0);
|
|
2545
|
+
};
|
|
2546
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
2547
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Note, { f, children: f.t.keepCodes }),
|
|
2548
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: f.cx("codes"), children: codes.map((c) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: c }) }, c)) }),
|
|
2549
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "button", variant: "secondary", className: f.cx("providerButton"), onClick: () => void copy(), children: f.t.copyCodes }),
|
|
2550
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "button", variant: "secondary", className: f.cx("providerButton"), onClick: download, children: f.t.downloadCodes }),
|
|
2551
|
+
copied === true && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Say, { f, tone: "success", children: f.t.codesCopied }),
|
|
2552
|
+
copied === false && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Say, { f, tone: "danger", children: f.t.codesNotCopied })
|
|
2553
|
+
] });
|
|
2554
|
+
}
|
|
2451
2555
|
function ProfilePart({ props, account, onSaved }) {
|
|
2452
2556
|
const auth = useAuth();
|
|
2453
2557
|
const { f, done, setDone, run, general } = useSection(props);
|
|
2454
2558
|
const [name, setName] = (0, import_react.useState)(account.name);
|
|
2559
|
+
const [editing, setEditing] = (0, import_react.useState)(account.name.trim() === "");
|
|
2455
2560
|
const submit = async (e) => {
|
|
2456
2561
|
e.preventDefault();
|
|
2457
2562
|
const r = await run(() => auth.account.update({ name }));
|
|
2458
2563
|
if (!r.ok) return;
|
|
2459
2564
|
onSaved(r.account);
|
|
2565
|
+
setName(r.account.name);
|
|
2566
|
+
setEditing(r.account.name.trim() === "");
|
|
2460
2567
|
setDone(f.t.saved);
|
|
2461
2568
|
props.onSaved?.({ kind: "profile.saved", name: r.account.name });
|
|
2462
2569
|
};
|
|
2570
|
+
const cancel = () => {
|
|
2571
|
+
setName(account.name);
|
|
2572
|
+
f.setError(null);
|
|
2573
|
+
setEditing(false);
|
|
2574
|
+
};
|
|
2575
|
+
if (!editing) {
|
|
2576
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Wrap, { f, as: "div", slot: "section", section: "profile", children: [
|
|
2577
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Heading, { f, children: f.t.profile }),
|
|
2578
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Note, { f, children: account.name }),
|
|
2579
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Note, { f, children: account.email }),
|
|
2580
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "button", variant: "secondary", disabled: f.busy, className: f.cx("providerButton"), onClick: () => {
|
|
2581
|
+
setDone(null);
|
|
2582
|
+
setEditing(true);
|
|
2583
|
+
}, children: f.t.change }),
|
|
2584
|
+
done && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Say, { f, tone: "success", children: done })
|
|
2585
|
+
] });
|
|
2586
|
+
}
|
|
2463
2587
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Wrap, { f, as: "form", slot: "section", section: "profile", onSubmit: submit, noValidate: true, children: [
|
|
2464
2588
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Heading, { f, children: f.t.profile }),
|
|
2465
2589
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Note, { f, children: account.email }),
|
|
2466
2590
|
general && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
|
|
2467
2591
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { f, name: "name", type: "text", label: f.t.name, value: name, autoComplete: "name", onChange: setName }),
|
|
2468
2592
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "submit", variant: "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.save }),
|
|
2593
|
+
account.name.trim() !== "" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Cancel, { f, onClick: cancel }),
|
|
2469
2594
|
done && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Say, { f, tone: "success", children: done })
|
|
2470
2595
|
] });
|
|
2471
2596
|
}
|
|
@@ -2474,15 +2599,35 @@ function EmailPart({ props, account }) {
|
|
|
2474
2599
|
const { f, done, setDone, run, general } = useSection(props);
|
|
2475
2600
|
const [email, setEmail] = (0, import_react.useState)("");
|
|
2476
2601
|
const [password, setPassword] = (0, import_react.useState)("");
|
|
2602
|
+
const [editing, setEditing] = (0, import_react.useState)(false);
|
|
2477
2603
|
const submit = async (e) => {
|
|
2478
2604
|
e.preventDefault();
|
|
2479
2605
|
if (!f.check(checkEmail(email), account.hasPassword && checkPassword(password))) return;
|
|
2480
2606
|
const r = await run(() => auth.account.changeEmail({ email, password }));
|
|
2481
2607
|
if (!r.ok) return;
|
|
2608
|
+
setEmail("");
|
|
2482
2609
|
setPassword("");
|
|
2610
|
+
setEditing(false);
|
|
2483
2611
|
setDone(f.t.emailSent.replace("{email}", r.email));
|
|
2484
2612
|
props.onSaved?.({ kind: "email.change_requested", email: r.email });
|
|
2485
2613
|
};
|
|
2614
|
+
const cancel = () => {
|
|
2615
|
+
setEmail("");
|
|
2616
|
+
setPassword("");
|
|
2617
|
+
f.setError(null);
|
|
2618
|
+
setEditing(false);
|
|
2619
|
+
};
|
|
2620
|
+
if (!editing) {
|
|
2621
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Wrap, { f, as: "div", slot: "section", section: "email", children: [
|
|
2622
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Heading, { f, children: f.t.emailAddress }),
|
|
2623
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Note, { f, children: account.email }),
|
|
2624
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "button", variant: "secondary", disabled: f.busy, className: f.cx("providerButton"), onClick: () => {
|
|
2625
|
+
setDone(null);
|
|
2626
|
+
setEditing(true);
|
|
2627
|
+
}, children: f.t.changeEmail }),
|
|
2628
|
+
done && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Say, { f, tone: "success", children: done })
|
|
2629
|
+
] });
|
|
2630
|
+
}
|
|
2486
2631
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Wrap, { f, as: "form", slot: "section", section: "email", onSubmit: submit, noValidate: true, children: [
|
|
2487
2632
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Heading, { f, children: f.t.emailAddress }),
|
|
2488
2633
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Note, { f, children: account.email }),
|
|
@@ -2490,7 +2635,7 @@ function EmailPart({ props, account }) {
|
|
|
2490
2635
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { f, name: "email", type: "email", label: f.t.newEmail, value: email, autoComplete: "email", required: true, onChange: setEmail }),
|
|
2491
2636
|
account.hasPassword && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { f, name: "password", type: "password", label: f.t.currentPassword, value: password, autoComplete: "current-password", required: true, onChange: setPassword }),
|
|
2492
2637
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "submit", variant: "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.changeEmail }),
|
|
2493
|
-
|
|
2638
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Cancel, { f, onClick: cancel })
|
|
2494
2639
|
] });
|
|
2495
2640
|
}
|
|
2496
2641
|
function LinkedPart({ props }) {
|
|
@@ -2555,6 +2700,7 @@ function PasswordPart({ props }) {
|
|
|
2555
2700
|
const { f, done, setDone, run, general } = useSection(props);
|
|
2556
2701
|
const [password, setPassword] = (0, import_react.useState)("");
|
|
2557
2702
|
const [newPassword, setNewPassword] = (0, import_react.useState)("");
|
|
2703
|
+
const [editing, setEditing] = (0, import_react.useState)(false);
|
|
2558
2704
|
usePasswordPolicy(f, useMethods(auth));
|
|
2559
2705
|
const submit = async (e) => {
|
|
2560
2706
|
e.preventDefault();
|
|
@@ -2563,16 +2709,34 @@ function PasswordPart({ props }) {
|
|
|
2563
2709
|
if (!r.ok) return;
|
|
2564
2710
|
setPassword("");
|
|
2565
2711
|
setNewPassword("");
|
|
2712
|
+
setEditing(false);
|
|
2566
2713
|
setDone(f.t.passwordChangedHere);
|
|
2567
2714
|
props.onSaved?.({ kind: "password.changed" });
|
|
2568
2715
|
};
|
|
2716
|
+
const cancel = () => {
|
|
2717
|
+
setPassword("");
|
|
2718
|
+
setNewPassword("");
|
|
2719
|
+
f.setError(null);
|
|
2720
|
+
setEditing(false);
|
|
2721
|
+
};
|
|
2722
|
+
if (!editing) {
|
|
2723
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Wrap, { f, as: "div", slot: "section", section: "password", children: [
|
|
2724
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Heading, { f, children: f.t.password }),
|
|
2725
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Note, { f, children: f.t.passwordSet }),
|
|
2726
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "button", variant: "secondary", disabled: f.busy, className: f.cx("providerButton"), onClick: () => {
|
|
2727
|
+
setDone(null);
|
|
2728
|
+
setEditing(true);
|
|
2729
|
+
}, children: f.t.changePassword }),
|
|
2730
|
+
done && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Say, { f, tone: "success", children: done })
|
|
2731
|
+
] });
|
|
2732
|
+
}
|
|
2569
2733
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Wrap, { f, as: "form", slot: "section", section: "password", onSubmit: submit, noValidate: true, children: [
|
|
2570
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Heading, { f, children: f.t.
|
|
2734
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Heading, { f, children: f.t.password }),
|
|
2571
2735
|
general && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
|
|
2572
2736
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { f, name: "password", type: "password", label: f.t.currentPassword, value: password, autoComplete: "current-password", required: true, onChange: setPassword }),
|
|
2573
2737
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { f, name: "newPassword", type: "password", label: f.t.newPassword, value: newPassword, autoComplete: "new-password", required: true, onChange: setNewPassword, hint: f.passwordRule }),
|
|
2574
2738
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "submit", variant: "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.changePassword }),
|
|
2575
|
-
|
|
2739
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Cancel, { f, onClick: cancel })
|
|
2576
2740
|
] });
|
|
2577
2741
|
}
|
|
2578
2742
|
function SecondStepPart({ props, account, onChanged }) {
|
|
@@ -2582,10 +2746,11 @@ function SecondStepPart({ props, account, onChanged }) {
|
|
|
2582
2746
|
const [code, setCode] = (0, import_react.useState)("");
|
|
2583
2747
|
const [setup, setSetup] = (0, import_react.useState)(null);
|
|
2584
2748
|
const [codes, setCodes] = (0, import_react.useState)(null);
|
|
2749
|
+
const [asking, setAsking] = (0, import_react.useState)(null);
|
|
2585
2750
|
const start = async (e) => {
|
|
2586
2751
|
e.preventDefault();
|
|
2587
2752
|
const r = await run(() => auth.account.mfa.setup({ password }));
|
|
2588
|
-
if (r.ok) setSetup({ secret: r.secret, otpauthUri: r.otpauthUri });
|
|
2753
|
+
if (r.ok) setSetup({ secret: r.secret, otpauthUri: r.otpauthUri, qr: r.qr ?? "" });
|
|
2589
2754
|
};
|
|
2590
2755
|
const confirm = async (e) => {
|
|
2591
2756
|
e.preventDefault();
|
|
@@ -2598,30 +2763,41 @@ function SecondStepPart({ props, account, onChanged }) {
|
|
|
2598
2763
|
onChanged(true);
|
|
2599
2764
|
props.onSaved?.({ kind: "mfa.enabled" });
|
|
2600
2765
|
};
|
|
2601
|
-
const turnOff = async (
|
|
2602
|
-
|
|
2603
|
-
const r = await run(() => auth.account.mfa.disable({ password }));
|
|
2766
|
+
const turnOff = async (key) => {
|
|
2767
|
+
const r = await run(() => auth.account.mfa.disable({ password }), key);
|
|
2604
2768
|
if (!r.ok) return;
|
|
2605
2769
|
setPassword("");
|
|
2770
|
+
setAsking(null);
|
|
2606
2771
|
setCodes(null);
|
|
2607
2772
|
onChanged(false);
|
|
2608
2773
|
props.onSaved?.({ kind: "mfa.disabled" });
|
|
2609
2774
|
};
|
|
2610
|
-
const renew = async () => {
|
|
2611
|
-
const r = await run(() => auth.account.mfa.recoveryCodes({ password }),
|
|
2775
|
+
const renew = async (key) => {
|
|
2776
|
+
const r = await run(() => auth.account.mfa.recoveryCodes({ password }), key);
|
|
2612
2777
|
if (!r.ok) return;
|
|
2778
|
+
setPassword("");
|
|
2779
|
+
setAsking(null);
|
|
2613
2780
|
setCodes(r.recoveryCodes);
|
|
2614
2781
|
props.onSaved?.({ kind: "recovery_codes.regenerated" });
|
|
2615
2782
|
};
|
|
2783
|
+
const press = (what) => {
|
|
2784
|
+
f.setError(null);
|
|
2785
|
+
if (!account.hasPassword) return void (what === "off" ? turnOff(what) : renew(what));
|
|
2786
|
+
setPassword("");
|
|
2787
|
+
setCodes(null);
|
|
2788
|
+
setAsking(what);
|
|
2789
|
+
};
|
|
2790
|
+
const cancel = () => {
|
|
2791
|
+
setPassword("");
|
|
2792
|
+
f.setError(null);
|
|
2793
|
+
setAsking(null);
|
|
2794
|
+
};
|
|
2616
2795
|
const passwordField = account.hasPassword && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { f, name: "password", type: "password", label: f.t.currentPassword, value: password, autoComplete: "current-password", required: true, onChange: setPassword });
|
|
2617
|
-
const shown = codes && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
2618
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Note, { f, children: f.t.keepCodes }),
|
|
2619
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: f.cx("codes"), children: codes.map((c) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: c }) }, c)) })
|
|
2620
|
-
] });
|
|
2621
2796
|
if (setup) {
|
|
2622
2797
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Wrap, { f, as: "form", slot: "section", section: "secondStep", onSubmit: confirm, noValidate: true, children: [
|
|
2623
2798
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Heading, { f, children: f.t.secondStep }),
|
|
2624
2799
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Note, { f, children: f.t.addToApp }),
|
|
2800
|
+
setup.qr && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { className: f.cx("qr"), src: setup.qr, width: 220, height: 220, alt: f.t.qrAlt }),
|
|
2625
2801
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { className: f.cx("secret"), children: setup.secret }),
|
|
2626
2802
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(A, { f, href: setup.otpauthUri, children: f.t.openInApp }),
|
|
2627
2803
|
general && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
|
|
@@ -2629,14 +2805,36 @@ function SecondStepPart({ props, account, onChanged }) {
|
|
|
2629
2805
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "submit", variant: "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.verify })
|
|
2630
2806
|
] });
|
|
2631
2807
|
}
|
|
2632
|
-
|
|
2808
|
+
if (!account.mfaEnabled) {
|
|
2809
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Wrap, { f, as: "form", slot: "section", section: "secondStep", onSubmit: start, noValidate: true, children: [
|
|
2810
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Heading, { f, children: f.t.secondStep }),
|
|
2811
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Note, { f, children: f.t.secondStepOff }),
|
|
2812
|
+
general && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
|
|
2813
|
+
passwordField,
|
|
2814
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "submit", variant: "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.turnOn })
|
|
2815
|
+
] });
|
|
2816
|
+
}
|
|
2817
|
+
if (asking) {
|
|
2818
|
+
const submit = (e) => {
|
|
2819
|
+
e.preventDefault();
|
|
2820
|
+
void (asking === "off" ? turnOff(SUBMIT) : renew(SUBMIT));
|
|
2821
|
+
};
|
|
2822
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Wrap, { f, as: "form", slot: "section", section: "secondStep", onSubmit: submit, noValidate: true, children: [
|
|
2823
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Heading, { f, children: f.t.secondStep }),
|
|
2824
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Note, { f, children: f.t.secondStepOn }),
|
|
2825
|
+
general && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
|
|
2826
|
+
passwordField,
|
|
2827
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "submit", variant: asking === "off" ? "danger" : "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: asking === "off" ? f.t.turnOff : f.t.newRecoveryCodes }),
|
|
2828
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Cancel, { f, onClick: cancel })
|
|
2829
|
+
] });
|
|
2830
|
+
}
|
|
2831
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Wrap, { f, as: "div", slot: "section", section: "secondStep", children: [
|
|
2633
2832
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Heading, { f, children: f.t.secondStep }),
|
|
2634
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Note, { f, children:
|
|
2635
|
-
|
|
2833
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Note, { f, children: f.t.secondStepOn }),
|
|
2834
|
+
codes && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RecoveryCodes, { f, codes }),
|
|
2636
2835
|
general && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
|
|
2637
|
-
|
|
2638
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "
|
|
2639
|
-
account.mfaEnabled && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "button", variant: "secondary", loading: f.loading("codes"), disabled: f.busy, className: f.cx("providerButton"), onClick: () => void renew(), children: f.t.newRecoveryCodes })
|
|
2836
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "button", variant: "danger", loading: f.loading("off"), disabled: f.busy, className: f.cx("button"), onClick: () => press("off"), children: f.t.turnOff }),
|
|
2837
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "button", variant: "secondary", loading: f.loading("codes"), disabled: f.busy, className: f.cx("providerButton"), onClick: () => press("codes"), children: f.t.newRecoveryCodes })
|
|
2640
2838
|
] });
|
|
2641
2839
|
}
|
|
2642
2840
|
function PhonePart({ props, account, onChanged }) {
|
|
@@ -2649,6 +2847,7 @@ function PhonePart({ props, account, onChanged }) {
|
|
|
2649
2847
|
const [code, setCode] = (0, import_react.useState)("");
|
|
2650
2848
|
const [sentTo, setSentTo] = (0, import_react.useState)("");
|
|
2651
2849
|
const [codes, setCodes] = (0, import_react.useState)(null);
|
|
2850
|
+
const [removing, setRemoving] = (0, import_react.useState)(false);
|
|
2652
2851
|
const load = () => auth.account.mfa.factors().then((w) => {
|
|
2653
2852
|
setWays(w);
|
|
2654
2853
|
if (w && w.phoneChannels.length > 0 && !w.phoneChannels.includes(channel)) setChannel(w.phoneChannels[0]);
|
|
@@ -2669,21 +2868,34 @@ function PhonePart({ props, account, onChanged }) {
|
|
|
2669
2868
|
setSentTo("");
|
|
2670
2869
|
setCode("");
|
|
2671
2870
|
setPassword("");
|
|
2871
|
+
setNumber("");
|
|
2672
2872
|
if (r.recoveryCodes.length > 0) setCodes(r.recoveryCodes);
|
|
2673
2873
|
onChanged(true);
|
|
2674
2874
|
props.onSaved?.({ kind: "phone.added", channel });
|
|
2675
2875
|
await load();
|
|
2676
2876
|
};
|
|
2677
|
-
const remove = async (
|
|
2678
|
-
|
|
2679
|
-
const r = await run(() => auth.account.mfa.removePhone({ password }));
|
|
2877
|
+
const remove = async (key) => {
|
|
2878
|
+
const r = await run(() => auth.account.mfa.removePhone({ password }), key);
|
|
2680
2879
|
if (!r.ok) return;
|
|
2681
2880
|
setPassword("");
|
|
2881
|
+
setRemoving(false);
|
|
2882
|
+
setCodes(null);
|
|
2682
2883
|
await load();
|
|
2683
2884
|
const left = await auth.account.mfa.factors();
|
|
2684
2885
|
onChanged(Boolean(left?.totp));
|
|
2685
2886
|
props.onSaved?.({ kind: "phone.removed" });
|
|
2686
2887
|
};
|
|
2888
|
+
const press = () => {
|
|
2889
|
+
f.setError(null);
|
|
2890
|
+
if (!account.hasPassword) return void remove("remove");
|
|
2891
|
+
setPassword("");
|
|
2892
|
+
setRemoving(true);
|
|
2893
|
+
};
|
|
2894
|
+
const cancel = () => {
|
|
2895
|
+
setPassword("");
|
|
2896
|
+
f.setError(null);
|
|
2897
|
+
setRemoving(false);
|
|
2898
|
+
};
|
|
2687
2899
|
const passwordField = account.hasPassword && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { f, name: "password", type: "password", label: f.t.currentPassword, value: password, autoComplete: "current-password", required: true, onChange: setPassword });
|
|
2688
2900
|
if (sentTo) {
|
|
2689
2901
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Wrap, { f, as: "form", slot: "section", section: "phone", onSubmit: confirm, noValidate: true, children: [
|
|
@@ -2694,23 +2906,46 @@ function PhonePart({ props, account, onChanged }) {
|
|
|
2694
2906
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "submit", variant: "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.verify })
|
|
2695
2907
|
] });
|
|
2696
2908
|
}
|
|
2697
|
-
|
|
2909
|
+
if (ways.phone) {
|
|
2910
|
+
const by = ways.phone.channel === "whatsapp" ? f.t.byWhatsapp : ways.phone.channel === "sms" ? f.t.bySms : "";
|
|
2911
|
+
const on = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Note, { f, children: [
|
|
2912
|
+
f.t.phoneOn.replace("{to}", ways.phone.number),
|
|
2913
|
+
by && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Tag, { f, plain: ` \xB7 ${by}`, children: by })
|
|
2914
|
+
] });
|
|
2915
|
+
if (removing) {
|
|
2916
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Wrap, { f, as: "form", slot: "section", section: "phone", onSubmit: (e) => {
|
|
2917
|
+
e.preventDefault();
|
|
2918
|
+
void remove(SUBMIT);
|
|
2919
|
+
}, noValidate: true, children: [
|
|
2920
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Heading, { f, children: f.t.phone }),
|
|
2921
|
+
on,
|
|
2922
|
+
general && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
|
|
2923
|
+
passwordField,
|
|
2924
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "submit", variant: "danger", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.removePhone }),
|
|
2925
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Cancel, { f, onClick: cancel })
|
|
2926
|
+
] });
|
|
2927
|
+
}
|
|
2928
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Wrap, { f, as: "div", slot: "section", section: "phone", children: [
|
|
2929
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Heading, { f, children: f.t.phone }),
|
|
2930
|
+
on,
|
|
2931
|
+
codes && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RecoveryCodes, { f, codes }),
|
|
2932
|
+
general && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
|
|
2933
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "button", variant: "danger", loading: f.loading("remove"), disabled: f.busy, className: f.cx("button"), onClick: press, children: f.t.removePhone })
|
|
2934
|
+
] });
|
|
2935
|
+
}
|
|
2936
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Wrap, { f, as: "form", slot: "section", section: "phone", onSubmit: add, noValidate: true, children: [
|
|
2698
2937
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Heading, { f, children: f.t.phone }),
|
|
2699
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Note, { f, children:
|
|
2700
|
-
codes && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
2701
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Note, { f, children: f.t.keepCodes }),
|
|
2702
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: f.cx("codes"), children: codes.map((c) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: c }) }, c)) })
|
|
2703
|
-
] }),
|
|
2938
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Note, { f, children: `${f.t.phoneOff} ${f.t.phoneHelp}` }),
|
|
2704
2939
|
general && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Say, { f, tone: "danger", children: f.say(general) }),
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2940
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { f, name: "phone", type: "tel", label: f.t.phone, value: number, autoComplete: "tel", required: true, onChange: setNumber }),
|
|
2941
|
+
ways.phoneChannels.length > 1 && f.C.Select && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChannelPick, { f, value: channel, channels: ways.phoneChannels, onChange: setChannel }),
|
|
2942
|
+
ways.phoneChannels.length > 1 && !f.C.Select && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: f.cx("field"), role: "radiogroup", children: ways.phoneChannels.map((c) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: f.cx("label"), children: [
|
|
2708
2943
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { type: "radio", name: "channel", value: c, checked: channel === c, disabled: f.busy, onChange: () => setChannel(c) }),
|
|
2709
2944
|
" ",
|
|
2710
2945
|
c === "whatsapp" ? f.t.byWhatsapp : f.t.bySms
|
|
2711
2946
|
] }, c)) }),
|
|
2712
2947
|
passwordField,
|
|
2713
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "submit", variant:
|
|
2948
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(f.Button, { type: "submit", variant: "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.addPhone })
|
|
2714
2949
|
] });
|
|
2715
2950
|
}
|
|
2716
2951
|
function AgentsPart({ props, when }) {
|