cauthy-auth 0.36.0 → 0.37.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/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +6 -0
- package/dist/index.mjs.map +1 -1
- package/dist/react.d.mts +12 -0
- package/dist/react.d.ts +12 -0
- package/dist/react.js +277 -45
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +277 -45
- package/dist/react.mjs.map +1 -1
- package/package.json +1 -1
package/dist/react.mjs
CHANGED
|
@@ -801,6 +801,13 @@ var TEXTS = {
|
|
|
801
801
|
recoveryCodes: "Recovery codes",
|
|
802
802
|
newRecoveryCodes: "New recovery codes",
|
|
803
803
|
keepCodes: "Keep these codes somewhere safe. Each works once, and they are not shown again.",
|
|
804
|
+
copyCodes: "Copy all",
|
|
805
|
+
downloadCodes: "Download .txt",
|
|
806
|
+
codesCopied: "The codes were copied.",
|
|
807
|
+
codesNotCopied: "The codes could not be copied. Select them and copy them by hand.",
|
|
808
|
+
change: "Change",
|
|
809
|
+
passwordSet: "Your account has a password.",
|
|
810
|
+
addAnotherPasskey: "Add a passkey",
|
|
804
811
|
passkeys: "Passkeys",
|
|
805
812
|
managePasskeys: "Add or remove a passkey",
|
|
806
813
|
passkeysHelp: "Sign in with your fingerprint, your face or your device's lock, without a password.",
|
|
@@ -985,6 +992,13 @@ var TEXTS = {
|
|
|
985
992
|
recoveryCodes: "C\xF3digos de recuperaci\xF3n",
|
|
986
993
|
newRecoveryCodes: "Nuevos c\xF3digos de recuperaci\xF3n",
|
|
987
994
|
keepCodes: "Guarda estos c\xF3digos en un lugar seguro. Cada uno sirve una vez y no se vuelven a mostrar.",
|
|
995
|
+
copyCodes: "Copiar todos",
|
|
996
|
+
downloadCodes: "Descargar .txt",
|
|
997
|
+
codesCopied: "Los c\xF3digos quedaron copiados.",
|
|
998
|
+
codesNotCopied: "No se pudieron copiar los c\xF3digos. Selecci\xF3nalos y c\xF3pialos a mano.",
|
|
999
|
+
change: "Cambiar",
|
|
1000
|
+
passwordSet: "Tu cuenta tiene contrase\xF1a.",
|
|
1001
|
+
addAnotherPasskey: "Agregar una llave de acceso",
|
|
988
1002
|
passkeys: "Llaves de acceso",
|
|
989
1003
|
managePasskeys: "Agregar o quitar una llave de acceso",
|
|
990
1004
|
passkeysHelp: "Entra con tu huella, tu rostro o el bloqueo de tu dispositivo, sin contrase\xF1a.",
|
|
@@ -2160,6 +2174,8 @@ function OrganizationMembers(props) {
|
|
|
2160
2174
|
const [role, setRole] = useState("");
|
|
2161
2175
|
const [name, setName] = useState("");
|
|
2162
2176
|
const [asking, setAsking] = useState(null);
|
|
2177
|
+
const [adding, setAdding] = useState(false);
|
|
2178
|
+
const [renamingOpen, setRenamingOpen] = useState(false);
|
|
2163
2179
|
const [gone, setGone] = useState(null);
|
|
2164
2180
|
const id = props.organizationId;
|
|
2165
2181
|
const when = props.formatDate ?? ((iso) => new Date(iso).toLocaleDateString());
|
|
@@ -2194,6 +2210,7 @@ function OrganizationMembers(props) {
|
|
|
2194
2210
|
const r = await run(() => auth.organizations.add(id, { email, role, locale: props.locale }), "add");
|
|
2195
2211
|
if (!r.ok) return;
|
|
2196
2212
|
setEmail("");
|
|
2213
|
+
setAdding(false);
|
|
2197
2214
|
setDone(f.t.memberAdded.replace("{email}", r.member.email));
|
|
2198
2215
|
saved({ kind: "member.added", organizationId: id, userId: r.member.userId, email: r.member.email, role: r.member.role || role });
|
|
2199
2216
|
await load();
|
|
@@ -2224,6 +2241,7 @@ function OrganizationMembers(props) {
|
|
|
2224
2241
|
if (!r.ok) return;
|
|
2225
2242
|
setSeat(r.organization);
|
|
2226
2243
|
setName(r.organization.name);
|
|
2244
|
+
setRenamingOpen(false);
|
|
2227
2245
|
setDone(f.t.organizationRenamed.replace("{name}", r.organization.name));
|
|
2228
2246
|
saved({ kind: "organization.renamed", organizationId: id, name: r.organization.name });
|
|
2229
2247
|
};
|
|
@@ -2253,6 +2271,24 @@ function OrganizationMembers(props) {
|
|
|
2253
2271
|
const archiving = seat.can.archive && !hidden("archive");
|
|
2254
2272
|
const deleting = seat.can.delete && !hidden("delete");
|
|
2255
2273
|
const renaming = seat.can.update && !hidden("rename");
|
|
2274
|
+
const alone = members !== null && members.every((m) => m.you);
|
|
2275
|
+
const addOpen = adding || alone;
|
|
2276
|
+
const open = (form) => {
|
|
2277
|
+
setDone(null);
|
|
2278
|
+
f.setError(null);
|
|
2279
|
+
if (form === "add") setAdding(true);
|
|
2280
|
+
else setRenamingOpen(true);
|
|
2281
|
+
};
|
|
2282
|
+
const cancelAdd = () => {
|
|
2283
|
+
setEmail("");
|
|
2284
|
+
f.setError(null);
|
|
2285
|
+
setAdding(false);
|
|
2286
|
+
};
|
|
2287
|
+
const cancelRename = () => {
|
|
2288
|
+
setName(seat.name);
|
|
2289
|
+
f.setError(null);
|
|
2290
|
+
setRenamingOpen(false);
|
|
2291
|
+
};
|
|
2256
2292
|
return /* @__PURE__ */ jsxs(Wrap, { f, as: "div", slot: "account", root, children: [
|
|
2257
2293
|
/* @__PURE__ */ jsxs(Wrap, { f, as: "section", slot: "section", section: "members", children: [
|
|
2258
2294
|
/* @__PURE__ */ jsxs(Heading, { f, children: [
|
|
@@ -2316,18 +2352,23 @@ function OrganizationMembers(props) {
|
|
|
2316
2352
|
}) }),
|
|
2317
2353
|
done && /* @__PURE__ */ jsx(Say, { f, tone: "success", children: done })
|
|
2318
2354
|
] }),
|
|
2319
|
-
manage && giveable.length > 0 && /* @__PURE__ */ jsxs(Wrap, { f, as: "form", slot: "section", section: "add-member", onSubmit: add, noValidate: true, children: [
|
|
2355
|
+
manage && giveable.length > 0 && (addOpen ? /* @__PURE__ */ jsxs(Wrap, { f, as: "form", slot: "section", section: "add-member", onSubmit: add, noValidate: true, children: [
|
|
2320
2356
|
/* @__PURE__ */ jsx(Heading, { f, children: f.t.memberAdd }),
|
|
2321
2357
|
/* @__PURE__ */ jsx(Field, { f, name: "email", type: "email", label: f.t.email, value: email, autoComplete: "off", required: true, onChange: setEmail }),
|
|
2322
2358
|
/* @__PURE__ */ jsx(AddRole, { f, value: role, options: giveable.map((c) => ({ value: c.role, label: roleName(c) })), onChange: setRole }),
|
|
2323
|
-
/* @__PURE__ */ jsx(f.Button, { type: "submit", variant: "primary", loading: f.loading("add"), disabled: f.busy, className: f.cx("button"), children: f.t.memberAdd })
|
|
2324
|
-
|
|
2359
|
+
/* @__PURE__ */ jsx(f.Button, { type: "submit", variant: "primary", loading: f.loading("add"), disabled: f.busy, className: f.cx("button"), children: f.t.memberAdd }),
|
|
2360
|
+
!alone && /* @__PURE__ */ jsx(Cancel, { f, onClick: cancelAdd })
|
|
2361
|
+
] }) : /* @__PURE__ */ jsx(Wrap, { f, as: "div", slot: "section", section: "add-member", children: /* @__PURE__ */ jsx(f.Button, { type: "button", variant: "secondary", disabled: f.busy, className: f.cx("providerButton"), onClick: () => open("add"), children: f.t.memberAdd }) })),
|
|
2325
2362
|
(renaming || archiving || deleting) && /* @__PURE__ */ jsxs(Wrap, { f, as: "section", slot: "section", section: "organization", children: [
|
|
2326
2363
|
/* @__PURE__ */ jsx(Heading, { f, children: f.t.organization }),
|
|
2327
|
-
renaming && /* @__PURE__ */ jsxs(Wrap, { f, as: "form", section: "rename", onSubmit: rename, noValidate: true, children: [
|
|
2364
|
+
renaming && (renamingOpen ? /* @__PURE__ */ jsxs(Wrap, { f, as: "form", section: "rename", onSubmit: rename, noValidate: true, children: [
|
|
2328
2365
|
/* @__PURE__ */ jsx(Field, { f, name: "name", type: "text", label: f.t.name, value: name, autoComplete: "organization", required: true, onChange: setName }),
|
|
2329
|
-
/* @__PURE__ */ jsx(f.Button, { type: "submit", variant: "primary", loading: f.loading("rename"), disabled: f.busy, className: f.cx("button"), children: f.t.organizationRename })
|
|
2330
|
-
|
|
2366
|
+
/* @__PURE__ */ jsx(f.Button, { type: "submit", variant: "primary", loading: f.loading("rename"), disabled: f.busy, className: f.cx("button"), children: f.t.organizationRename }),
|
|
2367
|
+
/* @__PURE__ */ jsx(Cancel, { f, onClick: cancelRename })
|
|
2368
|
+
] }) : /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
2369
|
+
/* @__PURE__ */ jsx(Note, { f, children: seat.name }),
|
|
2370
|
+
/* @__PURE__ */ jsx(f.Button, { type: "button", variant: "secondary", disabled: f.busy, className: f.cx("providerButton"), onClick: () => open("rename"), children: f.t.organizationRename })
|
|
2371
|
+
] })),
|
|
2331
2372
|
asking === "archive" ? confirming(archiveQuestion, f.t.organizationArchive, () => void close("archive")) : asking === "delete" ? confirming(deleteQuestion, f.t.organizationDelete, () => void close("delete")) : /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
2332
2373
|
archiving && /* @__PURE__ */ 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 }),
|
|
2333
2374
|
deleting && /* @__PURE__ */ 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 })
|
|
@@ -2346,6 +2387,7 @@ function PasskeysPart({ props, account, accountUrl, when }) {
|
|
|
2346
2387
|
const [list, setList] = useState([]);
|
|
2347
2388
|
const [name, setName] = useState("");
|
|
2348
2389
|
const [password, setPassword] = useState("");
|
|
2390
|
+
const [adding, setAdding] = useState(false);
|
|
2349
2391
|
useEffect(() => {
|
|
2350
2392
|
void auth.methods().then((m) => {
|
|
2351
2393
|
const can2 = m.passkeyHere && canUsePasskeys();
|
|
@@ -2371,6 +2413,7 @@ function PasskeysPart({ props, account, accountUrl, when }) {
|
|
|
2371
2413
|
setList([...list, r.passkey]);
|
|
2372
2414
|
setName("");
|
|
2373
2415
|
setPassword("");
|
|
2416
|
+
setAdding(false);
|
|
2374
2417
|
setDone(f.t.passkeyAdded);
|
|
2375
2418
|
props.onSaved?.({ kind: "passkey.added", id: r.passkey.id });
|
|
2376
2419
|
};
|
|
@@ -2380,43 +2423,123 @@ function PasskeysPart({ props, account, accountUrl, when }) {
|
|
|
2380
2423
|
setList(list.filter((p) => p.id !== id));
|
|
2381
2424
|
props.onSaved?.({ kind: "passkey.removed", id });
|
|
2382
2425
|
};
|
|
2426
|
+
const cancel = () => {
|
|
2427
|
+
setName("");
|
|
2428
|
+
setPassword("");
|
|
2429
|
+
f.setError(null);
|
|
2430
|
+
setAdding(false);
|
|
2431
|
+
};
|
|
2432
|
+
const listed = list.length === 0 ? /* @__PURE__ */ jsx(Note, { f, children: f.t.noPasskeys }) : /* @__PURE__ */ jsx("ul", { className: f.cx("sessions"), children: list.map((p) => /* @__PURE__ */ jsxs("li", { className: f.cx("session"), children: [
|
|
2433
|
+
p.name || f.t.passkeyUnnamed,
|
|
2434
|
+
p.kind !== "unknown" && /* @__PURE__ */ jsx(Tag, { f, plain: ` \xB7 ${f.t.passkeyKinds[p.kind]}`, children: f.t.passkeyKinds[p.kind] }),
|
|
2435
|
+
" \xB7 ",
|
|
2436
|
+
when(p.createdAt),
|
|
2437
|
+
" ",
|
|
2438
|
+
/* @__PURE__ */ 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 })
|
|
2439
|
+
] }, p.id)) });
|
|
2440
|
+
if (list.length > 0 && !adding) {
|
|
2441
|
+
return /* @__PURE__ */ jsxs(Wrap, { f, as: "div", slot: "section", section: "passkeys", children: [
|
|
2442
|
+
/* @__PURE__ */ jsx(Heading, { f, children: f.t.passkeys }),
|
|
2443
|
+
/* @__PURE__ */ jsx(Note, { f, children: f.t.passkeysHelp }),
|
|
2444
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
2445
|
+
listed,
|
|
2446
|
+
/* @__PURE__ */ jsx(f.Button, { type: "button", variant: "secondary", disabled: f.busy, className: f.cx("providerButton"), onClick: () => {
|
|
2447
|
+
setDone(null);
|
|
2448
|
+
f.setError(null);
|
|
2449
|
+
setAdding(true);
|
|
2450
|
+
}, children: f.t.addAnotherPasskey }),
|
|
2451
|
+
done && /* @__PURE__ */ jsx(Say, { f, tone: "success", children: done })
|
|
2452
|
+
] });
|
|
2453
|
+
}
|
|
2383
2454
|
return /* @__PURE__ */ jsxs(Wrap, { f, as: "form", slot: "section", section: "passkeys", onSubmit: add, noValidate: true, children: [
|
|
2384
2455
|
/* @__PURE__ */ jsx(Heading, { f, children: f.t.passkeys }),
|
|
2385
2456
|
/* @__PURE__ */ jsx(Note, { f, children: f.t.passkeysHelp }),
|
|
2386
2457
|
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
2387
|
-
|
|
2388
|
-
p.name || f.t.passkeyUnnamed,
|
|
2389
|
-
p.kind !== "unknown" && /* @__PURE__ */ jsx(Tag, { f, plain: ` \xB7 ${f.t.passkeyKinds[p.kind]}`, children: f.t.passkeyKinds[p.kind] }),
|
|
2390
|
-
" \xB7 ",
|
|
2391
|
-
when(p.createdAt),
|
|
2392
|
-
" ",
|
|
2393
|
-
/* @__PURE__ */ 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 })
|
|
2394
|
-
] }, p.id)) }),
|
|
2458
|
+
listed,
|
|
2395
2459
|
/* @__PURE__ */ jsx(Field, { f, name: "name", type: "text", label: f.t.passkeyName, value: name, autoComplete: "off", onChange: setName }),
|
|
2396
2460
|
account.hasPassword && /* @__PURE__ */ jsx(Field, { f, name: "password", type: "password", label: f.t.currentPassword, value: password, autoComplete: "current-password", required: true, onChange: setPassword }),
|
|
2397
2461
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", variant: "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.addPasskeyDevice }),
|
|
2398
2462
|
/* @__PURE__ */ 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 }),
|
|
2463
|
+
list.length > 0 && /* @__PURE__ */ jsx(Cancel, { f, onClick: cancel }),
|
|
2399
2464
|
done && /* @__PURE__ */ jsx(Say, { f, tone: "success", children: done })
|
|
2400
2465
|
] });
|
|
2401
2466
|
}
|
|
2467
|
+
function Cancel({ f, onClick }) {
|
|
2468
|
+
return /* @__PURE__ */ jsx(f.Button, { type: "button", variant: "secondary", disabled: f.busy, className: f.cx("providerButton"), onClick, children: f.t.cancel });
|
|
2469
|
+
}
|
|
2470
|
+
function RecoveryCodes({ f, codes }) {
|
|
2471
|
+
const [copied, setCopied] = useState(null);
|
|
2472
|
+
useEffect(() => setCopied(null), [codes]);
|
|
2473
|
+
const copy = async () => {
|
|
2474
|
+
try {
|
|
2475
|
+
await navigator.clipboard.writeText(codes.join("\n"));
|
|
2476
|
+
setCopied(true);
|
|
2477
|
+
} catch {
|
|
2478
|
+
setCopied(false);
|
|
2479
|
+
}
|
|
2480
|
+
};
|
|
2481
|
+
const download = () => {
|
|
2482
|
+
const file = new Blob([`${f.t.recoveryCodes}
|
|
2483
|
+
|
|
2484
|
+
${codes.join("\n")}
|
|
2485
|
+
`], { type: "text/plain;charset=utf-8" });
|
|
2486
|
+
const url = URL.createObjectURL(file);
|
|
2487
|
+
const a = document.createElement("a");
|
|
2488
|
+
a.href = url;
|
|
2489
|
+
a.download = "recovery-codes.txt";
|
|
2490
|
+
document.body.appendChild(a);
|
|
2491
|
+
a.click();
|
|
2492
|
+
a.remove();
|
|
2493
|
+
setTimeout(() => URL.revokeObjectURL(url), 0);
|
|
2494
|
+
};
|
|
2495
|
+
return /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
2496
|
+
/* @__PURE__ */ jsx(Note, { f, children: f.t.keepCodes }),
|
|
2497
|
+
/* @__PURE__ */ jsx("ul", { className: f.cx("codes"), children: codes.map((c) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("code", { children: c }) }, c)) }),
|
|
2498
|
+
/* @__PURE__ */ jsx(f.Button, { type: "button", variant: "secondary", className: f.cx("providerButton"), onClick: () => void copy(), children: f.t.copyCodes }),
|
|
2499
|
+
/* @__PURE__ */ jsx(f.Button, { type: "button", variant: "secondary", className: f.cx("providerButton"), onClick: download, children: f.t.downloadCodes }),
|
|
2500
|
+
copied === true && /* @__PURE__ */ jsx(Say, { f, tone: "success", children: f.t.codesCopied }),
|
|
2501
|
+
copied === false && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.t.codesNotCopied })
|
|
2502
|
+
] });
|
|
2503
|
+
}
|
|
2402
2504
|
function ProfilePart({ props, account, onSaved }) {
|
|
2403
2505
|
const auth = useAuth();
|
|
2404
2506
|
const { f, done, setDone, run, general } = useSection(props);
|
|
2405
2507
|
const [name, setName] = useState(account.name);
|
|
2508
|
+
const [editing, setEditing] = useState(account.name.trim() === "");
|
|
2406
2509
|
const submit = async (e) => {
|
|
2407
2510
|
e.preventDefault();
|
|
2408
2511
|
const r = await run(() => auth.account.update({ name }));
|
|
2409
2512
|
if (!r.ok) return;
|
|
2410
2513
|
onSaved(r.account);
|
|
2514
|
+
setName(r.account.name);
|
|
2515
|
+
setEditing(r.account.name.trim() === "");
|
|
2411
2516
|
setDone(f.t.saved);
|
|
2412
2517
|
props.onSaved?.({ kind: "profile.saved", name: r.account.name });
|
|
2413
2518
|
};
|
|
2519
|
+
const cancel = () => {
|
|
2520
|
+
setName(account.name);
|
|
2521
|
+
f.setError(null);
|
|
2522
|
+
setEditing(false);
|
|
2523
|
+
};
|
|
2524
|
+
if (!editing) {
|
|
2525
|
+
return /* @__PURE__ */ jsxs(Wrap, { f, as: "div", slot: "section", section: "profile", children: [
|
|
2526
|
+
/* @__PURE__ */ jsx(Heading, { f, children: f.t.profile }),
|
|
2527
|
+
/* @__PURE__ */ jsx(Note, { f, children: account.name }),
|
|
2528
|
+
/* @__PURE__ */ jsx(Note, { f, children: account.email }),
|
|
2529
|
+
/* @__PURE__ */ jsx(f.Button, { type: "button", variant: "secondary", disabled: f.busy, className: f.cx("providerButton"), onClick: () => {
|
|
2530
|
+
setDone(null);
|
|
2531
|
+
setEditing(true);
|
|
2532
|
+
}, children: f.t.change }),
|
|
2533
|
+
done && /* @__PURE__ */ jsx(Say, { f, tone: "success", children: done })
|
|
2534
|
+
] });
|
|
2535
|
+
}
|
|
2414
2536
|
return /* @__PURE__ */ jsxs(Wrap, { f, as: "form", slot: "section", section: "profile", onSubmit: submit, noValidate: true, children: [
|
|
2415
2537
|
/* @__PURE__ */ jsx(Heading, { f, children: f.t.profile }),
|
|
2416
2538
|
/* @__PURE__ */ jsx(Note, { f, children: account.email }),
|
|
2417
2539
|
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
2418
2540
|
/* @__PURE__ */ jsx(Field, { f, name: "name", type: "text", label: f.t.name, value: name, autoComplete: "name", onChange: setName }),
|
|
2419
2541
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", variant: "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.save }),
|
|
2542
|
+
account.name.trim() !== "" && /* @__PURE__ */ jsx(Cancel, { f, onClick: cancel }),
|
|
2420
2543
|
done && /* @__PURE__ */ jsx(Say, { f, tone: "success", children: done })
|
|
2421
2544
|
] });
|
|
2422
2545
|
}
|
|
@@ -2425,15 +2548,35 @@ function EmailPart({ props, account }) {
|
|
|
2425
2548
|
const { f, done, setDone, run, general } = useSection(props);
|
|
2426
2549
|
const [email, setEmail] = useState("");
|
|
2427
2550
|
const [password, setPassword] = useState("");
|
|
2551
|
+
const [editing, setEditing] = useState(false);
|
|
2428
2552
|
const submit = async (e) => {
|
|
2429
2553
|
e.preventDefault();
|
|
2430
2554
|
if (!f.check(checkEmail(email), account.hasPassword && checkPassword(password))) return;
|
|
2431
2555
|
const r = await run(() => auth.account.changeEmail({ email, password }));
|
|
2432
2556
|
if (!r.ok) return;
|
|
2557
|
+
setEmail("");
|
|
2433
2558
|
setPassword("");
|
|
2559
|
+
setEditing(false);
|
|
2434
2560
|
setDone(f.t.emailSent.replace("{email}", r.email));
|
|
2435
2561
|
props.onSaved?.({ kind: "email.change_requested", email: r.email });
|
|
2436
2562
|
};
|
|
2563
|
+
const cancel = () => {
|
|
2564
|
+
setEmail("");
|
|
2565
|
+
setPassword("");
|
|
2566
|
+
f.setError(null);
|
|
2567
|
+
setEditing(false);
|
|
2568
|
+
};
|
|
2569
|
+
if (!editing) {
|
|
2570
|
+
return /* @__PURE__ */ jsxs(Wrap, { f, as: "div", slot: "section", section: "email", children: [
|
|
2571
|
+
/* @__PURE__ */ jsx(Heading, { f, children: f.t.emailAddress }),
|
|
2572
|
+
/* @__PURE__ */ jsx(Note, { f, children: account.email }),
|
|
2573
|
+
/* @__PURE__ */ jsx(f.Button, { type: "button", variant: "secondary", disabled: f.busy, className: f.cx("providerButton"), onClick: () => {
|
|
2574
|
+
setDone(null);
|
|
2575
|
+
setEditing(true);
|
|
2576
|
+
}, children: f.t.changeEmail }),
|
|
2577
|
+
done && /* @__PURE__ */ jsx(Say, { f, tone: "success", children: done })
|
|
2578
|
+
] });
|
|
2579
|
+
}
|
|
2437
2580
|
return /* @__PURE__ */ jsxs(Wrap, { f, as: "form", slot: "section", section: "email", onSubmit: submit, noValidate: true, children: [
|
|
2438
2581
|
/* @__PURE__ */ jsx(Heading, { f, children: f.t.emailAddress }),
|
|
2439
2582
|
/* @__PURE__ */ jsx(Note, { f, children: account.email }),
|
|
@@ -2441,7 +2584,7 @@ function EmailPart({ props, account }) {
|
|
|
2441
2584
|
/* @__PURE__ */ jsx(Field, { f, name: "email", type: "email", label: f.t.newEmail, value: email, autoComplete: "email", required: true, onChange: setEmail }),
|
|
2442
2585
|
account.hasPassword && /* @__PURE__ */ jsx(Field, { f, name: "password", type: "password", label: f.t.currentPassword, value: password, autoComplete: "current-password", required: true, onChange: setPassword }),
|
|
2443
2586
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", variant: "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.changeEmail }),
|
|
2444
|
-
|
|
2587
|
+
/* @__PURE__ */ jsx(Cancel, { f, onClick: cancel })
|
|
2445
2588
|
] });
|
|
2446
2589
|
}
|
|
2447
2590
|
function LinkedPart({ props }) {
|
|
@@ -2506,6 +2649,7 @@ function PasswordPart({ props }) {
|
|
|
2506
2649
|
const { f, done, setDone, run, general } = useSection(props);
|
|
2507
2650
|
const [password, setPassword] = useState("");
|
|
2508
2651
|
const [newPassword, setNewPassword] = useState("");
|
|
2652
|
+
const [editing, setEditing] = useState(false);
|
|
2509
2653
|
usePasswordPolicy(f, useMethods(auth));
|
|
2510
2654
|
const submit = async (e) => {
|
|
2511
2655
|
e.preventDefault();
|
|
@@ -2514,16 +2658,34 @@ function PasswordPart({ props }) {
|
|
|
2514
2658
|
if (!r.ok) return;
|
|
2515
2659
|
setPassword("");
|
|
2516
2660
|
setNewPassword("");
|
|
2661
|
+
setEditing(false);
|
|
2517
2662
|
setDone(f.t.passwordChangedHere);
|
|
2518
2663
|
props.onSaved?.({ kind: "password.changed" });
|
|
2519
2664
|
};
|
|
2665
|
+
const cancel = () => {
|
|
2666
|
+
setPassword("");
|
|
2667
|
+
setNewPassword("");
|
|
2668
|
+
f.setError(null);
|
|
2669
|
+
setEditing(false);
|
|
2670
|
+
};
|
|
2671
|
+
if (!editing) {
|
|
2672
|
+
return /* @__PURE__ */ jsxs(Wrap, { f, as: "div", slot: "section", section: "password", children: [
|
|
2673
|
+
/* @__PURE__ */ jsx(Heading, { f, children: f.t.password }),
|
|
2674
|
+
/* @__PURE__ */ jsx(Note, { f, children: f.t.passwordSet }),
|
|
2675
|
+
/* @__PURE__ */ jsx(f.Button, { type: "button", variant: "secondary", disabled: f.busy, className: f.cx("providerButton"), onClick: () => {
|
|
2676
|
+
setDone(null);
|
|
2677
|
+
setEditing(true);
|
|
2678
|
+
}, children: f.t.changePassword }),
|
|
2679
|
+
done && /* @__PURE__ */ jsx(Say, { f, tone: "success", children: done })
|
|
2680
|
+
] });
|
|
2681
|
+
}
|
|
2520
2682
|
return /* @__PURE__ */ jsxs(Wrap, { f, as: "form", slot: "section", section: "password", onSubmit: submit, noValidate: true, children: [
|
|
2521
|
-
/* @__PURE__ */ jsx(Heading, { f, children: f.t.
|
|
2683
|
+
/* @__PURE__ */ jsx(Heading, { f, children: f.t.password }),
|
|
2522
2684
|
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
2523
2685
|
/* @__PURE__ */ jsx(Field, { f, name: "password", type: "password", label: f.t.currentPassword, value: password, autoComplete: "current-password", required: true, onChange: setPassword }),
|
|
2524
2686
|
/* @__PURE__ */ jsx(Field, { f, name: "newPassword", type: "password", label: f.t.newPassword, value: newPassword, autoComplete: "new-password", required: true, onChange: setNewPassword, hint: f.passwordRule }),
|
|
2525
2687
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", variant: "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.changePassword }),
|
|
2526
|
-
|
|
2688
|
+
/* @__PURE__ */ jsx(Cancel, { f, onClick: cancel })
|
|
2527
2689
|
] });
|
|
2528
2690
|
}
|
|
2529
2691
|
function SecondStepPart({ props, account, onChanged }) {
|
|
@@ -2533,6 +2695,7 @@ function SecondStepPart({ props, account, onChanged }) {
|
|
|
2533
2695
|
const [code, setCode] = useState("");
|
|
2534
2696
|
const [setup, setSetup] = useState(null);
|
|
2535
2697
|
const [codes, setCodes] = useState(null);
|
|
2698
|
+
const [asking, setAsking] = useState(null);
|
|
2536
2699
|
const start = async (e) => {
|
|
2537
2700
|
e.preventDefault();
|
|
2538
2701
|
const r = await run(() => auth.account.mfa.setup({ password }));
|
|
@@ -2549,26 +2712,36 @@ function SecondStepPart({ props, account, onChanged }) {
|
|
|
2549
2712
|
onChanged(true);
|
|
2550
2713
|
props.onSaved?.({ kind: "mfa.enabled" });
|
|
2551
2714
|
};
|
|
2552
|
-
const turnOff = async (
|
|
2553
|
-
|
|
2554
|
-
const r = await run(() => auth.account.mfa.disable({ password }));
|
|
2715
|
+
const turnOff = async (key) => {
|
|
2716
|
+
const r = await run(() => auth.account.mfa.disable({ password }), key);
|
|
2555
2717
|
if (!r.ok) return;
|
|
2556
2718
|
setPassword("");
|
|
2719
|
+
setAsking(null);
|
|
2557
2720
|
setCodes(null);
|
|
2558
2721
|
onChanged(false);
|
|
2559
2722
|
props.onSaved?.({ kind: "mfa.disabled" });
|
|
2560
2723
|
};
|
|
2561
|
-
const renew = async () => {
|
|
2562
|
-
const r = await run(() => auth.account.mfa.recoveryCodes({ password }),
|
|
2724
|
+
const renew = async (key) => {
|
|
2725
|
+
const r = await run(() => auth.account.mfa.recoveryCodes({ password }), key);
|
|
2563
2726
|
if (!r.ok) return;
|
|
2727
|
+
setPassword("");
|
|
2728
|
+
setAsking(null);
|
|
2564
2729
|
setCodes(r.recoveryCodes);
|
|
2565
2730
|
props.onSaved?.({ kind: "recovery_codes.regenerated" });
|
|
2566
2731
|
};
|
|
2732
|
+
const press = (what) => {
|
|
2733
|
+
f.setError(null);
|
|
2734
|
+
if (!account.hasPassword) return void (what === "off" ? turnOff(what) : renew(what));
|
|
2735
|
+
setPassword("");
|
|
2736
|
+
setCodes(null);
|
|
2737
|
+
setAsking(what);
|
|
2738
|
+
};
|
|
2739
|
+
const cancel = () => {
|
|
2740
|
+
setPassword("");
|
|
2741
|
+
f.setError(null);
|
|
2742
|
+
setAsking(null);
|
|
2743
|
+
};
|
|
2567
2744
|
const passwordField = account.hasPassword && /* @__PURE__ */ jsx(Field, { f, name: "password", type: "password", label: f.t.currentPassword, value: password, autoComplete: "current-password", required: true, onChange: setPassword });
|
|
2568
|
-
const shown = codes && /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
2569
|
-
/* @__PURE__ */ jsx(Note, { f, children: f.t.keepCodes }),
|
|
2570
|
-
/* @__PURE__ */ jsx("ul", { className: f.cx("codes"), children: codes.map((c) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("code", { children: c }) }, c)) })
|
|
2571
|
-
] });
|
|
2572
2745
|
if (setup) {
|
|
2573
2746
|
return /* @__PURE__ */ jsxs(Wrap, { f, as: "form", slot: "section", section: "secondStep", onSubmit: confirm, noValidate: true, children: [
|
|
2574
2747
|
/* @__PURE__ */ jsx(Heading, { f, children: f.t.secondStep }),
|
|
@@ -2580,14 +2753,36 @@ function SecondStepPart({ props, account, onChanged }) {
|
|
|
2580
2753
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", variant: "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.verify })
|
|
2581
2754
|
] });
|
|
2582
2755
|
}
|
|
2583
|
-
|
|
2756
|
+
if (!account.mfaEnabled) {
|
|
2757
|
+
return /* @__PURE__ */ jsxs(Wrap, { f, as: "form", slot: "section", section: "secondStep", onSubmit: start, noValidate: true, children: [
|
|
2758
|
+
/* @__PURE__ */ jsx(Heading, { f, children: f.t.secondStep }),
|
|
2759
|
+
/* @__PURE__ */ jsx(Note, { f, children: f.t.secondStepOff }),
|
|
2760
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
2761
|
+
passwordField,
|
|
2762
|
+
/* @__PURE__ */ jsx(f.Button, { type: "submit", variant: "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.turnOn })
|
|
2763
|
+
] });
|
|
2764
|
+
}
|
|
2765
|
+
if (asking) {
|
|
2766
|
+
const submit = (e) => {
|
|
2767
|
+
e.preventDefault();
|
|
2768
|
+
void (asking === "off" ? turnOff(SUBMIT) : renew(SUBMIT));
|
|
2769
|
+
};
|
|
2770
|
+
return /* @__PURE__ */ jsxs(Wrap, { f, as: "form", slot: "section", section: "secondStep", onSubmit: submit, noValidate: true, children: [
|
|
2771
|
+
/* @__PURE__ */ jsx(Heading, { f, children: f.t.secondStep }),
|
|
2772
|
+
/* @__PURE__ */ jsx(Note, { f, children: f.t.secondStepOn }),
|
|
2773
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
2774
|
+
passwordField,
|
|
2775
|
+
/* @__PURE__ */ 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 }),
|
|
2776
|
+
/* @__PURE__ */ jsx(Cancel, { f, onClick: cancel })
|
|
2777
|
+
] });
|
|
2778
|
+
}
|
|
2779
|
+
return /* @__PURE__ */ jsxs(Wrap, { f, as: "div", slot: "section", section: "secondStep", children: [
|
|
2584
2780
|
/* @__PURE__ */ jsx(Heading, { f, children: f.t.secondStep }),
|
|
2585
|
-
/* @__PURE__ */ jsx(Note, { f, children:
|
|
2586
|
-
|
|
2781
|
+
/* @__PURE__ */ jsx(Note, { f, children: f.t.secondStepOn }),
|
|
2782
|
+
codes && /* @__PURE__ */ jsx(RecoveryCodes, { f, codes }),
|
|
2587
2783
|
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
2588
|
-
|
|
2589
|
-
/* @__PURE__ */ jsx(f.Button, { type: "
|
|
2590
|
-
account.mfaEnabled && /* @__PURE__ */ 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 })
|
|
2784
|
+
/* @__PURE__ */ 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 }),
|
|
2785
|
+
/* @__PURE__ */ 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 })
|
|
2591
2786
|
] });
|
|
2592
2787
|
}
|
|
2593
2788
|
function PhonePart({ props, account, onChanged }) {
|
|
@@ -2600,6 +2795,7 @@ function PhonePart({ props, account, onChanged }) {
|
|
|
2600
2795
|
const [code, setCode] = useState("");
|
|
2601
2796
|
const [sentTo, setSentTo] = useState("");
|
|
2602
2797
|
const [codes, setCodes] = useState(null);
|
|
2798
|
+
const [removing, setRemoving] = useState(false);
|
|
2603
2799
|
const load = () => auth.account.mfa.factors().then((w) => {
|
|
2604
2800
|
setWays(w);
|
|
2605
2801
|
if (w && w.phoneChannels.length > 0 && !w.phoneChannels.includes(channel)) setChannel(w.phoneChannels[0]);
|
|
@@ -2620,21 +2816,34 @@ function PhonePart({ props, account, onChanged }) {
|
|
|
2620
2816
|
setSentTo("");
|
|
2621
2817
|
setCode("");
|
|
2622
2818
|
setPassword("");
|
|
2819
|
+
setNumber("");
|
|
2623
2820
|
if (r.recoveryCodes.length > 0) setCodes(r.recoveryCodes);
|
|
2624
2821
|
onChanged(true);
|
|
2625
2822
|
props.onSaved?.({ kind: "phone.added", channel });
|
|
2626
2823
|
await load();
|
|
2627
2824
|
};
|
|
2628
|
-
const remove = async (
|
|
2629
|
-
|
|
2630
|
-
const r = await run(() => auth.account.mfa.removePhone({ password }));
|
|
2825
|
+
const remove = async (key) => {
|
|
2826
|
+
const r = await run(() => auth.account.mfa.removePhone({ password }), key);
|
|
2631
2827
|
if (!r.ok) return;
|
|
2632
2828
|
setPassword("");
|
|
2829
|
+
setRemoving(false);
|
|
2830
|
+
setCodes(null);
|
|
2633
2831
|
await load();
|
|
2634
2832
|
const left = await auth.account.mfa.factors();
|
|
2635
2833
|
onChanged(Boolean(left?.totp));
|
|
2636
2834
|
props.onSaved?.({ kind: "phone.removed" });
|
|
2637
2835
|
};
|
|
2836
|
+
const press = () => {
|
|
2837
|
+
f.setError(null);
|
|
2838
|
+
if (!account.hasPassword) return void remove("remove");
|
|
2839
|
+
setPassword("");
|
|
2840
|
+
setRemoving(true);
|
|
2841
|
+
};
|
|
2842
|
+
const cancel = () => {
|
|
2843
|
+
setPassword("");
|
|
2844
|
+
f.setError(null);
|
|
2845
|
+
setRemoving(false);
|
|
2846
|
+
};
|
|
2638
2847
|
const passwordField = account.hasPassword && /* @__PURE__ */ jsx(Field, { f, name: "password", type: "password", label: f.t.currentPassword, value: password, autoComplete: "current-password", required: true, onChange: setPassword });
|
|
2639
2848
|
if (sentTo) {
|
|
2640
2849
|
return /* @__PURE__ */ jsxs(Wrap, { f, as: "form", slot: "section", section: "phone", onSubmit: confirm, noValidate: true, children: [
|
|
@@ -2645,23 +2854,46 @@ function PhonePart({ props, account, onChanged }) {
|
|
|
2645
2854
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", variant: "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.verify })
|
|
2646
2855
|
] });
|
|
2647
2856
|
}
|
|
2648
|
-
|
|
2857
|
+
if (ways.phone) {
|
|
2858
|
+
const by = ways.phone.channel === "whatsapp" ? f.t.byWhatsapp : ways.phone.channel === "sms" ? f.t.bySms : "";
|
|
2859
|
+
const on = /* @__PURE__ */ jsxs(Note, { f, children: [
|
|
2860
|
+
f.t.phoneOn.replace("{to}", ways.phone.number),
|
|
2861
|
+
by && /* @__PURE__ */ jsx(Tag, { f, plain: ` \xB7 ${by}`, children: by })
|
|
2862
|
+
] });
|
|
2863
|
+
if (removing) {
|
|
2864
|
+
return /* @__PURE__ */ jsxs(Wrap, { f, as: "form", slot: "section", section: "phone", onSubmit: (e) => {
|
|
2865
|
+
e.preventDefault();
|
|
2866
|
+
void remove(SUBMIT);
|
|
2867
|
+
}, noValidate: true, children: [
|
|
2868
|
+
/* @__PURE__ */ jsx(Heading, { f, children: f.t.phone }),
|
|
2869
|
+
on,
|
|
2870
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
2871
|
+
passwordField,
|
|
2872
|
+
/* @__PURE__ */ jsx(f.Button, { type: "submit", variant: "danger", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.removePhone }),
|
|
2873
|
+
/* @__PURE__ */ jsx(Cancel, { f, onClick: cancel })
|
|
2874
|
+
] });
|
|
2875
|
+
}
|
|
2876
|
+
return /* @__PURE__ */ jsxs(Wrap, { f, as: "div", slot: "section", section: "phone", children: [
|
|
2877
|
+
/* @__PURE__ */ jsx(Heading, { f, children: f.t.phone }),
|
|
2878
|
+
on,
|
|
2879
|
+
codes && /* @__PURE__ */ jsx(RecoveryCodes, { f, codes }),
|
|
2880
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
2881
|
+
/* @__PURE__ */ jsx(f.Button, { type: "button", variant: "danger", loading: f.loading("remove"), disabled: f.busy, className: f.cx("button"), onClick: press, children: f.t.removePhone })
|
|
2882
|
+
] });
|
|
2883
|
+
}
|
|
2884
|
+
return /* @__PURE__ */ jsxs(Wrap, { f, as: "form", slot: "section", section: "phone", onSubmit: add, noValidate: true, children: [
|
|
2649
2885
|
/* @__PURE__ */ jsx(Heading, { f, children: f.t.phone }),
|
|
2650
|
-
/* @__PURE__ */ jsx(Note, { f, children:
|
|
2651
|
-
codes && /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
2652
|
-
/* @__PURE__ */ jsx(Note, { f, children: f.t.keepCodes }),
|
|
2653
|
-
/* @__PURE__ */ jsx("ul", { className: f.cx("codes"), children: codes.map((c) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("code", { children: c }) }, c)) })
|
|
2654
|
-
] }),
|
|
2886
|
+
/* @__PURE__ */ jsx(Note, { f, children: `${f.t.phoneOff} ${f.t.phoneHelp}` }),
|
|
2655
2887
|
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2888
|
+
/* @__PURE__ */ jsx(Field, { f, name: "phone", type: "tel", label: f.t.phone, value: number, autoComplete: "tel", required: true, onChange: setNumber }),
|
|
2889
|
+
ways.phoneChannels.length > 1 && f.C.Select && /* @__PURE__ */ jsx(ChannelPick, { f, value: channel, channels: ways.phoneChannels, onChange: setChannel }),
|
|
2890
|
+
ways.phoneChannels.length > 1 && !f.C.Select && /* @__PURE__ */ jsx("div", { className: f.cx("field"), role: "radiogroup", children: ways.phoneChannels.map((c) => /* @__PURE__ */ jsxs("label", { className: f.cx("label"), children: [
|
|
2659
2891
|
/* @__PURE__ */ jsx("input", { type: "radio", name: "channel", value: c, checked: channel === c, disabled: f.busy, onChange: () => setChannel(c) }),
|
|
2660
2892
|
" ",
|
|
2661
2893
|
c === "whatsapp" ? f.t.byWhatsapp : f.t.bySms
|
|
2662
2894
|
] }, c)) }),
|
|
2663
2895
|
passwordField,
|
|
2664
|
-
/* @__PURE__ */ jsx(f.Button, { type: "submit", variant:
|
|
2896
|
+
/* @__PURE__ */ jsx(f.Button, { type: "submit", variant: "primary", loading: f.loading(), disabled: f.busy, className: f.cx("button"), children: f.t.addPhone })
|
|
2665
2897
|
] });
|
|
2666
2898
|
}
|
|
2667
2899
|
function AgentsPart({ props, when }) {
|