cauthy-auth 0.30.0 → 0.32.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 +50 -5
- package/dist/{cauthy-BXgsZ-Um.d.mts → cauthy-2jtP2LVQ.d.mts} +1 -1
- package/dist/{cauthy-CHENs452.d.ts → cauthy-CKfvvv_i.d.ts} +1 -1
- package/dist/cli.js +8 -5
- package/dist/client.d.mts +47 -6
- package/dist/client.d.ts +47 -6
- package/dist/client.js +16 -2
- package/dist/client.js.map +1 -1
- package/dist/client.mjs +16 -2
- package/dist/client.mjs.map +1 -1
- package/dist/express.d.mts +2 -2
- package/dist/express.d.ts +2 -2
- package/dist/fastify.d.mts +2 -2
- package/dist/fastify.d.ts +2 -2
- package/dist/hono.d.mts +2 -2
- package/dist/hono.d.ts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +64 -21
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +64 -21
- package/dist/index.mjs.map +1 -1
- package/dist/next.d.mts +2 -2
- package/dist/next.d.ts +2 -2
- package/dist/react.d.mts +339 -31
- package/dist/react.d.ts +339 -31
- package/dist/react.js +616 -225
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +610 -230
- package/dist/react.mjs.map +1 -1
- package/dist/styles.css +8 -0
- package/dist/svelte.d.mts +2 -2
- package/dist/svelte.d.ts +2 -2
- package/dist/svelte.js +16 -2
- package/dist/svelte.js.map +1 -1
- package/dist/svelte.mjs +16 -2
- package/dist/svelte.mjs.map +1 -1
- package/dist/{system-0mHrdAgO.d.mts → system-BrrJsrFW.d.mts} +14 -0
- package/dist/{system-BIYbS7h2.d.ts → system-BvvoNs2y.d.ts} +14 -0
- package/dist/vue.d.mts +2 -2
- package/dist/vue.d.ts +2 -2
- package/dist/vue.js +16 -2
- package/dist/vue.js.map +1 -1
- package/dist/vue.mjs +16 -2
- package/dist/vue.mjs.map +1 -1
- package/package.json +2 -1
package/dist/react.mjs
CHANGED
|
@@ -373,11 +373,11 @@ function createAuthClient(options = {}) {
|
|
|
373
373
|
if (res.ok) {
|
|
374
374
|
const m = await res.json();
|
|
375
375
|
if (m.password) policy = passwordPolicyOf(m.password);
|
|
376
|
-
return { providers: [], signUp: true, magicLink: false, passkey: false, ...m, ...policy ? { password: policy } : {}, passkeyHere: m.passkeyHere === true, passkeyOnCauthy: m.passkeyOnCauthy ?? m.passkey === true, sso: m.sso === true };
|
|
376
|
+
return { providers: [], signUp: true, magicLink: false, passkey: false, ...m, ...policy ? { password: policy } : {}, passwordSignIn: m.passwordSignIn !== false, passkeyHere: m.passkeyHere === true, passkeyOnCauthy: m.passkeyOnCauthy ?? m.passkey === true, sso: m.sso === true };
|
|
377
377
|
}
|
|
378
378
|
} catch {
|
|
379
379
|
}
|
|
380
|
-
return { providers: [], signUp: true, magicLink: false, passkey: false, passkeyHere: false, passkeyOnCauthy: false, sso: false };
|
|
380
|
+
return { providers: [], signUp: true, passwordSignIn: true, magicLink: false, passkey: false, passkeyHere: false, passkeyOnCauthy: false, sso: false };
|
|
381
381
|
}
|
|
382
382
|
async function ceremony(begin, finish, form, run, more = {}) {
|
|
383
383
|
const begun = await post(begin, form, null);
|
|
@@ -524,6 +524,20 @@ function createAuthClient(options = {}) {
|
|
|
524
524
|
forgotPassword: (f) => post("/forgot-password", { email: f.email }, checkEmail(f.email), f.captchaToken),
|
|
525
525
|
resetPassword: (f) => post("/reset-password", { token: f.token, password: f.password }, checkNewPassword(f.password, policy)),
|
|
526
526
|
verifyEmail: (f) => post("/verify-email", { token: f.token }, null),
|
|
527
|
+
async invitation(token) {
|
|
528
|
+
const bad = { ok: false, error: { code: "invalid_token", message: "This invitation is not valid, or it has expired." } };
|
|
529
|
+
if (typeof token !== "string" || token.trim() === "") return bad;
|
|
530
|
+
try {
|
|
531
|
+
const res = await doFetch(`${base}/invitation?token=${encodeURIComponent(token.trim())}`, { credentials: "same-origin", headers: { accept: "application/json" } });
|
|
532
|
+
const body = await res.json().catch(() => null);
|
|
533
|
+
if (res.ok && body?.invitation) return { ok: true, status: "ok", invitation: body.invitation };
|
|
534
|
+
const e = body?.error;
|
|
535
|
+
return { ok: false, error: e && typeof e.code === "string" ? { code: e.code, message: String(e.message ?? "") } : UNAVAILABLE };
|
|
536
|
+
} catch {
|
|
537
|
+
return { ok: false, error: UNAVAILABLE };
|
|
538
|
+
}
|
|
539
|
+
},
|
|
540
|
+
acceptInvitation: (token, password) => post("/invitation/accept", { token, password }, checkNewPassword(password, policy)),
|
|
527
541
|
signOut: () => post("/sign-out", {}, null),
|
|
528
542
|
organizations: {
|
|
529
543
|
async list(system) {
|
|
@@ -707,8 +721,8 @@ function definePolicy(given) {
|
|
|
707
721
|
}
|
|
708
722
|
|
|
709
723
|
// src/components.tsx
|
|
710
|
-
import { useEffect, useId, useRef, useState } from "react";
|
|
711
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
724
|
+
import { Fragment, useEffect, useId, useRef, useState } from "react";
|
|
725
|
+
import { Fragment as Fragment2, jsx, jsxs } from "react/jsx-runtime";
|
|
712
726
|
var TEXTS = {
|
|
713
727
|
en: {
|
|
714
728
|
email: "Email",
|
|
@@ -749,6 +763,7 @@ var TEXTS = {
|
|
|
749
763
|
removePhone: "Remove phone",
|
|
750
764
|
bySms: "SMS",
|
|
751
765
|
byWhatsapp: "WhatsApp",
|
|
766
|
+
channel: "Send codes by",
|
|
752
767
|
checkEmail: "Almost there: open the link we sent to confirm your address \u2014 it signs you in.",
|
|
753
768
|
backToSignIn: "Back to sign in",
|
|
754
769
|
emailMeALink: "Email me a sign-in link",
|
|
@@ -760,6 +775,13 @@ var TEXTS = {
|
|
|
760
775
|
passwordChanged: "Your password was changed. You can sign in with it now.",
|
|
761
776
|
confirming: "Confirming your address\u2026",
|
|
762
777
|
emailConfirmed: "Your address is confirmed. You can sign in now.",
|
|
778
|
+
invitedTo: "You've been invited to {workspace}",
|
|
779
|
+
invitedToOrganization: "You've been invited to {organization} on {workspace}",
|
|
780
|
+
invitedAs: "You will sign in as {email}.",
|
|
781
|
+
choosePassword: "Choose a password",
|
|
782
|
+
acceptInvite: "Accept and sign in",
|
|
783
|
+
openingInvitation: "Opening your invitation\u2026",
|
|
784
|
+
invitationInvalid: "This invitation is not valid: it was already used, or it has expired. Ask whoever invited you to send it again.",
|
|
763
785
|
profile: "Profile",
|
|
764
786
|
save: "Save",
|
|
765
787
|
saved: "Saved.",
|
|
@@ -831,6 +853,9 @@ var TEXTS = {
|
|
|
831
853
|
organizationDeleted: "{org} was deleted.",
|
|
832
854
|
yes: "Yes",
|
|
833
855
|
cancel: "Cancel",
|
|
856
|
+
termsChanged: "Our terms changed",
|
|
857
|
+
termsChangedHelp: "To go on, read and accept",
|
|
858
|
+
acceptTerms: "Accept",
|
|
834
859
|
errors: {
|
|
835
860
|
not_allowed: "Your role in this organization does not allow that.",
|
|
836
861
|
last_manager: "Somebody else must manage the members first: give that role to another member.",
|
|
@@ -874,7 +899,9 @@ var TEXTS = {
|
|
|
874
899
|
invalid_assertion: "Your company's answer could not be checked. Try again.",
|
|
875
900
|
provisioning_disabled: "Your company's sign-in worked, but this workspace has no account for you. Ask its admin to add you.",
|
|
876
901
|
connection_inactive: "Your company's sign-in is turned off for this workspace.",
|
|
877
|
-
invalid_grant: "That sign-in expired. Try again."
|
|
902
|
+
invalid_grant: "That sign-in expired. Try again.",
|
|
903
|
+
password_disabled: "This workspace does not sign in with a password. Use one of the other ways.",
|
|
904
|
+
passkeys_disabled: "Passkeys are turned off for this workspace."
|
|
878
905
|
}
|
|
879
906
|
},
|
|
880
907
|
es: {
|
|
@@ -916,6 +943,7 @@ var TEXTS = {
|
|
|
916
943
|
removePhone: "Quitar tel\xE9fono",
|
|
917
944
|
bySms: "SMS",
|
|
918
945
|
byWhatsapp: "WhatsApp",
|
|
946
|
+
channel: "Enviar los c\xF3digos por",
|
|
919
947
|
checkEmail: "Casi listo: abre el enlace que te enviamos para confirmar tu correo; te deja adentro.",
|
|
920
948
|
backToSignIn: "Volver a entrar",
|
|
921
949
|
emailMeALink: "Env\xEDame un enlace para entrar",
|
|
@@ -927,6 +955,13 @@ var TEXTS = {
|
|
|
927
955
|
passwordChanged: "Tu contrase\xF1a se cambi\xF3. Ya puedes entrar con ella.",
|
|
928
956
|
confirming: "Confirmando tu correo\u2026",
|
|
929
957
|
emailConfirmed: "Tu correo qued\xF3 confirmado. Ya puedes entrar.",
|
|
958
|
+
invitedTo: "Te invitaron a {workspace}",
|
|
959
|
+
invitedToOrganization: "Te invitaron a {organization} en {workspace}",
|
|
960
|
+
invitedAs: "Vas a entrar como {email}.",
|
|
961
|
+
choosePassword: "Elige una contrase\xF1a",
|
|
962
|
+
acceptInvite: "Aceptar y entrar",
|
|
963
|
+
openingInvitation: "Abriendo tu invitaci\xF3n\u2026",
|
|
964
|
+
invitationInvalid: "Esta invitaci\xF3n no es v\xE1lida: ya se us\xF3 o venci\xF3. P\xEDdele a quien te invit\xF3 que te la env\xEDe de nuevo.",
|
|
930
965
|
profile: "Perfil",
|
|
931
966
|
save: "Guardar",
|
|
932
967
|
saved: "Guardado.",
|
|
@@ -998,6 +1033,9 @@ var TEXTS = {
|
|
|
998
1033
|
organizationDeleted: "{org} qued\xF3 eliminada.",
|
|
999
1034
|
yes: "S\xED",
|
|
1000
1035
|
cancel: "Cancelar",
|
|
1036
|
+
termsChanged: "Nuestros t\xE9rminos cambiaron",
|
|
1037
|
+
termsChangedHelp: "Para seguir, lee y acepta",
|
|
1038
|
+
acceptTerms: "Aceptar",
|
|
1001
1039
|
errors: {
|
|
1002
1040
|
not_allowed: "Tu rol en esta organizaci\xF3n no permite eso.",
|
|
1003
1041
|
last_manager: "Primero alguien m\xE1s debe administrar los miembros: dale ese rol a otro miembro.",
|
|
@@ -1041,7 +1079,9 @@ var TEXTS = {
|
|
|
1041
1079
|
invalid_assertion: "No se pudo verificar la respuesta de tu empresa. Intenta de nuevo.",
|
|
1042
1080
|
provisioning_disabled: "El ingreso con tu empresa funcion\xF3, pero este workspace no tiene una cuenta para ti. P\xEDdele a su admin que te agregue.",
|
|
1043
1081
|
connection_inactive: "El inicio de sesi\xF3n de tu empresa est\xE1 apagado en este workspace.",
|
|
1044
|
-
invalid_grant: "Ese ingreso venci\xF3. Intenta de nuevo."
|
|
1082
|
+
invalid_grant: "Ese ingreso venci\xF3. Intenta de nuevo.",
|
|
1083
|
+
password_disabled: "En este workspace no se entra con contrase\xF1a. Usa una de las otras formas.",
|
|
1084
|
+
passkeys_disabled: "Las llaves de acceso est\xE1n desactivadas en este workspace."
|
|
1045
1085
|
}
|
|
1046
1086
|
}
|
|
1047
1087
|
};
|
|
@@ -1156,8 +1196,10 @@ function sameOrigin(to) {
|
|
|
1156
1196
|
function useForm(props) {
|
|
1157
1197
|
const t = { ...TEXTS[props.locale ?? "en"], ...props.texts, errors: { ...TEXTS[props.locale ?? "en"].errors, ...props.texts?.errors } };
|
|
1158
1198
|
const cx = (slot) => props.classNames?.[slot] ?? `cauthy-${slot}`;
|
|
1159
|
-
const
|
|
1160
|
-
const
|
|
1199
|
+
const own = (slot) => props.classNames?.[slot];
|
|
1200
|
+
const C = props.components ?? {};
|
|
1201
|
+
const Button = C.Button ?? PlainButton;
|
|
1202
|
+
const Input = C.Input ?? PlainInput;
|
|
1161
1203
|
const [error, setError] = useState(null);
|
|
1162
1204
|
const [busy, setBusy] = useState(false);
|
|
1163
1205
|
const [policy, setPolicy] = useState(void 0);
|
|
@@ -1172,7 +1214,81 @@ function useForm(props) {
|
|
|
1172
1214
|
else window.location.assign(sitePath(to) ?? sameOrigin(props.returnTo) ?? "/");
|
|
1173
1215
|
};
|
|
1174
1216
|
const root = useRoot(props);
|
|
1175
|
-
return { t, cx, Button, Input, error, setError, busy, setBusy, say, done, root, policy, setPolicy, passwordRule };
|
|
1217
|
+
return { t, cx, own, C, Button, Input, error, setError, busy, setBusy, say, done, root, policy, setPolicy, passwordRule };
|
|
1218
|
+
}
|
|
1219
|
+
function Note({ f, children, footer }) {
|
|
1220
|
+
const { Text } = f.C;
|
|
1221
|
+
if (Text) return /* @__PURE__ */ jsx(Text, { as: "p", tone: "muted", size: footer ? "sm" : "md", children });
|
|
1222
|
+
return /* @__PURE__ */ jsx("p", { className: f.cx(footer ? "footer" : "notice"), children });
|
|
1223
|
+
}
|
|
1224
|
+
function Heading({ f, children }) {
|
|
1225
|
+
const { Text } = f.C;
|
|
1226
|
+
if (Text) return /* @__PURE__ */ jsx(Text, { as: "h2", size: "lg", children });
|
|
1227
|
+
return /* @__PURE__ */ jsx("h2", { className: f.cx("heading"), children });
|
|
1228
|
+
}
|
|
1229
|
+
function Say({ f, tone, children }) {
|
|
1230
|
+
const { Alert } = f.C;
|
|
1231
|
+
if (Alert) return /* @__PURE__ */ jsx(Alert, { tone, children });
|
|
1232
|
+
if (tone === "danger") return /* @__PURE__ */ jsx("p", { role: "alert", className: f.cx("error"), children });
|
|
1233
|
+
return /* @__PURE__ */ jsx("p", { role: "status", className: f.cx("notice"), children });
|
|
1234
|
+
}
|
|
1235
|
+
function Or({ f, children }) {
|
|
1236
|
+
const { Divider } = f.C;
|
|
1237
|
+
if (Divider) return /* @__PURE__ */ jsx(Divider, { label: children });
|
|
1238
|
+
return /* @__PURE__ */ jsx("p", { className: f.cx("separator"), children });
|
|
1239
|
+
}
|
|
1240
|
+
function A({ f, href, newTab, children }) {
|
|
1241
|
+
const { Link } = f.C;
|
|
1242
|
+
if (Link) return /* @__PURE__ */ jsx(Link, { href, newTab, children });
|
|
1243
|
+
return /* @__PURE__ */ jsx("a", { className: f.cx("link"), href, target: newTab ? "_blank" : void 0, rel: newTab ? "noopener" : void 0, children });
|
|
1244
|
+
}
|
|
1245
|
+
function Tag({ f, tone, children, plain }) {
|
|
1246
|
+
const { Badge } = f.C;
|
|
1247
|
+
if (Badge) return /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
1248
|
+
" ",
|
|
1249
|
+
/* @__PURE__ */ jsx(Badge, { tone, children })
|
|
1250
|
+
] });
|
|
1251
|
+
return /* @__PURE__ */ jsx(Fragment2, { children: plain });
|
|
1252
|
+
}
|
|
1253
|
+
function Check(p) {
|
|
1254
|
+
const id = useId();
|
|
1255
|
+
const { f } = p;
|
|
1256
|
+
const { Checkbox } = f.C;
|
|
1257
|
+
if (Checkbox) {
|
|
1258
|
+
return /* @__PURE__ */ jsx(Checkbox, { id, name: p.name, checked: p.checked, required: p.required, className: f.own("check"), onChange: p.onChange, children: p.children });
|
|
1259
|
+
}
|
|
1260
|
+
return /* @__PURE__ */ jsxs("label", { className: f.cx("check"), children: [
|
|
1261
|
+
/* @__PURE__ */ jsx("input", { type: "checkbox", name: p.name, checked: p.checked, required: p.required, onChange: (e) => p.onChange(e.target.checked) }),
|
|
1262
|
+
/* @__PURE__ */ jsx("span", { children: p.children })
|
|
1263
|
+
] });
|
|
1264
|
+
}
|
|
1265
|
+
function Pick(p) {
|
|
1266
|
+
const made = useId();
|
|
1267
|
+
const id = p.id ?? made;
|
|
1268
|
+
const { f } = p;
|
|
1269
|
+
const { Select } = f.C;
|
|
1270
|
+
if (Select) {
|
|
1271
|
+
return /* @__PURE__ */ jsx(Select, { id, name: p.name, value: p.value, options: p.options, disabled: p.disabled, "aria-label": p.label, className: f.own("input"), onChange: p.onChange });
|
|
1272
|
+
}
|
|
1273
|
+
return /* @__PURE__ */ jsx("select", { id, name: p.name, "aria-label": p.label, className: f.cx("input"), value: p.value, disabled: p.disabled, onChange: (e) => p.onChange(e.target.value), children: p.options.map((o) => /* @__PURE__ */ jsx("option", { value: o.value, children: o.label }, o.value)) });
|
|
1274
|
+
}
|
|
1275
|
+
function Labelled({ f, id, label, children }) {
|
|
1276
|
+
const { Field: OwnField } = f.C;
|
|
1277
|
+
if (OwnField) return /* @__PURE__ */ jsx(OwnField, { id, label, className: f.own("field"), children });
|
|
1278
|
+
return /* @__PURE__ */ jsxs("label", { className: f.cx("field"), children: [
|
|
1279
|
+
/* @__PURE__ */ jsx("span", { className: f.cx("label"), children: label }),
|
|
1280
|
+
children
|
|
1281
|
+
] });
|
|
1282
|
+
}
|
|
1283
|
+
function Documents({ f, documents }) {
|
|
1284
|
+
return /* @__PURE__ */ jsx(Fragment2, { children: documents.map((d, i) => /* @__PURE__ */ jsxs("span", { children: [
|
|
1285
|
+
i > 0 && /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
1286
|
+
f.t.and,
|
|
1287
|
+
" "
|
|
1288
|
+
] }),
|
|
1289
|
+
/* @__PURE__ */ jsx(A, { f, href: d.url, newTab: true, children: d.kind === "terms" ? f.t.termsOfService : f.t.privacyPolicy }),
|
|
1290
|
+
" "
|
|
1291
|
+
] }, d.kind)) });
|
|
1176
1292
|
}
|
|
1177
1293
|
var PASSWORD_RULES = ["needs_lowercase", "needs_uppercase", "needs_digit", "needs_symbol", "needs_classes", "breached"];
|
|
1178
1294
|
function isPasswordRule(e) {
|
|
@@ -1190,26 +1306,43 @@ function Field(p) {
|
|
|
1190
1306
|
const { f } = p;
|
|
1191
1307
|
const bad = f.error?.field === p.name ? f.error : null;
|
|
1192
1308
|
const described = [bad ? `${id}-error` : "", p.hint ? `${id}-hint` : ""].filter(Boolean).join(" ");
|
|
1309
|
+
const input = /* @__PURE__ */ jsx(
|
|
1310
|
+
f.Input,
|
|
1311
|
+
{
|
|
1312
|
+
id,
|
|
1313
|
+
name: p.name,
|
|
1314
|
+
type: p.type,
|
|
1315
|
+
value: p.value,
|
|
1316
|
+
autoComplete: p.autoComplete,
|
|
1317
|
+
required: p.required,
|
|
1318
|
+
className: f.cx("input"),
|
|
1319
|
+
"aria-invalid": bad ? true : void 0,
|
|
1320
|
+
"aria-describedby": described || void 0,
|
|
1321
|
+
onChange: (e) => p.onChange(e.target.value)
|
|
1322
|
+
}
|
|
1323
|
+
);
|
|
1324
|
+
const { Field: OwnField } = f.C;
|
|
1325
|
+
if (OwnField) {
|
|
1326
|
+
return /* @__PURE__ */ jsx(
|
|
1327
|
+
OwnField,
|
|
1328
|
+
{
|
|
1329
|
+
id,
|
|
1330
|
+
label: p.label,
|
|
1331
|
+
aside: p.aside,
|
|
1332
|
+
help: p.hint && !bad ? p.hint : void 0,
|
|
1333
|
+
error: bad ? f.say(bad) : void 0,
|
|
1334
|
+
required: p.required,
|
|
1335
|
+
className: f.own("field"),
|
|
1336
|
+
children: input
|
|
1337
|
+
}
|
|
1338
|
+
);
|
|
1339
|
+
}
|
|
1193
1340
|
return /* @__PURE__ */ jsxs("div", { className: f.cx("field"), children: [
|
|
1194
1341
|
/* @__PURE__ */ jsxs("label", { className: f.cx("label"), htmlFor: id, children: [
|
|
1195
1342
|
p.label,
|
|
1196
1343
|
p.aside
|
|
1197
1344
|
] }),
|
|
1198
|
-
|
|
1199
|
-
f.Input,
|
|
1200
|
-
{
|
|
1201
|
-
id,
|
|
1202
|
-
name: p.name,
|
|
1203
|
-
type: p.type,
|
|
1204
|
-
value: p.value,
|
|
1205
|
-
autoComplete: p.autoComplete,
|
|
1206
|
-
required: p.required,
|
|
1207
|
-
className: f.cx("input"),
|
|
1208
|
-
"aria-invalid": bad ? true : void 0,
|
|
1209
|
-
"aria-describedby": described || void 0,
|
|
1210
|
-
onChange: (e) => p.onChange(e.target.value)
|
|
1211
|
-
}
|
|
1212
|
-
),
|
|
1345
|
+
input,
|
|
1213
1346
|
p.hint && !bad && /* @__PURE__ */ jsx("span", { id: `${id}-hint`, className: f.cx("hint"), children: p.hint }),
|
|
1214
1347
|
bad && /* @__PURE__ */ jsx("span", { id: `${id}-error`, role: "alert", className: f.cx("fieldError"), children: f.say(bad) })
|
|
1215
1348
|
] });
|
|
@@ -1236,23 +1369,16 @@ function useMailedToken(name, open) {
|
|
|
1236
1369
|
open(takeToken(name));
|
|
1237
1370
|
}, []);
|
|
1238
1371
|
}
|
|
1239
|
-
function
|
|
1240
|
-
const auth =
|
|
1241
|
-
const f = useForm(props);
|
|
1242
|
-
const [methods, setMethods] = useState(null);
|
|
1243
|
-
const [email, setEmail] = useState("");
|
|
1244
|
-
const [password, setPassword] = useState("");
|
|
1372
|
+
function SecondStepForm(p) {
|
|
1373
|
+
const { f, auth } = p;
|
|
1245
1374
|
const [code, setCode] = useState("");
|
|
1246
|
-
const [step, setStep] = useState("password");
|
|
1247
|
-
const challenge = useChallenge(methods?.captchaSiteKey, props.locale);
|
|
1248
1375
|
const [phoneWay, setPhoneWay] = useState(null);
|
|
1249
1376
|
const [phoneSent, setPhoneSent] = useState("");
|
|
1250
1377
|
useEffect(() => {
|
|
1251
|
-
if (step !== "code") return;
|
|
1252
1378
|
void auth.signIn.mfaMethods().then((r) => {
|
|
1253
1379
|
if (r.ok) setPhoneWay({ totp: r.totp, phone: r.phone, push: r.push, email: r.email });
|
|
1254
1380
|
});
|
|
1255
|
-
}, [
|
|
1381
|
+
}, []);
|
|
1256
1382
|
const sendEmail = async () => {
|
|
1257
1383
|
f.setBusy(true);
|
|
1258
1384
|
f.setError(null);
|
|
@@ -1288,6 +1414,62 @@ function SignIn(props) {
|
|
|
1288
1414
|
if (!r.ok) return f.setError(r.error);
|
|
1289
1415
|
setPhoneSent(r.sentTo);
|
|
1290
1416
|
};
|
|
1417
|
+
const submit = async (e) => {
|
|
1418
|
+
e.preventDefault();
|
|
1419
|
+
f.setBusy(true);
|
|
1420
|
+
f.setError(null);
|
|
1421
|
+
const r = await auth.signIn.mfa({ code });
|
|
1422
|
+
f.setBusy(false);
|
|
1423
|
+
if (!r.ok) return f.setError(r.error);
|
|
1424
|
+
f.done();
|
|
1425
|
+
};
|
|
1426
|
+
const general = f.error && !f.error.field ? f.error : null;
|
|
1427
|
+
const to = phoneWay?.phone?.number ?? "";
|
|
1428
|
+
return /* @__PURE__ */ jsxs("form", { className: f.cx("form"), ...f.root, onSubmit: submit, noValidate: true, children: [
|
|
1429
|
+
/* @__PURE__ */ jsx(Note, { f, children: phoneSent ? f.t.codeSent.replace("{to}", phoneSent) : phoneWay?.email ? f.t.codeHelpEmail.replace("{to}", phoneWay.email.to) : phoneWay?.phone && !phoneWay.totp ? f.t.codeHelpPhone : f.t.codeHelp }),
|
|
1430
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
1431
|
+
phoneWay?.email && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void sendEmail(), children: f.t.sendEmailAgain }),
|
|
1432
|
+
pushNumber > 0 ? f.C.Text ? (
|
|
1433
|
+
// The application's text: the number to pick drawn large, by its own rules.
|
|
1434
|
+
/* @__PURE__ */ jsxs("div", { role: "status", "aria-live": "polite", children: [
|
|
1435
|
+
/* @__PURE__ */ jsx(f.C.Text, { as: "p", children: f.t.pushPick.replace("{n}", String(pushNumber)) }),
|
|
1436
|
+
/* @__PURE__ */ jsx(f.C.Text, { as: "p", size: "lg", children: pushNumber }),
|
|
1437
|
+
/* @__PURE__ */ jsx(f.C.Text, { as: "p", tone: "muted", children: f.t.pushWaiting })
|
|
1438
|
+
] })
|
|
1439
|
+
) : /* @__PURE__ */ jsxs("div", { className: f.cx("notice"), role: "status", "aria-live": "polite", children: [
|
|
1440
|
+
/* @__PURE__ */ jsx("p", { children: f.t.pushPick.replace("{n}", String(pushNumber)) }),
|
|
1441
|
+
/* @__PURE__ */ jsx("p", { style: { fontSize: 48, fontWeight: 700, margin: "4px 0", textAlign: "center" }, children: pushNumber }),
|
|
1442
|
+
/* @__PURE__ */ jsx("p", { children: f.t.pushWaiting })
|
|
1443
|
+
] }) : phoneWay?.push && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("button"), onClick: () => void sendPush(), children: f.t.pushSend }),
|
|
1444
|
+
phoneWay?.phone && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void sendCode(), children: (phoneWay.phone.channel === "whatsapp" ? f.t.sendCodeWhatsapp : f.t.sendCodeSms).replace("{to}", to) }),
|
|
1445
|
+
/* @__PURE__ */ jsx(Field, { f, name: "code", type: "text", label: f.t.code, value: code, autoComplete: "one-time-code", required: true, onChange: setCode }),
|
|
1446
|
+
/* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.verify })
|
|
1447
|
+
] });
|
|
1448
|
+
}
|
|
1449
|
+
function ProviderButtons(p) {
|
|
1450
|
+
const { f } = p;
|
|
1451
|
+
return /* @__PURE__ */ jsx(Fragment2, { children: p.providers.map((provider) => /* @__PURE__ */ jsxs(f.Button, { type: "button", className: f.cx("providerButton"), onClick: () => p.onPick(provider.id), children: [
|
|
1452
|
+
provider.iconUrl && /* @__PURE__ */ jsx("img", { src: provider.iconUrl, alt: "", width: 18, height: 18, className: f.cx("providerIcon") }),
|
|
1453
|
+
f.t.continueWith,
|
|
1454
|
+
" ",
|
|
1455
|
+
provider.name
|
|
1456
|
+
] }, provider.id)) });
|
|
1457
|
+
}
|
|
1458
|
+
function signInOffers(methods) {
|
|
1459
|
+
const password = methods?.passwordSignIn !== false;
|
|
1460
|
+
return { password, email: password || methods?.magicLink === true || methods?.sso === true, passkey: methods?.passkey === true };
|
|
1461
|
+
}
|
|
1462
|
+
function SignIn(props) {
|
|
1463
|
+
const auth = useAuth();
|
|
1464
|
+
const f = useForm(props);
|
|
1465
|
+
const [methods, setMethods] = useState(null);
|
|
1466
|
+
const [email, setEmail] = useState("");
|
|
1467
|
+
const [password, setPassword] = useState("");
|
|
1468
|
+
const [code, setCode] = useState("");
|
|
1469
|
+
const [step, setStep] = useState("password");
|
|
1470
|
+
const challenge = useChallenge(methods?.captchaSiteKey, props.locale);
|
|
1471
|
+
const offers = signInOffers(methods);
|
|
1472
|
+
const passwordOn = offers.password;
|
|
1291
1473
|
const autofill = useRef(null);
|
|
1292
1474
|
const [offer, setOffer] = useState(0);
|
|
1293
1475
|
const [company, setCompany] = useState(null);
|
|
@@ -1339,10 +1521,18 @@ function SignIn(props) {
|
|
|
1339
1521
|
const submit = async (e) => {
|
|
1340
1522
|
e.preventDefault();
|
|
1341
1523
|
autofill.current?.abort();
|
|
1524
|
+
if (step === "password" && company?.enforced) {
|
|
1525
|
+
f.setError(null);
|
|
1526
|
+
return toCompany();
|
|
1527
|
+
}
|
|
1528
|
+
if (step === "password" && !passwordOn) {
|
|
1529
|
+
if (company) return toCompany();
|
|
1530
|
+
if (methods?.magicLink) return sendLink();
|
|
1531
|
+
return;
|
|
1532
|
+
}
|
|
1342
1533
|
f.setBusy(true);
|
|
1343
1534
|
f.setError(null);
|
|
1344
|
-
|
|
1345
|
-
const r = step === "code" ? await auth.signIn.mfa({ code }) : step === "sent" ? await auth.signIn.emailCode({ code }) : await auth.signIn.email({ email, password, captchaToken: challenge.token });
|
|
1535
|
+
const r = step === "sent" ? await auth.signIn.emailCode({ code }) : await auth.signIn.email({ email, password, captchaToken: challenge.token });
|
|
1346
1536
|
f.setBusy(false);
|
|
1347
1537
|
if (step === "password") challenge.renew();
|
|
1348
1538
|
if (!r.ok && r.error.code === "sso_required") return toCompany();
|
|
@@ -1376,49 +1566,31 @@ function SignIn(props) {
|
|
|
1376
1566
|
setStep("sent");
|
|
1377
1567
|
};
|
|
1378
1568
|
const general = f.error && !f.error.field ? f.error : null;
|
|
1569
|
+
const asksEmail = offers.email;
|
|
1379
1570
|
if (step === "opening") return /* @__PURE__ */ jsx("div", { className: f.cx("form"), ...f.root, "aria-busy": "true" });
|
|
1380
1571
|
if (step === "sent") {
|
|
1381
1572
|
return /* @__PURE__ */ jsxs("form", { className: f.cx("form"), ...f.root, onSubmit: submit, noValidate: true, children: [
|
|
1382
|
-
/* @__PURE__ */ jsx(
|
|
1383
|
-
general && /* @__PURE__ */ jsx(
|
|
1384
|
-
/* @__PURE__ */ jsx(
|
|
1385
|
-
/* @__PURE__ */ jsx(Field, { f, name: "code", type: "text", label: f.t.code, value: code, autoComplete: "one-time-code", required: true, onChange: setCode }),
|
|
1386
|
-
/* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.verify })
|
|
1387
|
-
] });
|
|
1388
|
-
}
|
|
1389
|
-
if (step === "code") {
|
|
1390
|
-
const to = phoneWay?.phone?.number ?? "";
|
|
1391
|
-
return /* @__PURE__ */ jsxs("form", { className: f.cx("form"), ...f.root, onSubmit: submit, noValidate: true, children: [
|
|
1392
|
-
/* @__PURE__ */ jsx("p", { className: f.cx("notice"), children: phoneSent ? f.t.codeSent.replace("{to}", phoneSent) : phoneWay?.email ? f.t.codeHelpEmail.replace("{to}", phoneWay.email.to) : phoneWay?.phone && !phoneWay.totp ? f.t.codeHelpPhone : f.t.codeHelp }),
|
|
1393
|
-
general && /* @__PURE__ */ jsx("p", { role: "alert", className: f.cx("error"), children: f.say(general) }),
|
|
1394
|
-
phoneWay?.email && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void sendEmail(), children: f.t.sendEmailAgain }),
|
|
1395
|
-
pushNumber > 0 ? /* @__PURE__ */ jsxs("div", { className: f.cx("notice"), role: "status", "aria-live": "polite", children: [
|
|
1396
|
-
/* @__PURE__ */ jsx("p", { children: f.t.pushPick.replace("{n}", String(pushNumber)) }),
|
|
1397
|
-
/* @__PURE__ */ jsx("p", { style: { fontSize: 48, fontWeight: 700, margin: "4px 0", textAlign: "center" }, children: pushNumber }),
|
|
1398
|
-
/* @__PURE__ */ jsx("p", { children: f.t.pushWaiting })
|
|
1399
|
-
] }) : phoneWay?.push && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("button"), onClick: () => void sendPush(), children: f.t.pushSend }),
|
|
1400
|
-
phoneWay?.phone && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void sendCode(), children: (phoneWay.phone.channel === "whatsapp" ? f.t.sendCodeWhatsapp : f.t.sendCodeSms).replace("{to}", to) }),
|
|
1573
|
+
/* @__PURE__ */ jsx(Note, { f, children: f.t.signInLinkSent }),
|
|
1574
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
1575
|
+
/* @__PURE__ */ jsx(Note, { f, children: f.t.codeFromMail }),
|
|
1401
1576
|
/* @__PURE__ */ jsx(Field, { f, name: "code", type: "text", label: f.t.code, value: code, autoComplete: "one-time-code", required: true, onChange: setCode }),
|
|
1402
1577
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.verify })
|
|
1403
1578
|
] });
|
|
1404
1579
|
}
|
|
1580
|
+
if (step === "code") return /* @__PURE__ */ jsx(SecondStepForm, { f, auth });
|
|
1405
1581
|
return /* @__PURE__ */ jsxs("form", { className: f.cx("form"), ...f.root, onSubmit: submit, noValidate: true, children: [
|
|
1406
|
-
general && /* @__PURE__ */ jsx(
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
] }, p.id)),
|
|
1412
|
-
methods?.passkey && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void usePasskey(), children: f.t.usePasskey }),
|
|
1413
|
-
((methods?.providers.length ?? 0) > 0 || methods?.passkey) && /* @__PURE__ */ jsx("p", { className: f.cx("separator"), children: f.t.orWithEmail }),
|
|
1414
|
-
/* @__PURE__ */ jsx(Field, { f, name: "email", type: "email", label: f.t.email, value: email, autoComplete: methods?.passkeyHere ? "username webauthn" : "username", required: true, onChange: setEmail }),
|
|
1582
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
1583
|
+
/* @__PURE__ */ jsx(ProviderButtons, { f, providers: methods?.providers ?? [], onPick: (id) => auth.signIn.social(id, { returnTo: props.returnTo }) }),
|
|
1584
|
+
offers.passkey && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void usePasskey(), children: f.t.usePasskey }),
|
|
1585
|
+
asksEmail && ((methods?.providers.length ?? 0) > 0 || offers.passkey) && /* @__PURE__ */ jsx(Or, { f, children: f.t.orWithEmail }),
|
|
1586
|
+
asksEmail && /* @__PURE__ */ jsx(Field, { f, name: "email", type: "email", label: f.t.email, value: email, autoComplete: methods?.passkeyHere ? "username webauthn" : "username", required: true, onChange: setEmail }),
|
|
1415
1587
|
company && /* @__PURE__ */ jsxs(f.Button, { type: "button", disabled: f.busy, className: f.cx(company.enforced ? "button" : "providerButton"), onClick: toCompany, children: [
|
|
1416
1588
|
f.t.continueWith,
|
|
1417
1589
|
" ",
|
|
1418
1590
|
company.name
|
|
1419
1591
|
] }),
|
|
1420
|
-
company?.enforced && /* @__PURE__ */ jsx(
|
|
1421
|
-
!company?.enforced && /* @__PURE__ */ jsxs(
|
|
1592
|
+
company?.enforced && /* @__PURE__ */ jsx(Note, { f, children: f.t.ssoOnly }),
|
|
1593
|
+
!company?.enforced && passwordOn && /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
1422
1594
|
/* @__PURE__ */ jsx(
|
|
1423
1595
|
Field,
|
|
1424
1596
|
{
|
|
@@ -1430,17 +1602,18 @@ function SignIn(props) {
|
|
|
1430
1602
|
autoComplete: "current-password",
|
|
1431
1603
|
required: true,
|
|
1432
1604
|
onChange: setPassword,
|
|
1433
|
-
aside: props.links?.forgotPassword ? /* @__PURE__ */ jsx(
|
|
1605
|
+
aside: props.links?.forgotPassword ? /* @__PURE__ */ jsx(A, { f, href: props.links.forgotPassword, children: f.t.forgotPassword }) : void 0
|
|
1434
1606
|
}
|
|
1435
1607
|
),
|
|
1436
1608
|
challenge.node,
|
|
1437
1609
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.signIn })
|
|
1438
1610
|
] }),
|
|
1611
|
+
!company?.enforced && !passwordOn && methods?.magicLink && challenge.node,
|
|
1439
1612
|
methods?.magicLink && !company?.enforced && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void sendLink(), children: f.t.emailMeALink }),
|
|
1440
|
-
methods?.signUp !== false && props.links?.signUp && /* @__PURE__ */ jsxs(
|
|
1613
|
+
methods?.signUp !== false && props.links?.signUp && /* @__PURE__ */ jsxs(Note, { f, footer: true, children: [
|
|
1441
1614
|
f.t.noAccount,
|
|
1442
1615
|
" ",
|
|
1443
|
-
/* @__PURE__ */ jsx(
|
|
1616
|
+
/* @__PURE__ */ jsx(A, { f, href: props.links.signUp, children: f.t.createAccount })
|
|
1444
1617
|
] })
|
|
1445
1618
|
] });
|
|
1446
1619
|
}
|
|
@@ -1495,44 +1668,43 @@ function SignUp(props) {
|
|
|
1495
1668
|
f.done();
|
|
1496
1669
|
};
|
|
1497
1670
|
const general = f.error && !f.error.field ? f.error : null;
|
|
1671
|
+
const passwordOn = methods?.passwordSignIn !== false;
|
|
1672
|
+
const providers = auth.session?.user.isAnonymous === true || methods?.organization?.required ? [] : methods?.providers ?? [];
|
|
1498
1673
|
if (sent) {
|
|
1499
1674
|
return /* @__PURE__ */ jsxs("div", { className: f.cx("form"), ...f.root, children: [
|
|
1500
|
-
/* @__PURE__ */ jsx(
|
|
1501
|
-
props.links?.signIn && /* @__PURE__ */ jsx(
|
|
1675
|
+
/* @__PURE__ */ jsx(Note, { f, children: f.t.checkEmail }),
|
|
1676
|
+
props.links?.signIn && /* @__PURE__ */ jsx(A, { f, href: props.links.signIn, children: f.t.backToSignIn })
|
|
1677
|
+
] });
|
|
1678
|
+
}
|
|
1679
|
+
const footer = props.links?.signIn && /* @__PURE__ */ jsxs(Note, { f, footer: true, children: [
|
|
1680
|
+
f.t.haveAccount,
|
|
1681
|
+
" ",
|
|
1682
|
+
/* @__PURE__ */ jsx(A, { f, href: props.links.signIn, children: f.t.signIn })
|
|
1683
|
+
] });
|
|
1684
|
+
if (!passwordOn) {
|
|
1685
|
+
return /* @__PURE__ */ jsxs("div", { className: f.cx("form"), ...f.root, children: [
|
|
1686
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
1687
|
+
/* @__PURE__ */ jsx(ProviderButtons, { f, providers, onPick: (id) => auth.signIn.social(id, { returnTo: props.returnTo }) }),
|
|
1688
|
+
footer
|
|
1502
1689
|
] });
|
|
1503
1690
|
}
|
|
1504
1691
|
return /* @__PURE__ */ jsxs("form", { className: f.cx("form"), ...f.root, onSubmit: submit, noValidate: true, children: [
|
|
1505
|
-
general && /* @__PURE__ */ jsx(
|
|
1692
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
1693
|
+
/* @__PURE__ */ jsx(ProviderButtons, { f, providers, onPick: (id) => auth.signIn.social(id, { returnTo: props.returnTo }) }),
|
|
1694
|
+
providers.length > 0 && /* @__PURE__ */ jsx(Or, { f, children: f.t.orWithEmail }),
|
|
1506
1695
|
methods?.organization?.ask && /* @__PURE__ */ jsx(Field, { f, name: "organization", type: "text", label: f.t.company, value: organization, autoComplete: "organization", required: methods.organization.required, onChange: setOrganization }),
|
|
1507
1696
|
/* @__PURE__ */ jsx(Field, { f, name: "name", type: "text", label: f.t.name, value: name, autoComplete: "name", onChange: setName }),
|
|
1508
1697
|
/* @__PURE__ */ jsx(Field, { f, name: "email", type: "email", label: f.t.email, value: email, autoComplete: "username", required: true, onChange: setEmail }),
|
|
1509
1698
|
/* @__PURE__ */ jsx(Field, { f, name: "password", type: "password", label: f.t.password, value: password, autoComplete: "new-password", required: true, onChange: setPassword, hint: f.passwordRule }),
|
|
1510
|
-
legal && legal.documents.length > 0 && /* @__PURE__ */ jsxs(
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
" ",
|
|
1515
|
-
legal.documents.map((d, i) => /* @__PURE__ */ jsxs("span", { children: [
|
|
1516
|
-
i > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1517
|
-
f.t.and,
|
|
1518
|
-
" "
|
|
1519
|
-
] }),
|
|
1520
|
-
/* @__PURE__ */ jsx("a", { className: f.cx("link"), href: d.url, target: "_blank", rel: "noopener", children: d.kind === "terms" ? f.t.termsOfService : f.t.privacyPolicy }),
|
|
1521
|
-
" "
|
|
1522
|
-
] }, d.kind))
|
|
1523
|
-
] })
|
|
1699
|
+
legal && legal.documents.length > 0 && /* @__PURE__ */ jsxs(Check, { f, name: "acceptLegal", checked: acceptLegal, required: true, onChange: setAcceptLegal, children: [
|
|
1700
|
+
f.t.iAccept,
|
|
1701
|
+
" ",
|
|
1702
|
+
/* @__PURE__ */ jsx(Documents, { f, documents: legal.documents })
|
|
1524
1703
|
] }),
|
|
1525
|
-
legal?.consentPurposes.map((p) => /* @__PURE__ */
|
|
1526
|
-
/* @__PURE__ */ jsx("input", { type: "checkbox", name: `consent_${p.key}`, checked: consents[p.key] === true, required: p.required, onChange: (e) => setConsents({ ...consents, [p.key]: e.target.checked }) }),
|
|
1527
|
-
/* @__PURE__ */ jsx("span", { children: p.label })
|
|
1528
|
-
] }, p.key)),
|
|
1704
|
+
legal?.consentPurposes.map((p) => /* @__PURE__ */ jsx(Check, { f, name: `consent_${p.key}`, checked: consents[p.key] === true, required: p.required, onChange: (on) => setConsents({ ...consents, [p.key]: on }), children: p.label }, p.key)),
|
|
1529
1705
|
challenge.node,
|
|
1530
1706
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.signUp }),
|
|
1531
|
-
|
|
1532
|
-
f.t.haveAccount,
|
|
1533
|
-
" ",
|
|
1534
|
-
/* @__PURE__ */ jsx("a", { className: f.cx("link"), href: props.links.signIn, children: f.t.signIn })
|
|
1535
|
-
] })
|
|
1707
|
+
footer
|
|
1536
1708
|
] });
|
|
1537
1709
|
}
|
|
1538
1710
|
function ForgotPassword(props) {
|
|
@@ -1554,16 +1726,16 @@ function ForgotPassword(props) {
|
|
|
1554
1726
|
const general = f.error && !f.error.field ? f.error : null;
|
|
1555
1727
|
if (sent) {
|
|
1556
1728
|
return /* @__PURE__ */ jsxs("div", { className: f.cx("form"), ...f.root, children: [
|
|
1557
|
-
/* @__PURE__ */ jsx(
|
|
1558
|
-
props.links?.signIn && /* @__PURE__ */ jsx(
|
|
1729
|
+
/* @__PURE__ */ jsx(Note, { f, children: f.t.linkSent }),
|
|
1730
|
+
props.links?.signIn && /* @__PURE__ */ jsx(A, { f, href: props.links.signIn, children: f.t.backToSignIn })
|
|
1559
1731
|
] });
|
|
1560
1732
|
}
|
|
1561
1733
|
return /* @__PURE__ */ jsxs("form", { className: f.cx("form"), ...f.root, onSubmit: submit, noValidate: true, children: [
|
|
1562
|
-
general && /* @__PURE__ */ jsx(
|
|
1734
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
1563
1735
|
/* @__PURE__ */ jsx(Field, { f, name: "email", type: "email", label: f.t.email, value: email, autoComplete: "username", required: true, onChange: setEmail }),
|
|
1564
1736
|
challenge.node,
|
|
1565
1737
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.sendLink }),
|
|
1566
|
-
props.links?.signIn && /* @__PURE__ */ jsx(
|
|
1738
|
+
props.links?.signIn && /* @__PURE__ */ jsx(Note, { f, footer: true, children: /* @__PURE__ */ jsx(A, { f, href: props.links.signIn, children: f.t.backToSignIn }) })
|
|
1567
1739
|
] });
|
|
1568
1740
|
}
|
|
1569
1741
|
function ResetPassword(props) {
|
|
@@ -1587,21 +1759,21 @@ function ResetPassword(props) {
|
|
|
1587
1759
|
setChanged(true);
|
|
1588
1760
|
};
|
|
1589
1761
|
const general = f.error && !f.error.field ? f.error : null;
|
|
1590
|
-
const back = props.links?.signIn && /* @__PURE__ */ jsx(
|
|
1762
|
+
const back = props.links?.signIn && /* @__PURE__ */ jsx(A, { f, href: props.links.signIn, children: f.t.backToSignIn });
|
|
1591
1763
|
if (changed) {
|
|
1592
1764
|
return /* @__PURE__ */ jsxs("div", { className: f.cx("form"), ...f.root, children: [
|
|
1593
|
-
/* @__PURE__ */ jsx(
|
|
1765
|
+
/* @__PURE__ */ jsx(Note, { f, children: f.t.passwordChanged }),
|
|
1594
1766
|
back
|
|
1595
1767
|
] });
|
|
1596
1768
|
}
|
|
1597
1769
|
if (token === "") {
|
|
1598
1770
|
return /* @__PURE__ */ jsxs("div", { className: f.cx("form"), ...f.root, children: [
|
|
1599
|
-
general && /* @__PURE__ */ jsx(
|
|
1600
|
-
props.links?.forgotPassword && /* @__PURE__ */ jsx(
|
|
1771
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
1772
|
+
props.links?.forgotPassword && /* @__PURE__ */ jsx(A, { f, href: props.links.forgotPassword, children: f.t.forgotPassword })
|
|
1601
1773
|
] });
|
|
1602
1774
|
}
|
|
1603
1775
|
return /* @__PURE__ */ jsxs("form", { className: f.cx("form"), ...f.root, onSubmit: submit, noValidate: true, children: [
|
|
1604
|
-
general && /* @__PURE__ */ jsx(
|
|
1776
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
1605
1777
|
/* @__PURE__ */ jsx(Field, { f, name: "password", type: "password", label: f.t.newPassword, value: password, autoComplete: "new-password", required: true, onChange: setPassword, hint: f.passwordRule }),
|
|
1606
1778
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy || token === null, className: f.cx("button"), children: f.t.savePassword })
|
|
1607
1779
|
] });
|
|
@@ -1623,12 +1795,98 @@ function VerifyEmail(props) {
|
|
|
1623
1795
|
});
|
|
1624
1796
|
});
|
|
1625
1797
|
return /* @__PURE__ */ jsxs("div", { className: f.cx("form"), ...f.root, "aria-busy": state === "confirming", children: [
|
|
1626
|
-
state === "confirming" && /* @__PURE__ */ jsx(
|
|
1627
|
-
state === "confirmed" && /* @__PURE__ */ jsx(
|
|
1628
|
-
state === "failed" && f.error && /* @__PURE__ */ jsx(
|
|
1629
|
-
state !== "confirming" && props.links?.signIn && /* @__PURE__ */ jsx(
|
|
1798
|
+
state === "confirming" && /* @__PURE__ */ jsx(Note, { f, children: f.t.confirming }),
|
|
1799
|
+
state === "confirmed" && /* @__PURE__ */ jsx(Note, { f, children: f.t.emailConfirmed }),
|
|
1800
|
+
state === "failed" && f.error && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(f.error) }),
|
|
1801
|
+
state !== "confirming" && props.links?.signIn && /* @__PURE__ */ jsx(A, { f, href: props.links.signIn, children: f.t.backToSignIn })
|
|
1630
1802
|
] });
|
|
1631
1803
|
}
|
|
1804
|
+
function AcceptInvite(props) {
|
|
1805
|
+
const auth = useAuth();
|
|
1806
|
+
const f = useForm(props);
|
|
1807
|
+
const [token, setToken] = useState("");
|
|
1808
|
+
const [invitation, setInvitation] = useState(null);
|
|
1809
|
+
const [state, setState] = useState("opening");
|
|
1810
|
+
const [password, setPassword] = useState("");
|
|
1811
|
+
usePasswordPolicy(f, useMethods(auth));
|
|
1812
|
+
useMailedToken("token", (t) => {
|
|
1813
|
+
if (!t) return setState("invalid");
|
|
1814
|
+
setToken(t);
|
|
1815
|
+
void auth.invitation(t).then((r) => {
|
|
1816
|
+
if (r.ok) {
|
|
1817
|
+
setInvitation(r.invitation);
|
|
1818
|
+
return setState("ready");
|
|
1819
|
+
}
|
|
1820
|
+
if (r.error.code !== "invalid_token") f.setError(r.error);
|
|
1821
|
+
setState("invalid");
|
|
1822
|
+
});
|
|
1823
|
+
});
|
|
1824
|
+
const submit = async (e) => {
|
|
1825
|
+
e.preventDefault();
|
|
1826
|
+
f.setBusy(true);
|
|
1827
|
+
f.setError(null);
|
|
1828
|
+
const r = await auth.acceptInvitation(token, password);
|
|
1829
|
+
f.setBusy(false);
|
|
1830
|
+
if (!r.ok) {
|
|
1831
|
+
if (r.error.code === "invalid_token") return setState("invalid");
|
|
1832
|
+
return f.setError(r.error);
|
|
1833
|
+
}
|
|
1834
|
+
props.onSaved?.({ kind: "invitation.accepted", email: invitation?.email ?? "", ...invitation?.organization ? { organization: invitation.organization } : {} });
|
|
1835
|
+
if (r.status === "mfa_required") return setState("code");
|
|
1836
|
+
f.done();
|
|
1837
|
+
};
|
|
1838
|
+
const general = f.error && !f.error.field ? f.error : null;
|
|
1839
|
+
const back = props.links?.signIn && /* @__PURE__ */ jsx(A, { f, href: props.links.signIn, children: f.t.backToSignIn });
|
|
1840
|
+
if (state === "opening") {
|
|
1841
|
+
return /* @__PURE__ */ jsx("div", { className: f.cx("form"), ...f.root, "aria-busy": "true", children: /* @__PURE__ */ jsx(Note, { f, children: f.t.openingInvitation }) });
|
|
1842
|
+
}
|
|
1843
|
+
if (state === "invalid") {
|
|
1844
|
+
return /* @__PURE__ */ jsxs("div", { className: f.cx("form"), ...f.root, children: [
|
|
1845
|
+
/* @__PURE__ */ jsx(Say, { f, tone: "danger", children: general ? f.say(general) : f.t.invitationInvalid }),
|
|
1846
|
+
back
|
|
1847
|
+
] });
|
|
1848
|
+
}
|
|
1849
|
+
if (state === "code") return /* @__PURE__ */ jsx(SecondStepForm, { f, auth });
|
|
1850
|
+
const workspace = invitation?.workspace ?? "";
|
|
1851
|
+
const heading = invitation?.organization ? f.t.invitedToOrganization.replace("{organization}", invitation.organization).replace("{workspace}", workspace) : f.t.invitedTo.replace("{workspace}", workspace);
|
|
1852
|
+
return /* @__PURE__ */ jsxs("form", { className: f.cx("form"), ...f.root, onSubmit: submit, noValidate: true, children: [
|
|
1853
|
+
/* @__PURE__ */ jsx(Heading, { f, children: heading }),
|
|
1854
|
+
/* @__PURE__ */ jsx(Note, { f, children: f.t.invitedAs.replace("{email}", invitation?.email ?? "") }),
|
|
1855
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
1856
|
+
/* @__PURE__ */ jsx("input", { type: "email", name: "username", autoComplete: "username", value: invitation?.email ?? "", readOnly: true, hidden: true }),
|
|
1857
|
+
/* @__PURE__ */ jsx(Field, { f, name: "password", type: "password", label: f.t.choosePassword, value: password, autoComplete: "new-password", required: true, onChange: setPassword, hint: f.passwordRule }),
|
|
1858
|
+
/* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.acceptInvite })
|
|
1859
|
+
] });
|
|
1860
|
+
}
|
|
1861
|
+
function PendingTerms(props) {
|
|
1862
|
+
const auth = useAuth();
|
|
1863
|
+
const f = useForm(props);
|
|
1864
|
+
const [owed, setOwed] = useState(null);
|
|
1865
|
+
useEffect(() => {
|
|
1866
|
+
void auth.account.legal().then((r) => setOwed(r.ok ? r.pending : []));
|
|
1867
|
+
}, []);
|
|
1868
|
+
if (!owed || owed.length === 0) return null;
|
|
1869
|
+
const accept = async () => {
|
|
1870
|
+
f.setBusy(true);
|
|
1871
|
+
f.setError(null);
|
|
1872
|
+
const r = await auth.account.acceptLegal({ kinds: owed.map((d) => d.kind) });
|
|
1873
|
+
f.setBusy(false);
|
|
1874
|
+
if (!r.ok) return f.setError(r.error);
|
|
1875
|
+
setOwed([]);
|
|
1876
|
+
props.onSuccess?.();
|
|
1877
|
+
};
|
|
1878
|
+
return /* @__PURE__ */ jsxs("div", { className: f.cx("form"), ...f.root, children: [
|
|
1879
|
+
/* @__PURE__ */ jsx(Heading, { f, children: f.t.termsChanged }),
|
|
1880
|
+
/* @__PURE__ */ jsxs(Note, { f, children: [
|
|
1881
|
+
f.t.termsChangedHelp,
|
|
1882
|
+
" ",
|
|
1883
|
+
/* @__PURE__ */ jsx(Documents, { f, documents: owed })
|
|
1884
|
+
] }),
|
|
1885
|
+
f.error && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(f.error) }),
|
|
1886
|
+
/* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("button"), onClick: () => void accept(), children: f.t.acceptTerms })
|
|
1887
|
+
] });
|
|
1888
|
+
}
|
|
1889
|
+
var ACCOUNT_SECTIONS = ["profile", "email", "password", "linked", "secondStep", "phone", "passkeys", "agents", "sessions"];
|
|
1632
1890
|
function useSection(props) {
|
|
1633
1891
|
const f = useForm({ ...props, unstyled: true });
|
|
1634
1892
|
const [done, setDone] = useState(null);
|
|
@@ -1647,37 +1905,65 @@ function useSection(props) {
|
|
|
1647
1905
|
function Account(props) {
|
|
1648
1906
|
const auth = useAuth();
|
|
1649
1907
|
const { accountUrl } = useSession();
|
|
1650
|
-
const {
|
|
1908
|
+
const { root } = useForm(props);
|
|
1651
1909
|
const cx = (slot) => props.classNames?.[slot] ?? `cauthy-${slot}`;
|
|
1652
1910
|
const [account, setAccount] = useState(null);
|
|
1653
|
-
const [sessions, setSessions] = useState([]);
|
|
1654
1911
|
useEffect(() => {
|
|
1655
1912
|
void auth.account.get().then(setAccount);
|
|
1656
|
-
void auth.account.sessions().then(setSessions);
|
|
1657
1913
|
}, []);
|
|
1658
1914
|
if (account === null) return /* @__PURE__ */ jsx("div", { className: cx("account"), ...root, "aria-busy": "true" });
|
|
1659
1915
|
const when = props.formatDate ?? ((iso) => new Date(iso).toLocaleString());
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1916
|
+
const mfa = (mfaEnabled) => setAccount({ ...account, mfaEnabled });
|
|
1917
|
+
const part = (section) => {
|
|
1918
|
+
switch (section) {
|
|
1919
|
+
case "profile":
|
|
1920
|
+
return /* @__PURE__ */ jsx(ProfilePart, { props, account, onSaved: setAccount });
|
|
1921
|
+
case "email":
|
|
1922
|
+
return /* @__PURE__ */ jsx(EmailPart, { props, account });
|
|
1923
|
+
case "password":
|
|
1924
|
+
return account.hasPassword ? /* @__PURE__ */ jsx(PasswordPart, { props }) : null;
|
|
1925
|
+
case "linked":
|
|
1926
|
+
return /* @__PURE__ */ jsx(LinkedPart, { props });
|
|
1927
|
+
case "secondStep":
|
|
1928
|
+
return /* @__PURE__ */ jsx(SecondStepPart, { props, account, onChanged: mfa });
|
|
1929
|
+
case "phone":
|
|
1930
|
+
return /* @__PURE__ */ jsx(PhonePart, { props, account, onChanged: mfa });
|
|
1931
|
+
case "passkeys":
|
|
1932
|
+
return /* @__PURE__ */ jsx(PasskeysPart, { props, account, accountUrl: accountUrl(), when });
|
|
1933
|
+
case "agents":
|
|
1934
|
+
return /* @__PURE__ */ jsx(AgentsPart, { props, when });
|
|
1935
|
+
case "sessions":
|
|
1936
|
+
return /* @__PURE__ */ jsx(SessionsPart, { props, when });
|
|
1937
|
+
}
|
|
1938
|
+
};
|
|
1939
|
+
return /* @__PURE__ */ jsx("div", { className: cx("account"), ...root, children: (props.sections ?? ACCOUNT_SECTIONS).map((section) => /* @__PURE__ */ jsx(Fragment, { children: part(section) }, section)) });
|
|
1940
|
+
}
|
|
1941
|
+
function AccountProfile(props) {
|
|
1942
|
+
return /* @__PURE__ */ jsx(Account, { ...props, sections: ["profile"] });
|
|
1943
|
+
}
|
|
1944
|
+
function AccountEmail(props) {
|
|
1945
|
+
return /* @__PURE__ */ jsx(Account, { ...props, sections: ["email"] });
|
|
1946
|
+
}
|
|
1947
|
+
function AccountPassword(props) {
|
|
1948
|
+
return /* @__PURE__ */ jsx(Account, { ...props, sections: ["password"] });
|
|
1949
|
+
}
|
|
1950
|
+
function AccountLinked(props) {
|
|
1951
|
+
return /* @__PURE__ */ jsx(Account, { ...props, sections: ["linked"] });
|
|
1952
|
+
}
|
|
1953
|
+
function AccountSecondStep(props) {
|
|
1954
|
+
return /* @__PURE__ */ jsx(Account, { ...props, sections: ["secondStep"] });
|
|
1955
|
+
}
|
|
1956
|
+
function AccountPhone(props) {
|
|
1957
|
+
return /* @__PURE__ */ jsx(Account, { ...props, sections: ["phone"] });
|
|
1958
|
+
}
|
|
1959
|
+
function AccountPasskeys(props) {
|
|
1960
|
+
return /* @__PURE__ */ jsx(Account, { ...props, sections: ["passkeys"] });
|
|
1961
|
+
}
|
|
1962
|
+
function AccountAgents(props) {
|
|
1963
|
+
return /* @__PURE__ */ jsx(Account, { ...props, sections: ["agents"] });
|
|
1964
|
+
}
|
|
1965
|
+
function AccountSessions(props) {
|
|
1966
|
+
return /* @__PURE__ */ jsx(Account, { ...props, sections: ["sessions"] });
|
|
1681
1967
|
}
|
|
1682
1968
|
var OWNER = "owner";
|
|
1683
1969
|
function memberActions(seat, m) {
|
|
@@ -1689,8 +1975,9 @@ function memberActions(seat, m) {
|
|
|
1689
1975
|
inviteAgain: seat.can.manageMembers && m.invited
|
|
1690
1976
|
};
|
|
1691
1977
|
}
|
|
1692
|
-
function rolesToGive(seat, roles) {
|
|
1693
|
-
|
|
1978
|
+
function rolesToGive(seat, roles, only) {
|
|
1979
|
+
const mine = seat.role === OWNER ? roles : roles.filter((c) => c.role !== OWNER);
|
|
1980
|
+
return only ? mine.filter((c) => only(c.role, c)) : mine;
|
|
1694
1981
|
}
|
|
1695
1982
|
function OrganizationMembers(props) {
|
|
1696
1983
|
const auth = useAuth();
|
|
@@ -1707,6 +1994,8 @@ function OrganizationMembers(props) {
|
|
|
1707
1994
|
const [gone, setGone] = useState(null);
|
|
1708
1995
|
const id = props.organizationId;
|
|
1709
1996
|
const when = props.formatDate ?? ((iso) => new Date(iso).toLocaleDateString());
|
|
1997
|
+
const hidden = (action) => props.hide?.includes(action) === true;
|
|
1998
|
+
const saved = (event) => props.onSaved?.(event);
|
|
1710
1999
|
const load = async () => {
|
|
1711
2000
|
const [list, people, choices] = await Promise.all([auth.organizations.list(), auth.organizations.members(id), auth.organizations.roles(id)]);
|
|
1712
2001
|
const mine = list.find((o) => o.id === id) ?? null;
|
|
@@ -1714,17 +2003,17 @@ function OrganizationMembers(props) {
|
|
|
1714
2003
|
if (mine) setName(mine.name);
|
|
1715
2004
|
setMembers(people);
|
|
1716
2005
|
setRoles(choices ?? []);
|
|
1717
|
-
const offered = mine ? rolesToGive(mine, choices ?? []) : [];
|
|
2006
|
+
const offered = mine ? rolesToGive(mine, choices ?? [], props.roles) : [];
|
|
1718
2007
|
if (offered.length > 0 && !offered.some((c) => c.role === role)) setRole(offered[0].role);
|
|
1719
2008
|
};
|
|
1720
2009
|
useEffect(() => {
|
|
1721
2010
|
void load();
|
|
1722
2011
|
}, [id]);
|
|
1723
|
-
if (gone !== null) return /* @__PURE__ */ jsx("div", { className: f.cx("account"), ...root, children: /* @__PURE__ */ jsx(
|
|
2012
|
+
if (gone !== null) return /* @__PURE__ */ jsx("div", { className: f.cx("account"), ...root, children: /* @__PURE__ */ jsx(Say, { f, tone: "success", children: gone }) });
|
|
1724
2013
|
if (seat === void 0) return /* @__PURE__ */ jsx("div", { className: f.cx("account"), ...root, "aria-busy": "true" });
|
|
1725
|
-
if (seat === null) return /* @__PURE__ */ jsx("div", { className: f.cx("account"), ...root, children: /* @__PURE__ */ jsx(
|
|
2014
|
+
if (seat === null) return /* @__PURE__ */ jsx("div", { className: f.cx("account"), ...root, children: /* @__PURE__ */ jsx(Note, { f, children: f.t.organizationMissing }) });
|
|
1726
2015
|
const manage = seat.can.manageMembers;
|
|
1727
|
-
const giveable = rolesToGive(seat, roles);
|
|
2016
|
+
const giveable = rolesToGive(seat, roles, props.roles);
|
|
1728
2017
|
const label = (r) => roles.find((c) => c.role === r)?.name || r;
|
|
1729
2018
|
const add = async (e) => {
|
|
1730
2019
|
e.preventDefault();
|
|
@@ -1732,22 +2021,28 @@ function OrganizationMembers(props) {
|
|
|
1732
2021
|
if (!r.ok) return;
|
|
1733
2022
|
setEmail("");
|
|
1734
2023
|
setDone(f.t.memberAdded.replace("{email}", r.member.email));
|
|
2024
|
+
saved({ kind: "member.added", organizationId: id, userId: r.member.userId, email: r.member.email, role: r.member.role || role });
|
|
1735
2025
|
await load();
|
|
1736
2026
|
};
|
|
1737
2027
|
const change = async (m, next) => {
|
|
1738
2028
|
const r = await run(() => auth.organizations.setRole(id, m.userId, next));
|
|
1739
|
-
if (r.ok)
|
|
2029
|
+
if (!r.ok) return;
|
|
2030
|
+
saved({ kind: "member.role_changed", organizationId: id, userId: m.userId, role: next, previousRole: m.role });
|
|
2031
|
+
await load();
|
|
1740
2032
|
};
|
|
1741
2033
|
const remove = async (m) => {
|
|
1742
2034
|
setAsking(null);
|
|
1743
2035
|
const r = await run(() => auth.organizations.remove(id, m.userId));
|
|
1744
2036
|
if (!r.ok) return;
|
|
2037
|
+
saved({ kind: m.you ? "member.left" : "member.removed", organizationId: id, userId: m.userId });
|
|
1745
2038
|
if (m.you) setSeat(null);
|
|
1746
2039
|
else await load();
|
|
1747
2040
|
};
|
|
1748
2041
|
const inviteAgain = async (m) => {
|
|
1749
2042
|
const r = await run(() => auth.organizations.inviteAgain(id, m.userId, { locale: props.locale }));
|
|
1750
|
-
if (r.ok)
|
|
2043
|
+
if (!r.ok) return;
|
|
2044
|
+
setDone(f.t.memberInvitationSent);
|
|
2045
|
+
saved({ kind: "member.invited_again", organizationId: id, userId: m.userId });
|
|
1751
2046
|
};
|
|
1752
2047
|
const rename = async (e) => {
|
|
1753
2048
|
e.preventDefault();
|
|
@@ -1756,11 +2051,21 @@ function OrganizationMembers(props) {
|
|
|
1756
2051
|
setSeat(r.organization);
|
|
1757
2052
|
setName(r.organization.name);
|
|
1758
2053
|
setDone(f.t.organizationRenamed.replace("{name}", r.organization.name));
|
|
2054
|
+
saved({ kind: "organization.renamed", organizationId: id, name: r.organization.name });
|
|
1759
2055
|
};
|
|
1760
2056
|
const close = async (how) => {
|
|
1761
2057
|
setAsking(null);
|
|
1762
2058
|
const r = await run(() => how === "archive" ? auth.organizations.archive(id) : auth.organizations.delete(id));
|
|
1763
|
-
if (r.ok)
|
|
2059
|
+
if (!r.ok) return;
|
|
2060
|
+
setGone((how === "archive" ? f.t.organizationArchived : f.t.organizationDeleted).replace("{org}", seat.name));
|
|
2061
|
+
saved({ kind: how === "archive" ? "organization.archived" : "organization.deleted", organizationId: id });
|
|
2062
|
+
};
|
|
2063
|
+
const ask = (key, title, question, yes) => {
|
|
2064
|
+
const { Confirm } = f.C;
|
|
2065
|
+
if (!Confirm) return setAsking(key);
|
|
2066
|
+
void Confirm({ title, body: question, confirmLabel: title, cancelLabel: f.t.cancel, danger: true }).then((ok) => {
|
|
2067
|
+
if (ok) yes();
|
|
2068
|
+
});
|
|
1764
2069
|
};
|
|
1765
2070
|
const confirming = (text2, label2, yes) => /* @__PURE__ */ jsxs("span", { role: "group", "aria-label": label2, children: [
|
|
1766
2071
|
/* @__PURE__ */ jsx("span", { children: text2 }),
|
|
@@ -1768,81 +2073,96 @@ function OrganizationMembers(props) {
|
|
|
1768
2073
|
/* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: yes, children: f.t.yes }),
|
|
1769
2074
|
/* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => setAsking(null), children: f.t.cancel })
|
|
1770
2075
|
] });
|
|
2076
|
+
const leaveQuestion = f.t.memberLeaveConfirm.replace("{org}", seat.name);
|
|
2077
|
+
const archiveQuestion = f.t.organizationArchiveConfirm.replace("{org}", seat.name);
|
|
2078
|
+
const deleteQuestion = f.t.organizationDeleteConfirm.replace("{org}", seat.name);
|
|
2079
|
+
const archiving = seat.can.archive && !hidden("archive");
|
|
2080
|
+
const deleting = seat.can.delete && !hidden("delete");
|
|
2081
|
+
const renaming = seat.can.update && !hidden("rename");
|
|
1771
2082
|
return /* @__PURE__ */ jsxs("div", { className: f.cx("account"), ...root, children: [
|
|
1772
2083
|
/* @__PURE__ */ jsxs("section", { className: f.cx("section"), children: [
|
|
1773
|
-
/* @__PURE__ */ jsxs(
|
|
2084
|
+
/* @__PURE__ */ jsxs(Heading, { f, children: [
|
|
1774
2085
|
f.t.members,
|
|
1775
2086
|
" \xB7 ",
|
|
1776
2087
|
seat.name
|
|
1777
2088
|
] }),
|
|
1778
|
-
problem && /* @__PURE__ */ jsx(
|
|
1779
|
-
members === null ? /* @__PURE__ */ jsxs(
|
|
1780
|
-
/* @__PURE__ */ jsx(
|
|
1781
|
-
auth.session && (asking === auth.session.user.id ? confirming(
|
|
1782
|
-
f.
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
2089
|
+
problem && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(problem) }),
|
|
2090
|
+
members === null ? /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
2091
|
+
/* @__PURE__ */ jsx(Note, { f, children: f.t.membersHidden }),
|
|
2092
|
+
auth.session && !hidden("leave") && (asking === auth.session.user.id ? confirming(leaveQuestion, f.t.memberLeave, () => void remove({ userId: auth.session.user.id, you: true })) : /* @__PURE__ */ jsx(
|
|
2093
|
+
f.Button,
|
|
2094
|
+
{
|
|
2095
|
+
type: "button",
|
|
2096
|
+
disabled: f.busy,
|
|
2097
|
+
className: f.cx("providerButton"),
|
|
2098
|
+
onClick: () => ask(auth.session.user.id, f.t.memberLeave, leaveQuestion, () => void remove({ userId: auth.session.user.id, you: true })),
|
|
2099
|
+
children: f.t.memberLeave
|
|
2100
|
+
}
|
|
2101
|
+
))
|
|
1786
2102
|
] }) : /* @__PURE__ */ jsx("ul", { className: f.cx("sessions"), children: members.map((m) => {
|
|
1787
2103
|
const who = m.name || m.email;
|
|
1788
2104
|
const may = memberActions(seat, m);
|
|
2105
|
+
const removable = may.remove && !(m.you && hidden("leave"));
|
|
2106
|
+
const question = m.you ? leaveQuestion : f.t.memberRemoveConfirm.replace("{who}", who);
|
|
2107
|
+
const action = m.you ? f.t.memberLeave : f.t.memberRemove;
|
|
2108
|
+
const choices = giveable.some((c) => c.role === m.role) ? giveable : [...roles.filter((c) => c.role === m.role), ...giveable];
|
|
1789
2109
|
return /* @__PURE__ */ jsxs("li", { className: f.cx("session"), children: [
|
|
1790
2110
|
/* @__PURE__ */ jsxs("span", { children: [
|
|
1791
2111
|
who,
|
|
1792
2112
|
m.name ? ` \xB7 ${m.email}` : "",
|
|
1793
|
-
m.you
|
|
1794
|
-
|
|
1795
|
-
|
|
2113
|
+
m.you && /* @__PURE__ */ jsx(Tag, { f, plain: ` (${f.t.memberYou})`, children: f.t.memberYou }),
|
|
2114
|
+
f.C.Badge ? /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
2115
|
+
m.invited && /* @__PURE__ */ jsx(Tag, { f, tone: "warning", plain: "", children: f.t.memberInvited }),
|
|
2116
|
+
m.manager && /* @__PURE__ */ jsx(Tag, { f, tone: "success", plain: "", children: f.t.memberManager })
|
|
2117
|
+
] }) : `${m.invited ? ` \xB7 ${f.t.memberInvited}` : ""}${m.manager ? ` \xB7 ${f.t.memberManager}` : ""}`,
|
|
1796
2118
|
" \xB7 ",
|
|
1797
2119
|
when(m.since)
|
|
1798
2120
|
] }),
|
|
1799
2121
|
" ",
|
|
1800
2122
|
may.changeRole && giveable.length > 0 ? /* @__PURE__ */ jsx(
|
|
1801
|
-
|
|
2123
|
+
Pick,
|
|
1802
2124
|
{
|
|
1803
|
-
|
|
1804
|
-
|
|
2125
|
+
f,
|
|
2126
|
+
name: `role_${m.userId}`,
|
|
2127
|
+
label: `${f.t.memberRole}: ${who}`,
|
|
1805
2128
|
value: m.role,
|
|
1806
2129
|
disabled: f.busy,
|
|
1807
|
-
|
|
1808
|
-
|
|
2130
|
+
options: choices.map((c) => ({ value: c.role, label: c.name || c.role })),
|
|
2131
|
+
onChange: (next) => void change(m, next)
|
|
1809
2132
|
}
|
|
1810
|
-
) : /* @__PURE__ */ jsx("span", { children: label(m.role) }),
|
|
2133
|
+
) : f.C.Badge ? /* @__PURE__ */ jsx(f.C.Badge, { tone: "neutral", children: label(m.role) }) : /* @__PURE__ */ jsx("span", { children: label(m.role) }),
|
|
1811
2134
|
" ",
|
|
1812
|
-
asking === m.userId ? confirming(
|
|
1813
|
-
m.you ? f.t.memberLeaveConfirm.replace("{org}", seat.name) : f.t.memberRemoveConfirm.replace("{who}", who),
|
|
1814
|
-
m.you ? f.t.memberLeave : f.t.memberRemove,
|
|
1815
|
-
() => void remove(m)
|
|
1816
|
-
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2135
|
+
asking === m.userId ? confirming(question, action, () => void remove(m)) : /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
1817
2136
|
may.inviteAgain && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void inviteAgain(m), children: f.t.memberInviteAgain }),
|
|
1818
|
-
|
|
2137
|
+
removable && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => ask(m.userId, action, question, () => void remove(m)), children: action })
|
|
1819
2138
|
] })
|
|
1820
2139
|
] }, m.userId);
|
|
1821
2140
|
}) }),
|
|
1822
|
-
done && /* @__PURE__ */ jsx(
|
|
2141
|
+
done && /* @__PURE__ */ jsx(Say, { f, tone: "success", children: done })
|
|
1823
2142
|
] }),
|
|
1824
2143
|
manage && giveable.length > 0 && /* @__PURE__ */ jsxs("form", { className: f.cx("section"), onSubmit: add, noValidate: true, children: [
|
|
1825
|
-
/* @__PURE__ */ jsx(
|
|
2144
|
+
/* @__PURE__ */ jsx(Heading, { f, children: f.t.memberAdd }),
|
|
1826
2145
|
/* @__PURE__ */ jsx(Field, { f, name: "email", type: "email", label: f.t.email, value: email, autoComplete: "off", required: true, onChange: setEmail }),
|
|
1827
|
-
/* @__PURE__ */
|
|
1828
|
-
/* @__PURE__ */ jsx("span", { className: f.cx("label"), children: f.t.memberRole }),
|
|
1829
|
-
/* @__PURE__ */ jsx("select", { name: "role", className: f.cx("input"), value: role, onChange: (e) => setRole(e.target.value), children: giveable.map((c) => /* @__PURE__ */ jsx("option", { value: c.role, children: c.name || c.role }, c.role)) })
|
|
1830
|
-
] }),
|
|
2146
|
+
/* @__PURE__ */ jsx(AddRole, { f, value: role, options: giveable.map((c) => ({ value: c.role, label: c.name || c.role })), onChange: setRole }),
|
|
1831
2147
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.memberAdd })
|
|
1832
2148
|
] }),
|
|
1833
|
-
(
|
|
1834
|
-
/* @__PURE__ */ jsx(
|
|
1835
|
-
|
|
2149
|
+
(renaming || archiving || deleting) && /* @__PURE__ */ jsxs("section", { className: f.cx("section"), children: [
|
|
2150
|
+
/* @__PURE__ */ jsx(Heading, { f, children: f.t.organization }),
|
|
2151
|
+
renaming && /* @__PURE__ */ jsxs("form", { onSubmit: rename, noValidate: true, children: [
|
|
1836
2152
|
/* @__PURE__ */ jsx(Field, { f, name: "name", type: "text", label: f.t.name, value: name, autoComplete: "organization", required: true, onChange: setName }),
|
|
1837
2153
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.organizationRename })
|
|
1838
2154
|
] }),
|
|
1839
|
-
asking === "archive" ? confirming(
|
|
1840
|
-
|
|
1841
|
-
|
|
2155
|
+
asking === "archive" ? confirming(archiveQuestion, f.t.organizationArchive, () => void close("archive")) : asking === "delete" ? confirming(deleteQuestion, f.t.organizationDelete, () => void close("delete")) : /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
2156
|
+
archiving && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => ask("archive", f.t.organizationArchive, archiveQuestion, () => void close("archive")), children: f.t.organizationArchive }),
|
|
2157
|
+
deleting && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => ask("delete", f.t.organizationDelete, deleteQuestion, () => void close("delete")), children: f.t.organizationDelete })
|
|
1842
2158
|
] })
|
|
1843
2159
|
] })
|
|
1844
2160
|
] });
|
|
1845
2161
|
}
|
|
2162
|
+
function AddRole({ f, value, options, onChange }) {
|
|
2163
|
+
const id = useId();
|
|
2164
|
+
return /* @__PURE__ */ jsx(Labelled, { f, id, label: f.t.memberRole, children: /* @__PURE__ */ jsx(Pick, { f, id, name: "role", value, options, onChange }) });
|
|
2165
|
+
}
|
|
1846
2166
|
function PasskeysPart({ props, account, accountUrl, when }) {
|
|
1847
2167
|
const auth = useAuth();
|
|
1848
2168
|
const { f, done, setDone, run, general } = useSection(props);
|
|
@@ -1860,8 +2180,8 @@ function PasskeysPart({ props, account, accountUrl, when }) {
|
|
|
1860
2180
|
if (here === null) return null;
|
|
1861
2181
|
if (!here) {
|
|
1862
2182
|
return /* @__PURE__ */ jsxs("section", { className: f.cx("section"), children: [
|
|
1863
|
-
/* @__PURE__ */ jsx(
|
|
1864
|
-
/* @__PURE__ */ jsx(
|
|
2183
|
+
/* @__PURE__ */ jsx(Heading, { f, children: f.t.passkeys }),
|
|
2184
|
+
/* @__PURE__ */ jsx(A, { f, href: accountUrl, children: f.t.managePasskeys })
|
|
1865
2185
|
] });
|
|
1866
2186
|
}
|
|
1867
2187
|
const add = async (e, kind = "device") => {
|
|
@@ -1875,18 +2195,21 @@ function PasskeysPart({ props, account, accountUrl, when }) {
|
|
|
1875
2195
|
setName("");
|
|
1876
2196
|
setPassword("");
|
|
1877
2197
|
setDone(f.t.passkeyAdded);
|
|
2198
|
+
props.onSaved?.({ kind: "passkey.added", id: r.passkey.id });
|
|
1878
2199
|
};
|
|
1879
2200
|
const remove = async (id) => {
|
|
1880
2201
|
const r = await run(() => auth.account.removePasskey(id));
|
|
1881
|
-
if (r.ok)
|
|
2202
|
+
if (!r.ok) return;
|
|
2203
|
+
setList(list.filter((p) => p.id !== id));
|
|
2204
|
+
props.onSaved?.({ kind: "passkey.removed", id });
|
|
1882
2205
|
};
|
|
1883
2206
|
return /* @__PURE__ */ jsxs("form", { className: f.cx("section"), onSubmit: add, noValidate: true, children: [
|
|
1884
|
-
/* @__PURE__ */ jsx(
|
|
1885
|
-
/* @__PURE__ */ jsx(
|
|
1886
|
-
general && /* @__PURE__ */ jsx(
|
|
1887
|
-
list.length === 0 ? /* @__PURE__ */ jsx(
|
|
2207
|
+
/* @__PURE__ */ jsx(Heading, { f, children: f.t.passkeys }),
|
|
2208
|
+
/* @__PURE__ */ jsx(Note, { f, children: f.t.passkeysHelp }),
|
|
2209
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
2210
|
+
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: [
|
|
1888
2211
|
p.name || f.t.passkeyUnnamed,
|
|
1889
|
-
p.kind !== "unknown"
|
|
2212
|
+
p.kind !== "unknown" && /* @__PURE__ */ jsx(Tag, { f, plain: ` \xB7 ${f.t.passkeyKinds[p.kind]}`, children: f.t.passkeyKinds[p.kind] }),
|
|
1890
2213
|
" \xB7 ",
|
|
1891
2214
|
when(p.createdAt),
|
|
1892
2215
|
" ",
|
|
@@ -1896,7 +2219,7 @@ function PasskeysPart({ props, account, accountUrl, when }) {
|
|
|
1896
2219
|
account.hasPassword && /* @__PURE__ */ jsx(Field, { f, name: "password", type: "password", label: f.t.currentPassword, value: password, autoComplete: "current-password", required: true, onChange: setPassword }),
|
|
1897
2220
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.addPasskeyDevice }),
|
|
1898
2221
|
/* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void add(null, "security_key"), children: f.t.addSecurityKey }),
|
|
1899
|
-
done && /* @__PURE__ */ jsx(
|
|
2222
|
+
done && /* @__PURE__ */ jsx(Say, { f, tone: "success", children: done })
|
|
1900
2223
|
] });
|
|
1901
2224
|
}
|
|
1902
2225
|
function ProfilePart({ props, account, onSaved }) {
|
|
@@ -1909,14 +2232,15 @@ function ProfilePart({ props, account, onSaved }) {
|
|
|
1909
2232
|
if (!r.ok) return;
|
|
1910
2233
|
onSaved(r.account);
|
|
1911
2234
|
setDone(f.t.saved);
|
|
2235
|
+
props.onSaved?.({ kind: "profile.saved", name: r.account.name });
|
|
1912
2236
|
};
|
|
1913
2237
|
return /* @__PURE__ */ jsxs("form", { className: f.cx("section"), onSubmit: submit, noValidate: true, children: [
|
|
1914
|
-
/* @__PURE__ */ jsx(
|
|
1915
|
-
/* @__PURE__ */ jsx(
|
|
1916
|
-
general && /* @__PURE__ */ jsx(
|
|
2238
|
+
/* @__PURE__ */ jsx(Heading, { f, children: f.t.profile }),
|
|
2239
|
+
/* @__PURE__ */ jsx(Note, { f, children: account.email }),
|
|
2240
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
1917
2241
|
/* @__PURE__ */ jsx(Field, { f, name: "name", type: "text", label: f.t.name, value: name, autoComplete: "name", onChange: setName }),
|
|
1918
2242
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.save }),
|
|
1919
|
-
done && /* @__PURE__ */ jsx(
|
|
2243
|
+
done && /* @__PURE__ */ jsx(Say, { f, tone: "success", children: done })
|
|
1920
2244
|
] });
|
|
1921
2245
|
}
|
|
1922
2246
|
function EmailPart({ props, account }) {
|
|
@@ -1930,15 +2254,16 @@ function EmailPart({ props, account }) {
|
|
|
1930
2254
|
if (!r.ok) return;
|
|
1931
2255
|
setPassword("");
|
|
1932
2256
|
setDone(f.t.emailSent.replace("{email}", r.email));
|
|
2257
|
+
props.onSaved?.({ kind: "email.change_requested", email: r.email });
|
|
1933
2258
|
};
|
|
1934
2259
|
return /* @__PURE__ */ jsxs("form", { className: f.cx("section"), onSubmit: submit, noValidate: true, children: [
|
|
1935
|
-
/* @__PURE__ */ jsx(
|
|
1936
|
-
/* @__PURE__ */ jsx(
|
|
1937
|
-
general && /* @__PURE__ */ jsx(
|
|
2260
|
+
/* @__PURE__ */ jsx(Heading, { f, children: f.t.emailAddress }),
|
|
2261
|
+
/* @__PURE__ */ jsx(Note, { f, children: account.email }),
|
|
2262
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
1938
2263
|
/* @__PURE__ */ jsx(Field, { f, name: "email", type: "email", label: f.t.newEmail, value: email, autoComplete: "email", required: true, onChange: setEmail }),
|
|
1939
2264
|
account.hasPassword && /* @__PURE__ */ jsx(Field, { f, name: "password", type: "password", label: f.t.currentPassword, value: password, autoComplete: "current-password", required: true, onChange: setPassword }),
|
|
1940
2265
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.changeEmail }),
|
|
1941
|
-
done && /* @__PURE__ */ jsx(
|
|
2266
|
+
done && /* @__PURE__ */ jsx(Say, { f, tone: "success", children: done })
|
|
1942
2267
|
] });
|
|
1943
2268
|
}
|
|
1944
2269
|
function LinkedPart({ props }) {
|
|
@@ -1951,21 +2276,26 @@ function LinkedPart({ props }) {
|
|
|
1951
2276
|
void auth.account.identities().then(setLinked);
|
|
1952
2277
|
void auth.methods().then((m) => setOffered(m.providers));
|
|
1953
2278
|
const back = typeof window === "undefined" ? null : new URLSearchParams(window.location.search);
|
|
1954
|
-
|
|
1955
|
-
|
|
2279
|
+
const provider = back?.get("linked");
|
|
2280
|
+
if (provider) {
|
|
2281
|
+
setCame(provider);
|
|
2282
|
+
props.onSaved?.({ kind: "identity.linked", provider });
|
|
2283
|
+
} else if (back?.get("auth_error")) f.setError({ code: back.get("auth_error"), message: "That account could not be linked. Try again." });
|
|
1956
2284
|
}, []);
|
|
1957
2285
|
if (linked === null) return null;
|
|
1958
2286
|
const name = (id) => offered.find((p) => p.id === id)?.name ?? id;
|
|
1959
2287
|
const unlink = async (provider) => {
|
|
1960
2288
|
const r = await run(() => auth.account.unlink(provider));
|
|
1961
|
-
if (r.ok)
|
|
2289
|
+
if (!r.ok) return;
|
|
2290
|
+
setLinked(linked.filter((x) => x.provider !== provider));
|
|
2291
|
+
props.onSaved?.({ kind: "identity.unlinked", provider });
|
|
1962
2292
|
};
|
|
1963
2293
|
const here = typeof window === "undefined" ? void 0 : window.location.pathname;
|
|
1964
2294
|
return /* @__PURE__ */ jsxs("section", { className: f.cx("section"), children: [
|
|
1965
|
-
/* @__PURE__ */ jsx(
|
|
1966
|
-
came && /* @__PURE__ */ jsx(
|
|
1967
|
-
general && /* @__PURE__ */ jsx(
|
|
1968
|
-
linked.length === 0 ? /* @__PURE__ */ jsx(
|
|
2295
|
+
/* @__PURE__ */ jsx(Heading, { f, children: f.t.linkedAccounts }),
|
|
2296
|
+
came && /* @__PURE__ */ jsx(Say, { f, tone: "success", children: f.t.linked }),
|
|
2297
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
2298
|
+
linked.length === 0 ? /* @__PURE__ */ jsx(Note, { f, children: f.t.noLinkedAccounts }) : /* @__PURE__ */ jsx("ul", { className: f.cx("sessions"), children: linked.map((x) => /* @__PURE__ */ jsxs("li", { className: f.cx("session"), children: [
|
|
1969
2299
|
name(x.provider),
|
|
1970
2300
|
x.email ? ` \xB7 ${x.email}` : "",
|
|
1971
2301
|
" ",
|
|
@@ -1991,14 +2321,15 @@ function PasswordPart({ props }) {
|
|
|
1991
2321
|
setPassword("");
|
|
1992
2322
|
setNewPassword("");
|
|
1993
2323
|
setDone(f.t.passwordChangedHere);
|
|
2324
|
+
props.onSaved?.({ kind: "password.changed" });
|
|
1994
2325
|
};
|
|
1995
2326
|
return /* @__PURE__ */ jsxs("form", { className: f.cx("section"), onSubmit: submit, noValidate: true, children: [
|
|
1996
|
-
/* @__PURE__ */ jsx(
|
|
1997
|
-
general && /* @__PURE__ */ jsx(
|
|
2327
|
+
/* @__PURE__ */ jsx(Heading, { f, children: f.t.changePassword }),
|
|
2328
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
1998
2329
|
/* @__PURE__ */ jsx(Field, { f, name: "password", type: "password", label: f.t.currentPassword, value: password, autoComplete: "current-password", required: true, onChange: setPassword }),
|
|
1999
2330
|
/* @__PURE__ */ jsx(Field, { f, name: "newPassword", type: "password", label: f.t.newPassword, value: newPassword, autoComplete: "new-password", required: true, onChange: setNewPassword, hint: f.passwordRule }),
|
|
2000
2331
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.changePassword }),
|
|
2001
|
-
done && /* @__PURE__ */ jsx(
|
|
2332
|
+
done && /* @__PURE__ */ jsx(Say, { f, tone: "success", children: done })
|
|
2002
2333
|
] });
|
|
2003
2334
|
}
|
|
2004
2335
|
function SecondStepPart({ props, account, onChanged }) {
|
|
@@ -2022,6 +2353,7 @@ function SecondStepPart({ props, account, onChanged }) {
|
|
|
2022
2353
|
setPassword("");
|
|
2023
2354
|
setCodes(r.recoveryCodes);
|
|
2024
2355
|
onChanged(true);
|
|
2356
|
+
props.onSaved?.({ kind: "mfa.enabled" });
|
|
2025
2357
|
};
|
|
2026
2358
|
const turnOff = async (e) => {
|
|
2027
2359
|
e.preventDefault();
|
|
@@ -2030,32 +2362,35 @@ function SecondStepPart({ props, account, onChanged }) {
|
|
|
2030
2362
|
setPassword("");
|
|
2031
2363
|
setCodes(null);
|
|
2032
2364
|
onChanged(false);
|
|
2365
|
+
props.onSaved?.({ kind: "mfa.disabled" });
|
|
2033
2366
|
};
|
|
2034
2367
|
const renew = async () => {
|
|
2035
2368
|
const r = await run(() => auth.account.mfa.recoveryCodes({ password }));
|
|
2036
|
-
if (r.ok)
|
|
2369
|
+
if (!r.ok) return;
|
|
2370
|
+
setCodes(r.recoveryCodes);
|
|
2371
|
+
props.onSaved?.({ kind: "recovery_codes.regenerated" });
|
|
2037
2372
|
};
|
|
2038
2373
|
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 });
|
|
2039
|
-
const shown = codes && /* @__PURE__ */ jsxs(
|
|
2040
|
-
/* @__PURE__ */ jsx(
|
|
2374
|
+
const shown = codes && /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
2375
|
+
/* @__PURE__ */ jsx(Note, { f, children: f.t.keepCodes }),
|
|
2041
2376
|
/* @__PURE__ */ jsx("ul", { className: f.cx("codes"), children: codes.map((c) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("code", { children: c }) }, c)) })
|
|
2042
2377
|
] });
|
|
2043
2378
|
if (setup) {
|
|
2044
2379
|
return /* @__PURE__ */ jsxs("form", { className: f.cx("section"), onSubmit: confirm, noValidate: true, children: [
|
|
2045
|
-
/* @__PURE__ */ jsx(
|
|
2046
|
-
/* @__PURE__ */ jsx(
|
|
2380
|
+
/* @__PURE__ */ jsx(Heading, { f, children: f.t.secondStep }),
|
|
2381
|
+
/* @__PURE__ */ jsx(Note, { f, children: f.t.addToApp }),
|
|
2047
2382
|
/* @__PURE__ */ jsx("code", { className: f.cx("secret"), children: setup.secret }),
|
|
2048
|
-
/* @__PURE__ */ jsx(
|
|
2049
|
-
general && /* @__PURE__ */ jsx(
|
|
2383
|
+
/* @__PURE__ */ jsx(A, { f, href: setup.otpauthUri, children: f.t.openInApp }),
|
|
2384
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
2050
2385
|
/* @__PURE__ */ jsx(Field, { f, name: "code", type: "text", label: f.t.code, value: code, autoComplete: "one-time-code", required: true, onChange: setCode }),
|
|
2051
2386
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.verify })
|
|
2052
2387
|
] });
|
|
2053
2388
|
}
|
|
2054
2389
|
return /* @__PURE__ */ jsxs("form", { className: f.cx("section"), onSubmit: account.mfaEnabled ? turnOff : start, noValidate: true, children: [
|
|
2055
|
-
/* @__PURE__ */ jsx(
|
|
2056
|
-
/* @__PURE__ */ jsx(
|
|
2390
|
+
/* @__PURE__ */ jsx(Heading, { f, children: f.t.secondStep }),
|
|
2391
|
+
/* @__PURE__ */ jsx(Note, { f, children: account.mfaEnabled ? f.t.secondStepOn : f.t.secondStepOff }),
|
|
2057
2392
|
shown,
|
|
2058
|
-
general && /* @__PURE__ */ jsx(
|
|
2393
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
2059
2394
|
passwordField,
|
|
2060
2395
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: account.mfaEnabled ? f.t.turnOff : f.t.turnOn }),
|
|
2061
2396
|
account.mfaEnabled && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void renew(), children: f.t.newRecoveryCodes })
|
|
@@ -2093,6 +2428,7 @@ function PhonePart({ props, account, onChanged }) {
|
|
|
2093
2428
|
setPassword("");
|
|
2094
2429
|
if (r.recoveryCodes.length > 0) setCodes(r.recoveryCodes);
|
|
2095
2430
|
onChanged(true);
|
|
2431
|
+
props.onSaved?.({ kind: "phone.added", channel });
|
|
2096
2432
|
await load();
|
|
2097
2433
|
};
|
|
2098
2434
|
const remove = async (e) => {
|
|
@@ -2103,27 +2439,29 @@ function PhonePart({ props, account, onChanged }) {
|
|
|
2103
2439
|
await load();
|
|
2104
2440
|
const left = await auth.account.mfa.factors();
|
|
2105
2441
|
onChanged(Boolean(left?.totp));
|
|
2442
|
+
props.onSaved?.({ kind: "phone.removed" });
|
|
2106
2443
|
};
|
|
2107
2444
|
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 });
|
|
2108
2445
|
if (sentTo) {
|
|
2109
2446
|
return /* @__PURE__ */ jsxs("form", { className: f.cx("section"), onSubmit: confirm, noValidate: true, children: [
|
|
2110
|
-
/* @__PURE__ */ jsx(
|
|
2111
|
-
/* @__PURE__ */ jsx(
|
|
2112
|
-
general && /* @__PURE__ */ jsx(
|
|
2447
|
+
/* @__PURE__ */ jsx(Heading, { f, children: f.t.phone }),
|
|
2448
|
+
/* @__PURE__ */ jsx(Note, { f, children: f.t.codeSent.replace("{to}", sentTo) }),
|
|
2449
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
2113
2450
|
/* @__PURE__ */ jsx(Field, { f, name: "code", type: "text", label: f.t.code, value: code, autoComplete: "one-time-code", required: true, onChange: setCode }),
|
|
2114
2451
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.verify })
|
|
2115
2452
|
] });
|
|
2116
2453
|
}
|
|
2117
2454
|
return /* @__PURE__ */ jsxs("form", { className: f.cx("section"), onSubmit: ways.phone ? remove : add, noValidate: true, children: [
|
|
2118
|
-
/* @__PURE__ */ jsx(
|
|
2119
|
-
/* @__PURE__ */ jsx(
|
|
2120
|
-
codes && /* @__PURE__ */ jsxs(
|
|
2121
|
-
/* @__PURE__ */ jsx(
|
|
2455
|
+
/* @__PURE__ */ jsx(Heading, { f, children: f.t.phone }),
|
|
2456
|
+
/* @__PURE__ */ jsx(Note, { f, children: ways.phone ? f.t.phoneOn.replace("{to}", ways.phone.number) : `${f.t.phoneOff} ${f.t.phoneHelp}` }),
|
|
2457
|
+
codes && /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
2458
|
+
/* @__PURE__ */ jsx(Note, { f, children: f.t.keepCodes }),
|
|
2122
2459
|
/* @__PURE__ */ jsx("ul", { className: f.cx("codes"), children: codes.map((c) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("code", { children: c }) }, c)) })
|
|
2123
2460
|
] }),
|
|
2124
|
-
general && /* @__PURE__ */ jsx(
|
|
2461
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
2125
2462
|
!ways.phone && /* @__PURE__ */ jsx(Field, { f, name: "phone", type: "tel", label: f.t.phone, value: number, autoComplete: "tel", required: true, onChange: setNumber }),
|
|
2126
|
-
!ways.phone && ways.phoneChannels.length > 1 && /* @__PURE__ */ jsx(
|
|
2463
|
+
!ways.phone && ways.phoneChannels.length > 1 && f.C.Select && /* @__PURE__ */ jsx(ChannelPick, { f, value: channel, channels: ways.phoneChannels, onChange: setChannel }),
|
|
2464
|
+
!ways.phone && 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: [
|
|
2127
2465
|
/* @__PURE__ */ jsx("input", { type: "radio", name: "channel", value: c, checked: channel === c, onChange: () => setChannel(c) }),
|
|
2128
2466
|
" ",
|
|
2129
2467
|
c === "whatsapp" ? f.t.byWhatsapp : f.t.bySms
|
|
@@ -2142,12 +2480,14 @@ function AgentsPart({ props, when }) {
|
|
|
2142
2480
|
if (list.length === 0) return null;
|
|
2143
2481
|
const disconnect = async (id) => {
|
|
2144
2482
|
const r = await run(() => auth.account.disconnectAgent(id));
|
|
2145
|
-
if (r.ok)
|
|
2483
|
+
if (!r.ok) return;
|
|
2484
|
+
setList(list.filter((a) => a.id !== id));
|
|
2485
|
+
props.onSaved?.({ kind: "agent.disconnected", id });
|
|
2146
2486
|
};
|
|
2147
2487
|
return /* @__PURE__ */ jsxs("section", { className: f.cx("section"), children: [
|
|
2148
|
-
/* @__PURE__ */ jsx(
|
|
2149
|
-
/* @__PURE__ */ jsx(
|
|
2150
|
-
general && /* @__PURE__ */ jsx(
|
|
2488
|
+
/* @__PURE__ */ jsx(Heading, { f, children: f.t.agents }),
|
|
2489
|
+
/* @__PURE__ */ jsx(Note, { f, children: f.t.agentsHelp }),
|
|
2490
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
2151
2491
|
/* @__PURE__ */ jsx("ul", { className: f.cx("sessions"), children: list.map((a) => /* @__PURE__ */ jsxs("li", { className: f.cx("session"), children: [
|
|
2152
2492
|
a.name || f.t.anAgent,
|
|
2153
2493
|
a.redirectHost ? ` (${a.redirectHost})` : "",
|
|
@@ -2161,20 +2501,47 @@ function AgentsPart({ props, when }) {
|
|
|
2161
2501
|
] }, a.id)) })
|
|
2162
2502
|
] });
|
|
2163
2503
|
}
|
|
2164
|
-
function
|
|
2504
|
+
function SessionsPart({ props, when }) {
|
|
2165
2505
|
const auth = useAuth();
|
|
2166
2506
|
const { f, run, general } = useSection(props);
|
|
2507
|
+
const [sessions, setSessions] = useState([]);
|
|
2508
|
+
useEffect(() => {
|
|
2509
|
+
void auth.account.sessions().then(setSessions);
|
|
2510
|
+
}, []);
|
|
2167
2511
|
const end = async () => {
|
|
2168
2512
|
const r = await run(() => auth.account.signOutEverywhere());
|
|
2169
2513
|
if (!r.ok) return;
|
|
2514
|
+
props.onSaved?.({ kind: "sessions.ended" });
|
|
2170
2515
|
if (props.onSignedOut) props.onSignedOut();
|
|
2171
2516
|
else window.location.assign("/");
|
|
2172
2517
|
};
|
|
2173
|
-
return /* @__PURE__ */ jsxs(
|
|
2174
|
-
|
|
2518
|
+
return /* @__PURE__ */ jsxs("section", { className: f.cx("section"), children: [
|
|
2519
|
+
/* @__PURE__ */ jsx(Heading, { f, children: f.t.sessions }),
|
|
2520
|
+
/* @__PURE__ */ jsx("ul", { className: f.cx("sessions"), children: sessions.map((s, i) => /* @__PURE__ */ jsxs("li", { className: f.cx("session"), children: [
|
|
2521
|
+
s.device || f.t.unknownDevice,
|
|
2522
|
+
" \xB7 ",
|
|
2523
|
+
s.ip,
|
|
2524
|
+
" \xB7 ",
|
|
2525
|
+
when(s.createdAt)
|
|
2526
|
+
] }, i)) }),
|
|
2527
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
2175
2528
|
/* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("button"), onClick: () => void end(), children: f.t.signOutEverywhere })
|
|
2176
2529
|
] });
|
|
2177
2530
|
}
|
|
2531
|
+
function ChannelPick({ f, value, channels, onChange }) {
|
|
2532
|
+
const id = useId();
|
|
2533
|
+
return /* @__PURE__ */ jsx(Labelled, { f, id, label: f.t.channel, children: /* @__PURE__ */ jsx(
|
|
2534
|
+
Pick,
|
|
2535
|
+
{
|
|
2536
|
+
f,
|
|
2537
|
+
id,
|
|
2538
|
+
name: "channel",
|
|
2539
|
+
value,
|
|
2540
|
+
options: channels.map((c) => ({ value: c, label: c === "whatsapp" ? f.t.byWhatsapp : f.t.bySms })),
|
|
2541
|
+
onChange: (c) => onChange(c)
|
|
2542
|
+
}
|
|
2543
|
+
) });
|
|
2544
|
+
}
|
|
2178
2545
|
|
|
2179
2546
|
// src/react.tsx
|
|
2180
2547
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
@@ -2276,6 +2643,8 @@ function useAuth() {
|
|
|
2276
2643
|
googleOneTap: (o) => then(client.signIn.googleOneTap(o))
|
|
2277
2644
|
},
|
|
2278
2645
|
signUp: { email: (f) => then(client.signUp.email(f)) },
|
|
2646
|
+
// The invited person is signed in once they accept.
|
|
2647
|
+
acceptInvitation: (token, password) => then(client.acceptInvitation(token, password)),
|
|
2279
2648
|
signOut: () => then(client.signOut()),
|
|
2280
2649
|
account: {
|
|
2281
2650
|
...client.account,
|
|
@@ -2293,11 +2662,22 @@ function useAuth() {
|
|
|
2293
2662
|
}, [basePath, refresh, session, status]);
|
|
2294
2663
|
}
|
|
2295
2664
|
export {
|
|
2665
|
+
AcceptInvite,
|
|
2296
2666
|
Account,
|
|
2667
|
+
AccountAgents,
|
|
2668
|
+
AccountEmail,
|
|
2669
|
+
AccountLinked,
|
|
2670
|
+
AccountPasskeys,
|
|
2671
|
+
AccountPassword,
|
|
2672
|
+
AccountPhone,
|
|
2673
|
+
AccountProfile,
|
|
2674
|
+
AccountSecondStep,
|
|
2675
|
+
AccountSessions,
|
|
2297
2676
|
CauthyProvider,
|
|
2298
2677
|
ForgotPassword,
|
|
2299
2678
|
GoogleOneTap,
|
|
2300
2679
|
OrganizationMembers,
|
|
2680
|
+
PendingTerms,
|
|
2301
2681
|
ResetPassword,
|
|
2302
2682
|
SignIn,
|
|
2303
2683
|
SignUp,
|