cauthy-auth 0.31.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 +40 -2
- package/dist/react.d.mts +280 -28
- package/dist/react.d.ts +280 -28
- package/dist/react.js +447 -193
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +444 -200
- package/dist/react.mjs.map +1 -1
- package/package.json +2 -1
package/dist/react.mjs
CHANGED
|
@@ -721,8 +721,8 @@ function definePolicy(given) {
|
|
|
721
721
|
}
|
|
722
722
|
|
|
723
723
|
// src/components.tsx
|
|
724
|
-
import { useEffect, useId, useRef, useState } from "react";
|
|
725
|
-
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";
|
|
726
726
|
var TEXTS = {
|
|
727
727
|
en: {
|
|
728
728
|
email: "Email",
|
|
@@ -763,6 +763,7 @@ var TEXTS = {
|
|
|
763
763
|
removePhone: "Remove phone",
|
|
764
764
|
bySms: "SMS",
|
|
765
765
|
byWhatsapp: "WhatsApp",
|
|
766
|
+
channel: "Send codes by",
|
|
766
767
|
checkEmail: "Almost there: open the link we sent to confirm your address \u2014 it signs you in.",
|
|
767
768
|
backToSignIn: "Back to sign in",
|
|
768
769
|
emailMeALink: "Email me a sign-in link",
|
|
@@ -852,6 +853,9 @@ var TEXTS = {
|
|
|
852
853
|
organizationDeleted: "{org} was deleted.",
|
|
853
854
|
yes: "Yes",
|
|
854
855
|
cancel: "Cancel",
|
|
856
|
+
termsChanged: "Our terms changed",
|
|
857
|
+
termsChangedHelp: "To go on, read and accept",
|
|
858
|
+
acceptTerms: "Accept",
|
|
855
859
|
errors: {
|
|
856
860
|
not_allowed: "Your role in this organization does not allow that.",
|
|
857
861
|
last_manager: "Somebody else must manage the members first: give that role to another member.",
|
|
@@ -939,6 +943,7 @@ var TEXTS = {
|
|
|
939
943
|
removePhone: "Quitar tel\xE9fono",
|
|
940
944
|
bySms: "SMS",
|
|
941
945
|
byWhatsapp: "WhatsApp",
|
|
946
|
+
channel: "Enviar los c\xF3digos por",
|
|
942
947
|
checkEmail: "Casi listo: abre el enlace que te enviamos para confirmar tu correo; te deja adentro.",
|
|
943
948
|
backToSignIn: "Volver a entrar",
|
|
944
949
|
emailMeALink: "Env\xEDame un enlace para entrar",
|
|
@@ -1028,6 +1033,9 @@ var TEXTS = {
|
|
|
1028
1033
|
organizationDeleted: "{org} qued\xF3 eliminada.",
|
|
1029
1034
|
yes: "S\xED",
|
|
1030
1035
|
cancel: "Cancelar",
|
|
1036
|
+
termsChanged: "Nuestros t\xE9rminos cambiaron",
|
|
1037
|
+
termsChangedHelp: "Para seguir, lee y acepta",
|
|
1038
|
+
acceptTerms: "Aceptar",
|
|
1031
1039
|
errors: {
|
|
1032
1040
|
not_allowed: "Tu rol en esta organizaci\xF3n no permite eso.",
|
|
1033
1041
|
last_manager: "Primero alguien m\xE1s debe administrar los miembros: dale ese rol a otro miembro.",
|
|
@@ -1188,8 +1196,10 @@ function sameOrigin(to) {
|
|
|
1188
1196
|
function useForm(props) {
|
|
1189
1197
|
const t = { ...TEXTS[props.locale ?? "en"], ...props.texts, errors: { ...TEXTS[props.locale ?? "en"].errors, ...props.texts?.errors } };
|
|
1190
1198
|
const cx = (slot) => props.classNames?.[slot] ?? `cauthy-${slot}`;
|
|
1191
|
-
const
|
|
1192
|
-
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;
|
|
1193
1203
|
const [error, setError] = useState(null);
|
|
1194
1204
|
const [busy, setBusy] = useState(false);
|
|
1195
1205
|
const [policy, setPolicy] = useState(void 0);
|
|
@@ -1204,7 +1214,81 @@ function useForm(props) {
|
|
|
1204
1214
|
else window.location.assign(sitePath(to) ?? sameOrigin(props.returnTo) ?? "/");
|
|
1205
1215
|
};
|
|
1206
1216
|
const root = useRoot(props);
|
|
1207
|
-
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)) });
|
|
1208
1292
|
}
|
|
1209
1293
|
var PASSWORD_RULES = ["needs_lowercase", "needs_uppercase", "needs_digit", "needs_symbol", "needs_classes", "breached"];
|
|
1210
1294
|
function isPasswordRule(e) {
|
|
@@ -1222,26 +1306,43 @@ function Field(p) {
|
|
|
1222
1306
|
const { f } = p;
|
|
1223
1307
|
const bad = f.error?.field === p.name ? f.error : null;
|
|
1224
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
|
+
}
|
|
1225
1340
|
return /* @__PURE__ */ jsxs("div", { className: f.cx("field"), children: [
|
|
1226
1341
|
/* @__PURE__ */ jsxs("label", { className: f.cx("label"), htmlFor: id, children: [
|
|
1227
1342
|
p.label,
|
|
1228
1343
|
p.aside
|
|
1229
1344
|
] }),
|
|
1230
|
-
|
|
1231
|
-
f.Input,
|
|
1232
|
-
{
|
|
1233
|
-
id,
|
|
1234
|
-
name: p.name,
|
|
1235
|
-
type: p.type,
|
|
1236
|
-
value: p.value,
|
|
1237
|
-
autoComplete: p.autoComplete,
|
|
1238
|
-
required: p.required,
|
|
1239
|
-
className: f.cx("input"),
|
|
1240
|
-
"aria-invalid": bad ? true : void 0,
|
|
1241
|
-
"aria-describedby": described || void 0,
|
|
1242
|
-
onChange: (e) => p.onChange(e.target.value)
|
|
1243
|
-
}
|
|
1244
|
-
),
|
|
1345
|
+
input,
|
|
1245
1346
|
p.hint && !bad && /* @__PURE__ */ jsx("span", { id: `${id}-hint`, className: f.cx("hint"), children: p.hint }),
|
|
1246
1347
|
bad && /* @__PURE__ */ jsx("span", { id: `${id}-error`, role: "alert", className: f.cx("fieldError"), children: f.say(bad) })
|
|
1247
1348
|
] });
|
|
@@ -1325,10 +1426,17 @@ function SecondStepForm(p) {
|
|
|
1325
1426
|
const general = f.error && !f.error.field ? f.error : null;
|
|
1326
1427
|
const to = phoneWay?.phone?.number ?? "";
|
|
1327
1428
|
return /* @__PURE__ */ jsxs("form", { className: f.cx("form"), ...f.root, onSubmit: submit, noValidate: true, children: [
|
|
1328
|
-
/* @__PURE__ */ jsx(
|
|
1329
|
-
general && /* @__PURE__ */ jsx(
|
|
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) }),
|
|
1330
1431
|
phoneWay?.email && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void sendEmail(), children: f.t.sendEmailAgain }),
|
|
1331
|
-
pushNumber > 0 ?
|
|
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: [
|
|
1332
1440
|
/* @__PURE__ */ jsx("p", { children: f.t.pushPick.replace("{n}", String(pushNumber)) }),
|
|
1333
1441
|
/* @__PURE__ */ jsx("p", { style: { fontSize: 48, fontWeight: 700, margin: "4px 0", textAlign: "center" }, children: pushNumber }),
|
|
1334
1442
|
/* @__PURE__ */ jsx("p", { children: f.t.pushWaiting })
|
|
@@ -1340,7 +1448,7 @@ function SecondStepForm(p) {
|
|
|
1340
1448
|
}
|
|
1341
1449
|
function ProviderButtons(p) {
|
|
1342
1450
|
const { f } = p;
|
|
1343
|
-
return /* @__PURE__ */ jsx(
|
|
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: [
|
|
1344
1452
|
provider.iconUrl && /* @__PURE__ */ jsx("img", { src: provider.iconUrl, alt: "", width: 18, height: 18, className: f.cx("providerIcon") }),
|
|
1345
1453
|
f.t.continueWith,
|
|
1346
1454
|
" ",
|
|
@@ -1462,27 +1570,27 @@ function SignIn(props) {
|
|
|
1462
1570
|
if (step === "opening") return /* @__PURE__ */ jsx("div", { className: f.cx("form"), ...f.root, "aria-busy": "true" });
|
|
1463
1571
|
if (step === "sent") {
|
|
1464
1572
|
return /* @__PURE__ */ jsxs("form", { className: f.cx("form"), ...f.root, onSubmit: submit, noValidate: true, children: [
|
|
1465
|
-
/* @__PURE__ */ jsx(
|
|
1466
|
-
general && /* @__PURE__ */ jsx(
|
|
1467
|
-
/* @__PURE__ */ jsx(
|
|
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 }),
|
|
1468
1576
|
/* @__PURE__ */ jsx(Field, { f, name: "code", type: "text", label: f.t.code, value: code, autoComplete: "one-time-code", required: true, onChange: setCode }),
|
|
1469
1577
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.verify })
|
|
1470
1578
|
] });
|
|
1471
1579
|
}
|
|
1472
1580
|
if (step === "code") return /* @__PURE__ */ jsx(SecondStepForm, { f, auth });
|
|
1473
1581
|
return /* @__PURE__ */ jsxs("form", { className: f.cx("form"), ...f.root, onSubmit: submit, noValidate: true, children: [
|
|
1474
|
-
general && /* @__PURE__ */ jsx(
|
|
1582
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
1475
1583
|
/* @__PURE__ */ jsx(ProviderButtons, { f, providers: methods?.providers ?? [], onPick: (id) => auth.signIn.social(id, { returnTo: props.returnTo }) }),
|
|
1476
1584
|
offers.passkey && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void usePasskey(), children: f.t.usePasskey }),
|
|
1477
|
-
asksEmail && ((methods?.providers.length ?? 0) > 0 || offers.passkey) && /* @__PURE__ */ jsx(
|
|
1585
|
+
asksEmail && ((methods?.providers.length ?? 0) > 0 || offers.passkey) && /* @__PURE__ */ jsx(Or, { f, children: f.t.orWithEmail }),
|
|
1478
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 }),
|
|
1479
1587
|
company && /* @__PURE__ */ jsxs(f.Button, { type: "button", disabled: f.busy, className: f.cx(company.enforced ? "button" : "providerButton"), onClick: toCompany, children: [
|
|
1480
1588
|
f.t.continueWith,
|
|
1481
1589
|
" ",
|
|
1482
1590
|
company.name
|
|
1483
1591
|
] }),
|
|
1484
|
-
company?.enforced && /* @__PURE__ */ jsx(
|
|
1485
|
-
!company?.enforced && passwordOn && /* @__PURE__ */ jsxs(
|
|
1592
|
+
company?.enforced && /* @__PURE__ */ jsx(Note, { f, children: f.t.ssoOnly }),
|
|
1593
|
+
!company?.enforced && passwordOn && /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
1486
1594
|
/* @__PURE__ */ jsx(
|
|
1487
1595
|
Field,
|
|
1488
1596
|
{
|
|
@@ -1494,7 +1602,7 @@ function SignIn(props) {
|
|
|
1494
1602
|
autoComplete: "current-password",
|
|
1495
1603
|
required: true,
|
|
1496
1604
|
onChange: setPassword,
|
|
1497
|
-
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
|
|
1498
1606
|
}
|
|
1499
1607
|
),
|
|
1500
1608
|
challenge.node,
|
|
@@ -1502,10 +1610,10 @@ function SignIn(props) {
|
|
|
1502
1610
|
] }),
|
|
1503
1611
|
!company?.enforced && !passwordOn && methods?.magicLink && challenge.node,
|
|
1504
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 }),
|
|
1505
|
-
methods?.signUp !== false && props.links?.signUp && /* @__PURE__ */ jsxs(
|
|
1613
|
+
methods?.signUp !== false && props.links?.signUp && /* @__PURE__ */ jsxs(Note, { f, footer: true, children: [
|
|
1506
1614
|
f.t.noAccount,
|
|
1507
1615
|
" ",
|
|
1508
|
-
/* @__PURE__ */ jsx(
|
|
1616
|
+
/* @__PURE__ */ jsx(A, { f, href: props.links.signUp, children: f.t.createAccount })
|
|
1509
1617
|
] })
|
|
1510
1618
|
] });
|
|
1511
1619
|
}
|
|
@@ -1564,49 +1672,36 @@ function SignUp(props) {
|
|
|
1564
1672
|
const providers = auth.session?.user.isAnonymous === true || methods?.organization?.required ? [] : methods?.providers ?? [];
|
|
1565
1673
|
if (sent) {
|
|
1566
1674
|
return /* @__PURE__ */ jsxs("div", { className: f.cx("form"), ...f.root, children: [
|
|
1567
|
-
/* @__PURE__ */ jsx(
|
|
1568
|
-
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 })
|
|
1569
1677
|
] });
|
|
1570
1678
|
}
|
|
1571
|
-
const footer = props.links?.signIn && /* @__PURE__ */ jsxs(
|
|
1679
|
+
const footer = props.links?.signIn && /* @__PURE__ */ jsxs(Note, { f, footer: true, children: [
|
|
1572
1680
|
f.t.haveAccount,
|
|
1573
1681
|
" ",
|
|
1574
|
-
/* @__PURE__ */ jsx(
|
|
1682
|
+
/* @__PURE__ */ jsx(A, { f, href: props.links.signIn, children: f.t.signIn })
|
|
1575
1683
|
] });
|
|
1576
1684
|
if (!passwordOn) {
|
|
1577
1685
|
return /* @__PURE__ */ jsxs("div", { className: f.cx("form"), ...f.root, children: [
|
|
1578
|
-
general && /* @__PURE__ */ jsx(
|
|
1686
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
1579
1687
|
/* @__PURE__ */ jsx(ProviderButtons, { f, providers, onPick: (id) => auth.signIn.social(id, { returnTo: props.returnTo }) }),
|
|
1580
1688
|
footer
|
|
1581
1689
|
] });
|
|
1582
1690
|
}
|
|
1583
1691
|
return /* @__PURE__ */ jsxs("form", { className: f.cx("form"), ...f.root, onSubmit: submit, noValidate: true, children: [
|
|
1584
|
-
general && /* @__PURE__ */ jsx(
|
|
1692
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
1585
1693
|
/* @__PURE__ */ jsx(ProviderButtons, { f, providers, onPick: (id) => auth.signIn.social(id, { returnTo: props.returnTo }) }),
|
|
1586
|
-
providers.length > 0 && /* @__PURE__ */ jsx(
|
|
1694
|
+
providers.length > 0 && /* @__PURE__ */ jsx(Or, { f, children: f.t.orWithEmail }),
|
|
1587
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 }),
|
|
1588
1696
|
/* @__PURE__ */ jsx(Field, { f, name: "name", type: "text", label: f.t.name, value: name, autoComplete: "name", onChange: setName }),
|
|
1589
1697
|
/* @__PURE__ */ jsx(Field, { f, name: "email", type: "email", label: f.t.email, value: email, autoComplete: "username", required: true, onChange: setEmail }),
|
|
1590
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 }),
|
|
1591
|
-
legal && legal.documents.length > 0 && /* @__PURE__ */ jsxs(
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
" ",
|
|
1596
|
-
legal.documents.map((d, i) => /* @__PURE__ */ jsxs("span", { children: [
|
|
1597
|
-
i > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1598
|
-
f.t.and,
|
|
1599
|
-
" "
|
|
1600
|
-
] }),
|
|
1601
|
-
/* @__PURE__ */ jsx("a", { className: f.cx("link"), href: d.url, target: "_blank", rel: "noopener", children: d.kind === "terms" ? f.t.termsOfService : f.t.privacyPolicy }),
|
|
1602
|
-
" "
|
|
1603
|
-
] }, d.kind))
|
|
1604
|
-
] })
|
|
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 })
|
|
1605
1703
|
] }),
|
|
1606
|
-
legal?.consentPurposes.map((p) => /* @__PURE__ */
|
|
1607
|
-
/* @__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 }) }),
|
|
1608
|
-
/* @__PURE__ */ jsx("span", { children: p.label })
|
|
1609
|
-
] }, 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)),
|
|
1610
1705
|
challenge.node,
|
|
1611
1706
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.signUp }),
|
|
1612
1707
|
footer
|
|
@@ -1631,16 +1726,16 @@ function ForgotPassword(props) {
|
|
|
1631
1726
|
const general = f.error && !f.error.field ? f.error : null;
|
|
1632
1727
|
if (sent) {
|
|
1633
1728
|
return /* @__PURE__ */ jsxs("div", { className: f.cx("form"), ...f.root, children: [
|
|
1634
|
-
/* @__PURE__ */ jsx(
|
|
1635
|
-
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 })
|
|
1636
1731
|
] });
|
|
1637
1732
|
}
|
|
1638
1733
|
return /* @__PURE__ */ jsxs("form", { className: f.cx("form"), ...f.root, onSubmit: submit, noValidate: true, children: [
|
|
1639
|
-
general && /* @__PURE__ */ jsx(
|
|
1734
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
1640
1735
|
/* @__PURE__ */ jsx(Field, { f, name: "email", type: "email", label: f.t.email, value: email, autoComplete: "username", required: true, onChange: setEmail }),
|
|
1641
1736
|
challenge.node,
|
|
1642
1737
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.sendLink }),
|
|
1643
|
-
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 }) })
|
|
1644
1739
|
] });
|
|
1645
1740
|
}
|
|
1646
1741
|
function ResetPassword(props) {
|
|
@@ -1664,21 +1759,21 @@ function ResetPassword(props) {
|
|
|
1664
1759
|
setChanged(true);
|
|
1665
1760
|
};
|
|
1666
1761
|
const general = f.error && !f.error.field ? f.error : null;
|
|
1667
|
-
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 });
|
|
1668
1763
|
if (changed) {
|
|
1669
1764
|
return /* @__PURE__ */ jsxs("div", { className: f.cx("form"), ...f.root, children: [
|
|
1670
|
-
/* @__PURE__ */ jsx(
|
|
1765
|
+
/* @__PURE__ */ jsx(Note, { f, children: f.t.passwordChanged }),
|
|
1671
1766
|
back
|
|
1672
1767
|
] });
|
|
1673
1768
|
}
|
|
1674
1769
|
if (token === "") {
|
|
1675
1770
|
return /* @__PURE__ */ jsxs("div", { className: f.cx("form"), ...f.root, children: [
|
|
1676
|
-
general && /* @__PURE__ */ jsx(
|
|
1677
|
-
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 })
|
|
1678
1773
|
] });
|
|
1679
1774
|
}
|
|
1680
1775
|
return /* @__PURE__ */ jsxs("form", { className: f.cx("form"), ...f.root, onSubmit: submit, noValidate: true, children: [
|
|
1681
|
-
general && /* @__PURE__ */ jsx(
|
|
1776
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
1682
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 }),
|
|
1683
1778
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy || token === null, className: f.cx("button"), children: f.t.savePassword })
|
|
1684
1779
|
] });
|
|
@@ -1700,10 +1795,10 @@ function VerifyEmail(props) {
|
|
|
1700
1795
|
});
|
|
1701
1796
|
});
|
|
1702
1797
|
return /* @__PURE__ */ jsxs("div", { className: f.cx("form"), ...f.root, "aria-busy": state === "confirming", children: [
|
|
1703
|
-
state === "confirming" && /* @__PURE__ */ jsx(
|
|
1704
|
-
state === "confirmed" && /* @__PURE__ */ jsx(
|
|
1705
|
-
state === "failed" && f.error && /* @__PURE__ */ jsx(
|
|
1706
|
-
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 })
|
|
1707
1802
|
] });
|
|
1708
1803
|
}
|
|
1709
1804
|
function AcceptInvite(props) {
|
|
@@ -1736,17 +1831,18 @@ function AcceptInvite(props) {
|
|
|
1736
1831
|
if (r.error.code === "invalid_token") return setState("invalid");
|
|
1737
1832
|
return f.setError(r.error);
|
|
1738
1833
|
}
|
|
1834
|
+
props.onSaved?.({ kind: "invitation.accepted", email: invitation?.email ?? "", ...invitation?.organization ? { organization: invitation.organization } : {} });
|
|
1739
1835
|
if (r.status === "mfa_required") return setState("code");
|
|
1740
1836
|
f.done();
|
|
1741
1837
|
};
|
|
1742
1838
|
const general = f.error && !f.error.field ? f.error : null;
|
|
1743
|
-
const back = props.links?.signIn && /* @__PURE__ */ jsx(
|
|
1839
|
+
const back = props.links?.signIn && /* @__PURE__ */ jsx(A, { f, href: props.links.signIn, children: f.t.backToSignIn });
|
|
1744
1840
|
if (state === "opening") {
|
|
1745
|
-
return /* @__PURE__ */ jsx("div", { className: f.cx("form"), ...f.root, "aria-busy": "true", children: /* @__PURE__ */ jsx(
|
|
1841
|
+
return /* @__PURE__ */ jsx("div", { className: f.cx("form"), ...f.root, "aria-busy": "true", children: /* @__PURE__ */ jsx(Note, { f, children: f.t.openingInvitation }) });
|
|
1746
1842
|
}
|
|
1747
1843
|
if (state === "invalid") {
|
|
1748
1844
|
return /* @__PURE__ */ jsxs("div", { className: f.cx("form"), ...f.root, children: [
|
|
1749
|
-
/* @__PURE__ */ jsx(
|
|
1845
|
+
/* @__PURE__ */ jsx(Say, { f, tone: "danger", children: general ? f.say(general) : f.t.invitationInvalid }),
|
|
1750
1846
|
back
|
|
1751
1847
|
] });
|
|
1752
1848
|
}
|
|
@@ -1754,14 +1850,43 @@ function AcceptInvite(props) {
|
|
|
1754
1850
|
const workspace = invitation?.workspace ?? "";
|
|
1755
1851
|
const heading = invitation?.organization ? f.t.invitedToOrganization.replace("{organization}", invitation.organization).replace("{workspace}", workspace) : f.t.invitedTo.replace("{workspace}", workspace);
|
|
1756
1852
|
return /* @__PURE__ */ jsxs("form", { className: f.cx("form"), ...f.root, onSubmit: submit, noValidate: true, children: [
|
|
1757
|
-
/* @__PURE__ */ jsx(
|
|
1758
|
-
/* @__PURE__ */ jsx(
|
|
1759
|
-
general && /* @__PURE__ */ jsx(
|
|
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) }),
|
|
1760
1856
|
/* @__PURE__ */ jsx("input", { type: "email", name: "username", autoComplete: "username", value: invitation?.email ?? "", readOnly: true, hidden: true }),
|
|
1761
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 }),
|
|
1762
1858
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.acceptInvite })
|
|
1763
1859
|
] });
|
|
1764
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"];
|
|
1765
1890
|
function useSection(props) {
|
|
1766
1891
|
const f = useForm({ ...props, unstyled: true });
|
|
1767
1892
|
const [done, setDone] = useState(null);
|
|
@@ -1780,37 +1905,65 @@ function useSection(props) {
|
|
|
1780
1905
|
function Account(props) {
|
|
1781
1906
|
const auth = useAuth();
|
|
1782
1907
|
const { accountUrl } = useSession();
|
|
1783
|
-
const {
|
|
1908
|
+
const { root } = useForm(props);
|
|
1784
1909
|
const cx = (slot) => props.classNames?.[slot] ?? `cauthy-${slot}`;
|
|
1785
1910
|
const [account, setAccount] = useState(null);
|
|
1786
|
-
const [sessions, setSessions] = useState([]);
|
|
1787
1911
|
useEffect(() => {
|
|
1788
1912
|
void auth.account.get().then(setAccount);
|
|
1789
|
-
void auth.account.sessions().then(setSessions);
|
|
1790
1913
|
}, []);
|
|
1791
1914
|
if (account === null) return /* @__PURE__ */ jsx("div", { className: cx("account"), ...root, "aria-busy": "true" });
|
|
1792
1915
|
const when = props.formatDate ?? ((iso) => new Date(iso).toLocaleString());
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
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"] });
|
|
1814
1967
|
}
|
|
1815
1968
|
var OWNER = "owner";
|
|
1816
1969
|
function memberActions(seat, m) {
|
|
@@ -1822,8 +1975,9 @@ function memberActions(seat, m) {
|
|
|
1822
1975
|
inviteAgain: seat.can.manageMembers && m.invited
|
|
1823
1976
|
};
|
|
1824
1977
|
}
|
|
1825
|
-
function rolesToGive(seat, roles) {
|
|
1826
|
-
|
|
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;
|
|
1827
1981
|
}
|
|
1828
1982
|
function OrganizationMembers(props) {
|
|
1829
1983
|
const auth = useAuth();
|
|
@@ -1840,6 +1994,8 @@ function OrganizationMembers(props) {
|
|
|
1840
1994
|
const [gone, setGone] = useState(null);
|
|
1841
1995
|
const id = props.organizationId;
|
|
1842
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);
|
|
1843
1999
|
const load = async () => {
|
|
1844
2000
|
const [list, people, choices] = await Promise.all([auth.organizations.list(), auth.organizations.members(id), auth.organizations.roles(id)]);
|
|
1845
2001
|
const mine = list.find((o) => o.id === id) ?? null;
|
|
@@ -1847,17 +2003,17 @@ function OrganizationMembers(props) {
|
|
|
1847
2003
|
if (mine) setName(mine.name);
|
|
1848
2004
|
setMembers(people);
|
|
1849
2005
|
setRoles(choices ?? []);
|
|
1850
|
-
const offered = mine ? rolesToGive(mine, choices ?? []) : [];
|
|
2006
|
+
const offered = mine ? rolesToGive(mine, choices ?? [], props.roles) : [];
|
|
1851
2007
|
if (offered.length > 0 && !offered.some((c) => c.role === role)) setRole(offered[0].role);
|
|
1852
2008
|
};
|
|
1853
2009
|
useEffect(() => {
|
|
1854
2010
|
void load();
|
|
1855
2011
|
}, [id]);
|
|
1856
|
-
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 }) });
|
|
1857
2013
|
if (seat === void 0) return /* @__PURE__ */ jsx("div", { className: f.cx("account"), ...root, "aria-busy": "true" });
|
|
1858
|
-
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 }) });
|
|
1859
2015
|
const manage = seat.can.manageMembers;
|
|
1860
|
-
const giveable = rolesToGive(seat, roles);
|
|
2016
|
+
const giveable = rolesToGive(seat, roles, props.roles);
|
|
1861
2017
|
const label = (r) => roles.find((c) => c.role === r)?.name || r;
|
|
1862
2018
|
const add = async (e) => {
|
|
1863
2019
|
e.preventDefault();
|
|
@@ -1865,22 +2021,28 @@ function OrganizationMembers(props) {
|
|
|
1865
2021
|
if (!r.ok) return;
|
|
1866
2022
|
setEmail("");
|
|
1867
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 });
|
|
1868
2025
|
await load();
|
|
1869
2026
|
};
|
|
1870
2027
|
const change = async (m, next) => {
|
|
1871
2028
|
const r = await run(() => auth.organizations.setRole(id, m.userId, next));
|
|
1872
|
-
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();
|
|
1873
2032
|
};
|
|
1874
2033
|
const remove = async (m) => {
|
|
1875
2034
|
setAsking(null);
|
|
1876
2035
|
const r = await run(() => auth.organizations.remove(id, m.userId));
|
|
1877
2036
|
if (!r.ok) return;
|
|
2037
|
+
saved({ kind: m.you ? "member.left" : "member.removed", organizationId: id, userId: m.userId });
|
|
1878
2038
|
if (m.you) setSeat(null);
|
|
1879
2039
|
else await load();
|
|
1880
2040
|
};
|
|
1881
2041
|
const inviteAgain = async (m) => {
|
|
1882
2042
|
const r = await run(() => auth.organizations.inviteAgain(id, m.userId, { locale: props.locale }));
|
|
1883
|
-
if (r.ok)
|
|
2043
|
+
if (!r.ok) return;
|
|
2044
|
+
setDone(f.t.memberInvitationSent);
|
|
2045
|
+
saved({ kind: "member.invited_again", organizationId: id, userId: m.userId });
|
|
1884
2046
|
};
|
|
1885
2047
|
const rename = async (e) => {
|
|
1886
2048
|
e.preventDefault();
|
|
@@ -1889,11 +2051,21 @@ function OrganizationMembers(props) {
|
|
|
1889
2051
|
setSeat(r.organization);
|
|
1890
2052
|
setName(r.organization.name);
|
|
1891
2053
|
setDone(f.t.organizationRenamed.replace("{name}", r.organization.name));
|
|
2054
|
+
saved({ kind: "organization.renamed", organizationId: id, name: r.organization.name });
|
|
1892
2055
|
};
|
|
1893
2056
|
const close = async (how) => {
|
|
1894
2057
|
setAsking(null);
|
|
1895
2058
|
const r = await run(() => how === "archive" ? auth.organizations.archive(id) : auth.organizations.delete(id));
|
|
1896
|
-
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
|
+
});
|
|
1897
2069
|
};
|
|
1898
2070
|
const confirming = (text2, label2, yes) => /* @__PURE__ */ jsxs("span", { role: "group", "aria-label": label2, children: [
|
|
1899
2071
|
/* @__PURE__ */ jsx("span", { children: text2 }),
|
|
@@ -1901,81 +2073,96 @@ function OrganizationMembers(props) {
|
|
|
1901
2073
|
/* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: yes, children: f.t.yes }),
|
|
1902
2074
|
/* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => setAsking(null), children: f.t.cancel })
|
|
1903
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");
|
|
1904
2082
|
return /* @__PURE__ */ jsxs("div", { className: f.cx("account"), ...root, children: [
|
|
1905
2083
|
/* @__PURE__ */ jsxs("section", { className: f.cx("section"), children: [
|
|
1906
|
-
/* @__PURE__ */ jsxs(
|
|
2084
|
+
/* @__PURE__ */ jsxs(Heading, { f, children: [
|
|
1907
2085
|
f.t.members,
|
|
1908
2086
|
" \xB7 ",
|
|
1909
2087
|
seat.name
|
|
1910
2088
|
] }),
|
|
1911
|
-
problem && /* @__PURE__ */ jsx(
|
|
1912
|
-
members === null ? /* @__PURE__ */ jsxs(
|
|
1913
|
-
/* @__PURE__ */ jsx(
|
|
1914
|
-
auth.session && (asking === auth.session.user.id ? confirming(
|
|
1915
|
-
f.
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
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
|
+
))
|
|
1919
2102
|
] }) : /* @__PURE__ */ jsx("ul", { className: f.cx("sessions"), children: members.map((m) => {
|
|
1920
2103
|
const who = m.name || m.email;
|
|
1921
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];
|
|
1922
2109
|
return /* @__PURE__ */ jsxs("li", { className: f.cx("session"), children: [
|
|
1923
2110
|
/* @__PURE__ */ jsxs("span", { children: [
|
|
1924
2111
|
who,
|
|
1925
2112
|
m.name ? ` \xB7 ${m.email}` : "",
|
|
1926
|
-
m.you
|
|
1927
|
-
|
|
1928
|
-
|
|
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}` : ""}`,
|
|
1929
2118
|
" \xB7 ",
|
|
1930
2119
|
when(m.since)
|
|
1931
2120
|
] }),
|
|
1932
2121
|
" ",
|
|
1933
2122
|
may.changeRole && giveable.length > 0 ? /* @__PURE__ */ jsx(
|
|
1934
|
-
|
|
2123
|
+
Pick,
|
|
1935
2124
|
{
|
|
1936
|
-
|
|
1937
|
-
|
|
2125
|
+
f,
|
|
2126
|
+
name: `role_${m.userId}`,
|
|
2127
|
+
label: `${f.t.memberRole}: ${who}`,
|
|
1938
2128
|
value: m.role,
|
|
1939
2129
|
disabled: f.busy,
|
|
1940
|
-
|
|
1941
|
-
|
|
2130
|
+
options: choices.map((c) => ({ value: c.role, label: c.name || c.role })),
|
|
2131
|
+
onChange: (next) => void change(m, next)
|
|
1942
2132
|
}
|
|
1943
|
-
) : /* @__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) }),
|
|
1944
2134
|
" ",
|
|
1945
|
-
asking === m.userId ? confirming(
|
|
1946
|
-
m.you ? f.t.memberLeaveConfirm.replace("{org}", seat.name) : f.t.memberRemoveConfirm.replace("{who}", who),
|
|
1947
|
-
m.you ? f.t.memberLeave : f.t.memberRemove,
|
|
1948
|
-
() => void remove(m)
|
|
1949
|
-
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2135
|
+
asking === m.userId ? confirming(question, action, () => void remove(m)) : /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
1950
2136
|
may.inviteAgain && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void inviteAgain(m), children: f.t.memberInviteAgain }),
|
|
1951
|
-
|
|
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 })
|
|
1952
2138
|
] })
|
|
1953
2139
|
] }, m.userId);
|
|
1954
2140
|
}) }),
|
|
1955
|
-
done && /* @__PURE__ */ jsx(
|
|
2141
|
+
done && /* @__PURE__ */ jsx(Say, { f, tone: "success", children: done })
|
|
1956
2142
|
] }),
|
|
1957
2143
|
manage && giveable.length > 0 && /* @__PURE__ */ jsxs("form", { className: f.cx("section"), onSubmit: add, noValidate: true, children: [
|
|
1958
|
-
/* @__PURE__ */ jsx(
|
|
2144
|
+
/* @__PURE__ */ jsx(Heading, { f, children: f.t.memberAdd }),
|
|
1959
2145
|
/* @__PURE__ */ jsx(Field, { f, name: "email", type: "email", label: f.t.email, value: email, autoComplete: "off", required: true, onChange: setEmail }),
|
|
1960
|
-
/* @__PURE__ */
|
|
1961
|
-
/* @__PURE__ */ jsx("span", { className: f.cx("label"), children: f.t.memberRole }),
|
|
1962
|
-
/* @__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)) })
|
|
1963
|
-
] }),
|
|
2146
|
+
/* @__PURE__ */ jsx(AddRole, { f, value: role, options: giveable.map((c) => ({ value: c.role, label: c.name || c.role })), onChange: setRole }),
|
|
1964
2147
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.memberAdd })
|
|
1965
2148
|
] }),
|
|
1966
|
-
(
|
|
1967
|
-
/* @__PURE__ */ jsx(
|
|
1968
|
-
|
|
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: [
|
|
1969
2152
|
/* @__PURE__ */ jsx(Field, { f, name: "name", type: "text", label: f.t.name, value: name, autoComplete: "organization", required: true, onChange: setName }),
|
|
1970
2153
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.organizationRename })
|
|
1971
2154
|
] }),
|
|
1972
|
-
asking === "archive" ? confirming(
|
|
1973
|
-
|
|
1974
|
-
|
|
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 })
|
|
1975
2158
|
] })
|
|
1976
2159
|
] })
|
|
1977
2160
|
] });
|
|
1978
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
|
+
}
|
|
1979
2166
|
function PasskeysPart({ props, account, accountUrl, when }) {
|
|
1980
2167
|
const auth = useAuth();
|
|
1981
2168
|
const { f, done, setDone, run, general } = useSection(props);
|
|
@@ -1993,8 +2180,8 @@ function PasskeysPart({ props, account, accountUrl, when }) {
|
|
|
1993
2180
|
if (here === null) return null;
|
|
1994
2181
|
if (!here) {
|
|
1995
2182
|
return /* @__PURE__ */ jsxs("section", { className: f.cx("section"), children: [
|
|
1996
|
-
/* @__PURE__ */ jsx(
|
|
1997
|
-
/* @__PURE__ */ jsx(
|
|
2183
|
+
/* @__PURE__ */ jsx(Heading, { f, children: f.t.passkeys }),
|
|
2184
|
+
/* @__PURE__ */ jsx(A, { f, href: accountUrl, children: f.t.managePasskeys })
|
|
1998
2185
|
] });
|
|
1999
2186
|
}
|
|
2000
2187
|
const add = async (e, kind = "device") => {
|
|
@@ -2008,18 +2195,21 @@ function PasskeysPart({ props, account, accountUrl, when }) {
|
|
|
2008
2195
|
setName("");
|
|
2009
2196
|
setPassword("");
|
|
2010
2197
|
setDone(f.t.passkeyAdded);
|
|
2198
|
+
props.onSaved?.({ kind: "passkey.added", id: r.passkey.id });
|
|
2011
2199
|
};
|
|
2012
2200
|
const remove = async (id) => {
|
|
2013
2201
|
const r = await run(() => auth.account.removePasskey(id));
|
|
2014
|
-
if (r.ok)
|
|
2202
|
+
if (!r.ok) return;
|
|
2203
|
+
setList(list.filter((p) => p.id !== id));
|
|
2204
|
+
props.onSaved?.({ kind: "passkey.removed", id });
|
|
2015
2205
|
};
|
|
2016
2206
|
return /* @__PURE__ */ jsxs("form", { className: f.cx("section"), onSubmit: add, noValidate: true, children: [
|
|
2017
|
-
/* @__PURE__ */ jsx(
|
|
2018
|
-
/* @__PURE__ */ jsx(
|
|
2019
|
-
general && /* @__PURE__ */ jsx(
|
|
2020
|
-
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: [
|
|
2021
2211
|
p.name || f.t.passkeyUnnamed,
|
|
2022
|
-
p.kind !== "unknown"
|
|
2212
|
+
p.kind !== "unknown" && /* @__PURE__ */ jsx(Tag, { f, plain: ` \xB7 ${f.t.passkeyKinds[p.kind]}`, children: f.t.passkeyKinds[p.kind] }),
|
|
2023
2213
|
" \xB7 ",
|
|
2024
2214
|
when(p.createdAt),
|
|
2025
2215
|
" ",
|
|
@@ -2029,7 +2219,7 @@ function PasskeysPart({ props, account, accountUrl, when }) {
|
|
|
2029
2219
|
account.hasPassword && /* @__PURE__ */ jsx(Field, { f, name: "password", type: "password", label: f.t.currentPassword, value: password, autoComplete: "current-password", required: true, onChange: setPassword }),
|
|
2030
2220
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.addPasskeyDevice }),
|
|
2031
2221
|
/* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void add(null, "security_key"), children: f.t.addSecurityKey }),
|
|
2032
|
-
done && /* @__PURE__ */ jsx(
|
|
2222
|
+
done && /* @__PURE__ */ jsx(Say, { f, tone: "success", children: done })
|
|
2033
2223
|
] });
|
|
2034
2224
|
}
|
|
2035
2225
|
function ProfilePart({ props, account, onSaved }) {
|
|
@@ -2042,14 +2232,15 @@ function ProfilePart({ props, account, onSaved }) {
|
|
|
2042
2232
|
if (!r.ok) return;
|
|
2043
2233
|
onSaved(r.account);
|
|
2044
2234
|
setDone(f.t.saved);
|
|
2235
|
+
props.onSaved?.({ kind: "profile.saved", name: r.account.name });
|
|
2045
2236
|
};
|
|
2046
2237
|
return /* @__PURE__ */ jsxs("form", { className: f.cx("section"), onSubmit: submit, noValidate: true, children: [
|
|
2047
|
-
/* @__PURE__ */ jsx(
|
|
2048
|
-
/* @__PURE__ */ jsx(
|
|
2049
|
-
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) }),
|
|
2050
2241
|
/* @__PURE__ */ jsx(Field, { f, name: "name", type: "text", label: f.t.name, value: name, autoComplete: "name", onChange: setName }),
|
|
2051
2242
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.save }),
|
|
2052
|
-
done && /* @__PURE__ */ jsx(
|
|
2243
|
+
done && /* @__PURE__ */ jsx(Say, { f, tone: "success", children: done })
|
|
2053
2244
|
] });
|
|
2054
2245
|
}
|
|
2055
2246
|
function EmailPart({ props, account }) {
|
|
@@ -2063,15 +2254,16 @@ function EmailPart({ props, account }) {
|
|
|
2063
2254
|
if (!r.ok) return;
|
|
2064
2255
|
setPassword("");
|
|
2065
2256
|
setDone(f.t.emailSent.replace("{email}", r.email));
|
|
2257
|
+
props.onSaved?.({ kind: "email.change_requested", email: r.email });
|
|
2066
2258
|
};
|
|
2067
2259
|
return /* @__PURE__ */ jsxs("form", { className: f.cx("section"), onSubmit: submit, noValidate: true, children: [
|
|
2068
|
-
/* @__PURE__ */ jsx(
|
|
2069
|
-
/* @__PURE__ */ jsx(
|
|
2070
|
-
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) }),
|
|
2071
2263
|
/* @__PURE__ */ jsx(Field, { f, name: "email", type: "email", label: f.t.newEmail, value: email, autoComplete: "email", required: true, onChange: setEmail }),
|
|
2072
2264
|
account.hasPassword && /* @__PURE__ */ jsx(Field, { f, name: "password", type: "password", label: f.t.currentPassword, value: password, autoComplete: "current-password", required: true, onChange: setPassword }),
|
|
2073
2265
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.changeEmail }),
|
|
2074
|
-
done && /* @__PURE__ */ jsx(
|
|
2266
|
+
done && /* @__PURE__ */ jsx(Say, { f, tone: "success", children: done })
|
|
2075
2267
|
] });
|
|
2076
2268
|
}
|
|
2077
2269
|
function LinkedPart({ props }) {
|
|
@@ -2084,21 +2276,26 @@ function LinkedPart({ props }) {
|
|
|
2084
2276
|
void auth.account.identities().then(setLinked);
|
|
2085
2277
|
void auth.methods().then((m) => setOffered(m.providers));
|
|
2086
2278
|
const back = typeof window === "undefined" ? null : new URLSearchParams(window.location.search);
|
|
2087
|
-
|
|
2088
|
-
|
|
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." });
|
|
2089
2284
|
}, []);
|
|
2090
2285
|
if (linked === null) return null;
|
|
2091
2286
|
const name = (id) => offered.find((p) => p.id === id)?.name ?? id;
|
|
2092
2287
|
const unlink = async (provider) => {
|
|
2093
2288
|
const r = await run(() => auth.account.unlink(provider));
|
|
2094
|
-
if (r.ok)
|
|
2289
|
+
if (!r.ok) return;
|
|
2290
|
+
setLinked(linked.filter((x) => x.provider !== provider));
|
|
2291
|
+
props.onSaved?.({ kind: "identity.unlinked", provider });
|
|
2095
2292
|
};
|
|
2096
2293
|
const here = typeof window === "undefined" ? void 0 : window.location.pathname;
|
|
2097
2294
|
return /* @__PURE__ */ jsxs("section", { className: f.cx("section"), children: [
|
|
2098
|
-
/* @__PURE__ */ jsx(
|
|
2099
|
-
came && /* @__PURE__ */ jsx(
|
|
2100
|
-
general && /* @__PURE__ */ jsx(
|
|
2101
|
-
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: [
|
|
2102
2299
|
name(x.provider),
|
|
2103
2300
|
x.email ? ` \xB7 ${x.email}` : "",
|
|
2104
2301
|
" ",
|
|
@@ -2124,14 +2321,15 @@ function PasswordPart({ props }) {
|
|
|
2124
2321
|
setPassword("");
|
|
2125
2322
|
setNewPassword("");
|
|
2126
2323
|
setDone(f.t.passwordChangedHere);
|
|
2324
|
+
props.onSaved?.({ kind: "password.changed" });
|
|
2127
2325
|
};
|
|
2128
2326
|
return /* @__PURE__ */ jsxs("form", { className: f.cx("section"), onSubmit: submit, noValidate: true, children: [
|
|
2129
|
-
/* @__PURE__ */ jsx(
|
|
2130
|
-
general && /* @__PURE__ */ jsx(
|
|
2327
|
+
/* @__PURE__ */ jsx(Heading, { f, children: f.t.changePassword }),
|
|
2328
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
2131
2329
|
/* @__PURE__ */ jsx(Field, { f, name: "password", type: "password", label: f.t.currentPassword, value: password, autoComplete: "current-password", required: true, onChange: setPassword }),
|
|
2132
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 }),
|
|
2133
2331
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.changePassword }),
|
|
2134
|
-
done && /* @__PURE__ */ jsx(
|
|
2332
|
+
done && /* @__PURE__ */ jsx(Say, { f, tone: "success", children: done })
|
|
2135
2333
|
] });
|
|
2136
2334
|
}
|
|
2137
2335
|
function SecondStepPart({ props, account, onChanged }) {
|
|
@@ -2155,6 +2353,7 @@ function SecondStepPart({ props, account, onChanged }) {
|
|
|
2155
2353
|
setPassword("");
|
|
2156
2354
|
setCodes(r.recoveryCodes);
|
|
2157
2355
|
onChanged(true);
|
|
2356
|
+
props.onSaved?.({ kind: "mfa.enabled" });
|
|
2158
2357
|
};
|
|
2159
2358
|
const turnOff = async (e) => {
|
|
2160
2359
|
e.preventDefault();
|
|
@@ -2163,32 +2362,35 @@ function SecondStepPart({ props, account, onChanged }) {
|
|
|
2163
2362
|
setPassword("");
|
|
2164
2363
|
setCodes(null);
|
|
2165
2364
|
onChanged(false);
|
|
2365
|
+
props.onSaved?.({ kind: "mfa.disabled" });
|
|
2166
2366
|
};
|
|
2167
2367
|
const renew = async () => {
|
|
2168
2368
|
const r = await run(() => auth.account.mfa.recoveryCodes({ password }));
|
|
2169
|
-
if (r.ok)
|
|
2369
|
+
if (!r.ok) return;
|
|
2370
|
+
setCodes(r.recoveryCodes);
|
|
2371
|
+
props.onSaved?.({ kind: "recovery_codes.regenerated" });
|
|
2170
2372
|
};
|
|
2171
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 });
|
|
2172
|
-
const shown = codes && /* @__PURE__ */ jsxs(
|
|
2173
|
-
/* @__PURE__ */ jsx(
|
|
2374
|
+
const shown = codes && /* @__PURE__ */ jsxs(Fragment2, { children: [
|
|
2375
|
+
/* @__PURE__ */ jsx(Note, { f, children: f.t.keepCodes }),
|
|
2174
2376
|
/* @__PURE__ */ jsx("ul", { className: f.cx("codes"), children: codes.map((c) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("code", { children: c }) }, c)) })
|
|
2175
2377
|
] });
|
|
2176
2378
|
if (setup) {
|
|
2177
2379
|
return /* @__PURE__ */ jsxs("form", { className: f.cx("section"), onSubmit: confirm, noValidate: true, children: [
|
|
2178
|
-
/* @__PURE__ */ jsx(
|
|
2179
|
-
/* @__PURE__ */ jsx(
|
|
2380
|
+
/* @__PURE__ */ jsx(Heading, { f, children: f.t.secondStep }),
|
|
2381
|
+
/* @__PURE__ */ jsx(Note, { f, children: f.t.addToApp }),
|
|
2180
2382
|
/* @__PURE__ */ jsx("code", { className: f.cx("secret"), children: setup.secret }),
|
|
2181
|
-
/* @__PURE__ */ jsx(
|
|
2182
|
-
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) }),
|
|
2183
2385
|
/* @__PURE__ */ jsx(Field, { f, name: "code", type: "text", label: f.t.code, value: code, autoComplete: "one-time-code", required: true, onChange: setCode }),
|
|
2184
2386
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.verify })
|
|
2185
2387
|
] });
|
|
2186
2388
|
}
|
|
2187
2389
|
return /* @__PURE__ */ jsxs("form", { className: f.cx("section"), onSubmit: account.mfaEnabled ? turnOff : start, noValidate: true, children: [
|
|
2188
|
-
/* @__PURE__ */ jsx(
|
|
2189
|
-
/* @__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 }),
|
|
2190
2392
|
shown,
|
|
2191
|
-
general && /* @__PURE__ */ jsx(
|
|
2393
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
2192
2394
|
passwordField,
|
|
2193
2395
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: account.mfaEnabled ? f.t.turnOff : f.t.turnOn }),
|
|
2194
2396
|
account.mfaEnabled && /* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("providerButton"), onClick: () => void renew(), children: f.t.newRecoveryCodes })
|
|
@@ -2226,6 +2428,7 @@ function PhonePart({ props, account, onChanged }) {
|
|
|
2226
2428
|
setPassword("");
|
|
2227
2429
|
if (r.recoveryCodes.length > 0) setCodes(r.recoveryCodes);
|
|
2228
2430
|
onChanged(true);
|
|
2431
|
+
props.onSaved?.({ kind: "phone.added", channel });
|
|
2229
2432
|
await load();
|
|
2230
2433
|
};
|
|
2231
2434
|
const remove = async (e) => {
|
|
@@ -2236,27 +2439,29 @@ function PhonePart({ props, account, onChanged }) {
|
|
|
2236
2439
|
await load();
|
|
2237
2440
|
const left = await auth.account.mfa.factors();
|
|
2238
2441
|
onChanged(Boolean(left?.totp));
|
|
2442
|
+
props.onSaved?.({ kind: "phone.removed" });
|
|
2239
2443
|
};
|
|
2240
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 });
|
|
2241
2445
|
if (sentTo) {
|
|
2242
2446
|
return /* @__PURE__ */ jsxs("form", { className: f.cx("section"), onSubmit: confirm, noValidate: true, children: [
|
|
2243
|
-
/* @__PURE__ */ jsx(
|
|
2244
|
-
/* @__PURE__ */ jsx(
|
|
2245
|
-
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) }),
|
|
2246
2450
|
/* @__PURE__ */ jsx(Field, { f, name: "code", type: "text", label: f.t.code, value: code, autoComplete: "one-time-code", required: true, onChange: setCode }),
|
|
2247
2451
|
/* @__PURE__ */ jsx(f.Button, { type: "submit", disabled: f.busy, className: f.cx("button"), children: f.t.verify })
|
|
2248
2452
|
] });
|
|
2249
2453
|
}
|
|
2250
2454
|
return /* @__PURE__ */ jsxs("form", { className: f.cx("section"), onSubmit: ways.phone ? remove : add, noValidate: true, children: [
|
|
2251
|
-
/* @__PURE__ */ jsx(
|
|
2252
|
-
/* @__PURE__ */ jsx(
|
|
2253
|
-
codes && /* @__PURE__ */ jsxs(
|
|
2254
|
-
/* @__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 }),
|
|
2255
2459
|
/* @__PURE__ */ jsx("ul", { className: f.cx("codes"), children: codes.map((c) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("code", { children: c }) }, c)) })
|
|
2256
2460
|
] }),
|
|
2257
|
-
general && /* @__PURE__ */ jsx(
|
|
2461
|
+
general && /* @__PURE__ */ jsx(Say, { f, tone: "danger", children: f.say(general) }),
|
|
2258
2462
|
!ways.phone && /* @__PURE__ */ jsx(Field, { f, name: "phone", type: "tel", label: f.t.phone, value: number, autoComplete: "tel", required: true, onChange: setNumber }),
|
|
2259
|
-
!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: [
|
|
2260
2465
|
/* @__PURE__ */ jsx("input", { type: "radio", name: "channel", value: c, checked: channel === c, onChange: () => setChannel(c) }),
|
|
2261
2466
|
" ",
|
|
2262
2467
|
c === "whatsapp" ? f.t.byWhatsapp : f.t.bySms
|
|
@@ -2275,12 +2480,14 @@ function AgentsPart({ props, when }) {
|
|
|
2275
2480
|
if (list.length === 0) return null;
|
|
2276
2481
|
const disconnect = async (id) => {
|
|
2277
2482
|
const r = await run(() => auth.account.disconnectAgent(id));
|
|
2278
|
-
if (r.ok)
|
|
2483
|
+
if (!r.ok) return;
|
|
2484
|
+
setList(list.filter((a) => a.id !== id));
|
|
2485
|
+
props.onSaved?.({ kind: "agent.disconnected", id });
|
|
2279
2486
|
};
|
|
2280
2487
|
return /* @__PURE__ */ jsxs("section", { className: f.cx("section"), children: [
|
|
2281
|
-
/* @__PURE__ */ jsx(
|
|
2282
|
-
/* @__PURE__ */ jsx(
|
|
2283
|
-
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) }),
|
|
2284
2491
|
/* @__PURE__ */ jsx("ul", { className: f.cx("sessions"), children: list.map((a) => /* @__PURE__ */ jsxs("li", { className: f.cx("session"), children: [
|
|
2285
2492
|
a.name || f.t.anAgent,
|
|
2286
2493
|
a.redirectHost ? ` (${a.redirectHost})` : "",
|
|
@@ -2294,20 +2501,47 @@ function AgentsPart({ props, when }) {
|
|
|
2294
2501
|
] }, a.id)) })
|
|
2295
2502
|
] });
|
|
2296
2503
|
}
|
|
2297
|
-
function
|
|
2504
|
+
function SessionsPart({ props, when }) {
|
|
2298
2505
|
const auth = useAuth();
|
|
2299
2506
|
const { f, run, general } = useSection(props);
|
|
2507
|
+
const [sessions, setSessions] = useState([]);
|
|
2508
|
+
useEffect(() => {
|
|
2509
|
+
void auth.account.sessions().then(setSessions);
|
|
2510
|
+
}, []);
|
|
2300
2511
|
const end = async () => {
|
|
2301
2512
|
const r = await run(() => auth.account.signOutEverywhere());
|
|
2302
2513
|
if (!r.ok) return;
|
|
2514
|
+
props.onSaved?.({ kind: "sessions.ended" });
|
|
2303
2515
|
if (props.onSignedOut) props.onSignedOut();
|
|
2304
2516
|
else window.location.assign("/");
|
|
2305
2517
|
};
|
|
2306
|
-
return /* @__PURE__ */ jsxs(
|
|
2307
|
-
|
|
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) }),
|
|
2308
2528
|
/* @__PURE__ */ jsx(f.Button, { type: "button", disabled: f.busy, className: f.cx("button"), onClick: () => void end(), children: f.t.signOutEverywhere })
|
|
2309
2529
|
] });
|
|
2310
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
|
+
}
|
|
2311
2545
|
|
|
2312
2546
|
// src/react.tsx
|
|
2313
2547
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
@@ -2430,10 +2664,20 @@ function useAuth() {
|
|
|
2430
2664
|
export {
|
|
2431
2665
|
AcceptInvite,
|
|
2432
2666
|
Account,
|
|
2667
|
+
AccountAgents,
|
|
2668
|
+
AccountEmail,
|
|
2669
|
+
AccountLinked,
|
|
2670
|
+
AccountPasskeys,
|
|
2671
|
+
AccountPassword,
|
|
2672
|
+
AccountPhone,
|
|
2673
|
+
AccountProfile,
|
|
2674
|
+
AccountSecondStep,
|
|
2675
|
+
AccountSessions,
|
|
2433
2676
|
CauthyProvider,
|
|
2434
2677
|
ForgotPassword,
|
|
2435
2678
|
GoogleOneTap,
|
|
2436
2679
|
OrganizationMembers,
|
|
2680
|
+
PendingTerms,
|
|
2437
2681
|
ResetPassword,
|
|
2438
2682
|
SignIn,
|
|
2439
2683
|
SignUp,
|