@protobase/ui 0.15.5 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/account/two-factor-setup.js +6 -5
- package/dist/app/app.js +1 -1
- package/dist/app/create/create-page.js +1 -0
- package/dist/app/create/create-record-form.js +1 -0
- package/dist/app/displays/map-display.js +50 -34
- package/dist/app/displays/map-groups.js +12 -3
- package/dist/app/displays/measured-heights.js +23 -0
- package/dist/app/displays/record-card.js +2 -2
- package/dist/app/displays/virtual-cards.js +12 -14
- package/dist/app/field-editor.js +9 -1
- package/dist/app/list-page.js +1 -1
- package/dist/app/map/approximate-position.js +76 -0
- package/dist/app/map/area-features.js +80 -0
- package/dist/app/map/maplibre.js +11 -0
- package/dist/app/map/position-areas.js +78 -0
- package/dist/app/map/record-map.js +2 -7
- package/dist/app/map/record-position.js +5 -4
- package/dist/app/map/records-map.js +24 -7
- package/dist/app/map/theme-color.js +23 -0
- package/dist/app/nav-recent.js +1 -1
- package/dist/app/pages/blocks/card-frame.js +2 -2
- package/dist/app/pages/blocks/grid.js +10 -2
- package/dist/app/pages/blocks/link.js +1 -1
- package/dist/app/pages/blocks/stat.js +9 -5
- package/dist/app/pages/field-value.js +1 -1
- package/dist/app/record-page.js +5 -1
- package/dist/app/router.js +7 -8
- package/dist/app/saved/saved-records.js +1 -1
- package/dist/app/search/search-model.js +1 -1
- package/dist/app/searches/use-save-search.js +4 -3
- package/dist/app/use-record-editor.js +5 -3
- package/dist/app-shell/app-shell.d.ts +1 -0
- package/dist/app-shell/app-shell.js +4 -3
- package/dist/app-shell/page-scroll.js +17 -1
- package/dist/app-shell/sidebar.d.ts +1 -0
- package/dist/app-shell/sidebar.js +4 -4
- package/dist/app-shell/top-bar.js +4 -4
- package/dist/auth/auth-gate.js +18 -9
- package/dist/auth/auth-provider.js +1 -0
- package/dist/auth/code-form.js +77 -0
- package/dist/auth/email-code-form.js +18 -77
- package/dist/auth/forgot-password-form.js +10 -10
- package/dist/auth/forgot-password-page.js +2 -2
- package/dist/auth/resend-code-button.js +29 -0
- package/dist/auth/sign-in-form.js +7 -8
- package/dist/auth/sign-in-page.js +3 -3
- package/dist/auth/sign-in-prompt.js +13 -9
- package/dist/auth/sign-up-code-form.js +22 -0
- package/dist/auth/sign-up-details-form.js +81 -111
- package/dist/auth/sign-up-page.js +17 -8
- package/dist/auth/two-factor-form.js +3 -3
- package/dist/auth/use-sign-in-address.js +21 -8
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/lib/flip-guard.js +43 -0
- package/dist/lib/page-scroll-lock.js +20 -0
- package/dist/lib/use-focus-trap.js +4 -4
- package/dist/organizations/invitation-page.js +7 -6
- package/dist/package.js +1 -1
- package/dist/primitives/otp-input.d.ts +21 -0
- package/dist/primitives/otp-input.js +117 -0
- package/dist/primitives/otp-value.js +23 -0
- package/dist/primitives/route-link.d.ts +1 -0
- package/dist/primitives/route-link.js +20 -0
- package/dist/primitives/textarea.js +36 -0
- package/dist/record-view/field.js +56 -53
- package/dist/shell/assets/app-DJAZP1yB.js +66 -0
- package/dist/shell/assets/index-C5pYkUfv.css +2 -0
- package/dist/shell/assets/{index-DxmdRnr8.js → index-LBhMBiK4.js} +1 -1
- package/dist/shell/assets/maplibre-Dy0ZTnFZ.js +814 -0
- package/dist/shell/assets/record-map-BiWSbqqT.js +1 -0
- package/dist/shell/assets/records-map-DabYc3ad.js +1 -0
- package/dist/shell/assets/shared-protobase-ui-BURelnPG.js +1 -0
- package/dist/shell/index.html +4 -4
- package/dist/shell/protobase.shell.json +1 -1
- package/dist/styles.css +15 -0
- package/dist/toasts/toast.js +22 -6
- package/package.json +4 -4
- package/dist/auth/code-input.js +0 -17
- package/dist/auth/sign-in-address.js +0 -47
- package/dist/shell/assets/app-BdEV1_xI.js +0 -66
- package/dist/shell/assets/index-ibaHR5wQ.css +0 -2
- package/dist/shell/assets/maplibre-gl-DFcSGTFJ.js +0 -1
- package/dist/shell/assets/record-map-CL9bBLic.js +0 -814
- package/dist/shell/assets/records-map-DgtD0cK5.js +0 -1
- package/dist/shell/assets/shared-protobase-ui-ibIDwOpE.js +0 -1
- /package/dist/shell/assets/{record-map-DBE96hFo.css → maplibre-DBE96hFo.css} +0 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { Button } from "../primitives/button.js";
|
|
2
|
+
import { OtpInput } from "../primitives/otp-input.js";
|
|
3
|
+
import { AuthLayout } from "./auth-layout.js";
|
|
4
|
+
import { ResendCodeButton } from "./resend-code-button.js";
|
|
5
|
+
import { useState } from "react";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
//#region src/auth/code-form.tsx
|
|
8
|
+
/**
|
|
9
|
+
* A step that checks an emailed code on its own: where it went, a box per digit, a new code after a wait, and a way back
|
|
10
|
+
* to another address. Nothing else is asked for until the code is right.
|
|
11
|
+
*/
|
|
12
|
+
const CodeForm = ({ title, description, explanation, submitLabel, onSubmit, onResend, onChangeAddress, changeAddressLabel, busy, error, notice, resendCooldown }) => {
|
|
13
|
+
const [code, setCode] = useState("");
|
|
14
|
+
return /* @__PURE__ */ jsxs(AuthLayout, {
|
|
15
|
+
title,
|
|
16
|
+
description,
|
|
17
|
+
children: [
|
|
18
|
+
/* @__PURE__ */ jsx("p", {
|
|
19
|
+
className: "mb-4 text-[13px] text-muted-foreground",
|
|
20
|
+
children: explanation
|
|
21
|
+
}),
|
|
22
|
+
notice && /* @__PURE__ */ jsx("p", {
|
|
23
|
+
role: "status",
|
|
24
|
+
className: "mb-4 rounded-md bg-success-soft px-3 py-2 text-xs font-medium text-success-text",
|
|
25
|
+
children: notice
|
|
26
|
+
}),
|
|
27
|
+
/* @__PURE__ */ jsxs("form", {
|
|
28
|
+
className: "flex flex-col gap-4",
|
|
29
|
+
onSubmit: (event) => {
|
|
30
|
+
event.preventDefault();
|
|
31
|
+
onSubmit(code);
|
|
32
|
+
},
|
|
33
|
+
children: [
|
|
34
|
+
/* @__PURE__ */ jsxs("label", {
|
|
35
|
+
className: "flex flex-col gap-1.5 text-[13px] font-medium",
|
|
36
|
+
children: ["Code", /* @__PURE__ */ jsx(OtpInput, {
|
|
37
|
+
name: "code",
|
|
38
|
+
required: true,
|
|
39
|
+
autoFocus: true,
|
|
40
|
+
value: code,
|
|
41
|
+
invalid: Boolean(error),
|
|
42
|
+
onChange: setCode,
|
|
43
|
+
onComplete: (complete) => !busy && onSubmit(complete)
|
|
44
|
+
})]
|
|
45
|
+
}),
|
|
46
|
+
error && /* @__PURE__ */ jsx("p", {
|
|
47
|
+
role: "alert",
|
|
48
|
+
className: "text-xs font-medium text-danger-text",
|
|
49
|
+
children: error
|
|
50
|
+
}),
|
|
51
|
+
/* @__PURE__ */ jsx(Button, {
|
|
52
|
+
variant: "primary",
|
|
53
|
+
type: "submit",
|
|
54
|
+
loading: busy,
|
|
55
|
+
className: "min-h-10",
|
|
56
|
+
children: submitLabel
|
|
57
|
+
}),
|
|
58
|
+
/* @__PURE__ */ jsxs("div", {
|
|
59
|
+
className: "flex flex-wrap justify-center gap-x-2 sm:justify-between",
|
|
60
|
+
children: [/* @__PURE__ */ jsx(Button, {
|
|
61
|
+
variant: "ghost",
|
|
62
|
+
onClick: onChangeAddress,
|
|
63
|
+
className: "min-h-10",
|
|
64
|
+
children: changeAddressLabel
|
|
65
|
+
}), /* @__PURE__ */ jsx(ResendCodeButton, {
|
|
66
|
+
onResend,
|
|
67
|
+
disabled: busy,
|
|
68
|
+
cooldown: resendCooldown
|
|
69
|
+
})]
|
|
70
|
+
})
|
|
71
|
+
]
|
|
72
|
+
})
|
|
73
|
+
]
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
//#endregion
|
|
77
|
+
export { CodeForm };
|
|
@@ -1,81 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { AuthLayout } from "./auth-layout.js";
|
|
4
|
-
import { useState } from "react";
|
|
5
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { CodeForm } from "./code-form.js";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
3
|
//#region src/auth/email-code-form.tsx
|
|
7
4
|
/** The second half of signing in with an emailed code: the code from the email. */
|
|
8
|
-
const EmailCodeForm = ({ email,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}),
|
|
25
|
-
notice && /* @__PURE__ */ jsx("p", {
|
|
26
|
-
role: "status",
|
|
27
|
-
className: "mb-4 rounded-md bg-success-soft px-3 py-2 text-xs font-medium text-success-text",
|
|
28
|
-
children: notice
|
|
29
|
-
}),
|
|
30
|
-
/* @__PURE__ */ jsxs("form", {
|
|
31
|
-
className: "flex flex-col gap-4",
|
|
32
|
-
onSubmit: (event) => {
|
|
33
|
-
event.preventDefault();
|
|
34
|
-
onSubmit(code.trim());
|
|
35
|
-
},
|
|
36
|
-
children: [
|
|
37
|
-
/* @__PURE__ */ jsxs("label", {
|
|
38
|
-
className: "flex flex-col gap-1.5 text-[13px] font-medium",
|
|
39
|
-
children: ["Code", /* @__PURE__ */ jsx(CodeInput, {
|
|
40
|
-
name: "code",
|
|
41
|
-
required: true,
|
|
42
|
-
autoFocus: true,
|
|
43
|
-
value: code,
|
|
44
|
-
invalid: Boolean(error),
|
|
45
|
-
onChange: (event) => setCode(event.target.value)
|
|
46
|
-
})]
|
|
47
|
-
}),
|
|
48
|
-
error && /* @__PURE__ */ jsx("p", {
|
|
49
|
-
role: "alert",
|
|
50
|
-
className: "text-xs font-medium text-danger-text",
|
|
51
|
-
children: error
|
|
52
|
-
}),
|
|
53
|
-
/* @__PURE__ */ jsx(Button, {
|
|
54
|
-
variant: "primary",
|
|
55
|
-
type: "submit",
|
|
56
|
-
loading: busy,
|
|
57
|
-
className: "min-h-10",
|
|
58
|
-
children: "Sign in"
|
|
59
|
-
}),
|
|
60
|
-
/* @__PURE__ */ jsxs("div", {
|
|
61
|
-
className: "flex justify-between gap-2",
|
|
62
|
-
children: [/* @__PURE__ */ jsx(Button, {
|
|
63
|
-
variant: "ghost",
|
|
64
|
-
onClick: onBack,
|
|
65
|
-
className: "min-h-10",
|
|
66
|
-
children: "Back to sign in"
|
|
67
|
-
}), /* @__PURE__ */ jsx(Button, {
|
|
68
|
-
variant: "ghost",
|
|
69
|
-
onClick: onResend,
|
|
70
|
-
disabled: busy,
|
|
71
|
-
className: "min-h-10",
|
|
72
|
-
children: "Send a new code"
|
|
73
|
-
})]
|
|
74
|
-
})
|
|
75
|
-
]
|
|
76
|
-
})
|
|
77
|
-
]
|
|
78
|
-
});
|
|
79
|
-
};
|
|
5
|
+
const EmailCodeForm = ({ email, onBack, ...rest }) => /* @__PURE__ */ jsx(CodeForm, {
|
|
6
|
+
title: "Check your email",
|
|
7
|
+
description: "Enter the code we sent to sign in.",
|
|
8
|
+
explanation: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
9
|
+
"If ",
|
|
10
|
+
/* @__PURE__ */ jsx("span", {
|
|
11
|
+
className: "font-medium text-foreground",
|
|
12
|
+
children: email
|
|
13
|
+
}),
|
|
14
|
+
" has an account, a 6-digit code is on its way. It works for 5 minutes, once."
|
|
15
|
+
] }),
|
|
16
|
+
submitLabel: "Sign in",
|
|
17
|
+
onChangeAddress: onBack,
|
|
18
|
+
changeAddressLabel: "Back to sign in",
|
|
19
|
+
...rest
|
|
20
|
+
});
|
|
80
21
|
//#endregion
|
|
81
22
|
export { EmailCodeForm };
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import { cn } from "../lib/cn.js";
|
|
2
|
+
import { RouteLink } from "../primitives/route-link.js";
|
|
1
3
|
import { Input } from "../primitives/input.js";
|
|
2
|
-
import { Button } from "../primitives/button.js";
|
|
4
|
+
import { Button, buttonClass } from "../primitives/button.js";
|
|
3
5
|
import { AuthLayout } from "./auth-layout.js";
|
|
4
6
|
import { useState } from "react";
|
|
5
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
8
|
//#region src/auth/forgot-password-form.tsx
|
|
7
|
-
const ForgotPasswordForm = ({ onSubmit,
|
|
9
|
+
const ForgotPasswordForm = ({ onSubmit, back, busy, error, sentTo }) => {
|
|
8
10
|
const [email, setEmail] = useState("");
|
|
9
11
|
if (sentTo) return /* @__PURE__ */ jsxs(AuthLayout, {
|
|
10
12
|
title: "Check your email",
|
|
@@ -18,10 +20,9 @@ const ForgotPasswordForm = ({ onSubmit, onBack, busy, error, sentTo }) => {
|
|
|
18
20
|
}),
|
|
19
21
|
" has an account, an email with a link to choose a new password is on its way. The link works once, for a limited time."
|
|
20
22
|
]
|
|
21
|
-
}), /* @__PURE__ */ jsx(
|
|
22
|
-
|
|
23
|
-
className: "mt-4 min-h-10 w-full",
|
|
24
|
-
onClick: onBack,
|
|
23
|
+
}), /* @__PURE__ */ jsx(RouteLink, {
|
|
24
|
+
to: back,
|
|
25
|
+
className: cn(buttonClass({ variant: "primary" }), "mt-4 min-h-10 w-full"),
|
|
25
26
|
children: "Back to sign in"
|
|
26
27
|
})]
|
|
27
28
|
});
|
|
@@ -61,10 +62,9 @@ const ForgotPasswordForm = ({ onSubmit, onBack, busy, error, sentTo }) => {
|
|
|
61
62
|
className: "min-h-10",
|
|
62
63
|
children: "Send reset link"
|
|
63
64
|
}),
|
|
64
|
-
/* @__PURE__ */ jsx(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
className: "min-h-10",
|
|
65
|
+
/* @__PURE__ */ jsx(RouteLink, {
|
|
66
|
+
to: back,
|
|
67
|
+
className: cn(buttonClass({ variant: "ghost" }), "min-h-10"),
|
|
68
68
|
children: "Back to sign in"
|
|
69
69
|
})
|
|
70
70
|
]
|
|
@@ -6,7 +6,7 @@ import { AuthError } from "@protobase/client";
|
|
|
6
6
|
import { jsx } from "react/jsx-runtime";
|
|
7
7
|
//#region src/auth/forgot-password-page.tsx
|
|
8
8
|
/** Asks the server to email a reset link that leads back to this page. */
|
|
9
|
-
const ForgotPasswordPage = ({
|
|
9
|
+
const ForgotPasswordPage = ({ back }) => {
|
|
10
10
|
const { session } = useAuth();
|
|
11
11
|
const [busy, setBusy] = useState(false);
|
|
12
12
|
const [error, setError] = useState();
|
|
@@ -27,7 +27,7 @@ const ForgotPasswordPage = ({ onBack }) => {
|
|
|
27
27
|
busy,
|
|
28
28
|
error,
|
|
29
29
|
sentTo,
|
|
30
|
-
|
|
30
|
+
back,
|
|
31
31
|
onSubmit: (email) => void submit(email)
|
|
32
32
|
});
|
|
33
33
|
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Button } from "../primitives/button.js";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
//#region src/auth/resend-code-button.tsx
|
|
5
|
+
/** "Send a new code", counting down first: the screen opens right after a code went out, and so does every resend. */
|
|
6
|
+
const ResendCodeButton = ({ onResend, cooldown = 30, disabled }) => {
|
|
7
|
+
const [until, setUntil] = useState(() => Date.now() + cooldown * 1e3);
|
|
8
|
+
const [now, setNow] = useState(() => Date.now());
|
|
9
|
+
const left = Math.max(0, Math.ceil((until - now) / 1e3));
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (left === 0) return;
|
|
12
|
+
const timer = setInterval(() => setNow(Date.now()), 1e3);
|
|
13
|
+
return () => clearInterval(timer);
|
|
14
|
+
}, [left]);
|
|
15
|
+
return /* @__PURE__ */ jsx(Button, {
|
|
16
|
+
variant: "ghost",
|
|
17
|
+
disabled: disabled || left > 0,
|
|
18
|
+
onClick: () => {
|
|
19
|
+
const sent = Date.now();
|
|
20
|
+
setUntil(sent + cooldown * 1e3);
|
|
21
|
+
setNow(sent);
|
|
22
|
+
onResend();
|
|
23
|
+
},
|
|
24
|
+
className: "min-h-10",
|
|
25
|
+
children: left > 0 ? `Send a new code in ${left}s` : "Send a new code"
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
//#endregion
|
|
29
|
+
export { ResendCodeButton };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { RouteLink } from "../primitives/route-link.js";
|
|
1
2
|
import { Input } from "../primitives/input.js";
|
|
2
3
|
import { Button } from "../primitives/button.js";
|
|
3
4
|
import { AuthLayout } from "./auth-layout.js";
|
|
@@ -14,7 +15,7 @@ const Divider = () => /* @__PURE__ */ jsxs("div", {
|
|
|
14
15
|
/* @__PURE__ */ jsx("span", { className: "h-px flex-1 bg-border" })
|
|
15
16
|
]
|
|
16
17
|
});
|
|
17
|
-
const SignInForm = ({ onSubmit, busy, error, workspace, notice, methods = ["password"], onSendCode, onPasskey, passkeyDomains = [],
|
|
18
|
+
const SignInForm = ({ onSubmit, busy, error, workspace, notice, methods = ["password"], onSendCode, onPasskey, passkeyDomains = [], forgotPassword, providers = [], onContinueWith, signUp, onBrowse }) => {
|
|
18
19
|
const [email, setEmail] = useState("");
|
|
19
20
|
const [password, setPassword] = useState("");
|
|
20
21
|
const emailInput = useRef(null);
|
|
@@ -125,22 +126,20 @@ const SignInForm = ({ onSubmit, busy, error, workspace, notice, methods = ["pass
|
|
|
125
126
|
className: "min-h-10",
|
|
126
127
|
children: [/* @__PURE__ */ jsx(Mail, { className: "size-4" }), "Email me a sign-in code"]
|
|
127
128
|
}),
|
|
128
|
-
withPassword &&
|
|
129
|
-
|
|
130
|
-
onClick: onForgotPassword,
|
|
129
|
+
withPassword && forgotPassword && /* @__PURE__ */ jsx(RouteLink, {
|
|
130
|
+
to: forgotPassword,
|
|
131
131
|
className: "self-center text-[13px] font-medium text-primary-text hover:underline",
|
|
132
132
|
children: "Forgot password?"
|
|
133
133
|
})
|
|
134
134
|
]
|
|
135
135
|
}),
|
|
136
|
-
|
|
136
|
+
signUp && /* @__PURE__ */ jsxs("p", {
|
|
137
137
|
className: "mt-4 text-center text-[13px] text-muted-foreground",
|
|
138
138
|
children: [
|
|
139
139
|
"New here?",
|
|
140
140
|
" ",
|
|
141
|
-
/* @__PURE__ */ jsx(
|
|
142
|
-
|
|
143
|
-
onClick: onSignUp,
|
|
141
|
+
/* @__PURE__ */ jsx(RouteLink, {
|
|
142
|
+
to: signUp,
|
|
144
143
|
className: "font-medium text-primary-text hover:underline",
|
|
145
144
|
children: "Create an account"
|
|
146
145
|
})
|
|
@@ -5,7 +5,7 @@ import { useState } from "react";
|
|
|
5
5
|
import { AuthError } from "@protobase/client";
|
|
6
6
|
import { jsx } from "react/jsx-runtime";
|
|
7
7
|
//#region src/auth/sign-in-page.tsx
|
|
8
|
-
const SignInPage = ({ workspace, notice,
|
|
8
|
+
const SignInPage = ({ workspace, notice, forgotPassword, signUp, onBrowse, onCodeSent, error: initialError }) => {
|
|
9
9
|
const { signIn, signInSocial, signInProviders, signInMethods, passkeyDomains, sendSignInCode, signInWithPasskey } = useAuth();
|
|
10
10
|
const [busy, setBusy] = useState(false);
|
|
11
11
|
const [error, setError] = useState(initialError);
|
|
@@ -26,8 +26,8 @@ const SignInPage = ({ workspace, notice, onForgotPassword, onSignUp, onBrowse, o
|
|
|
26
26
|
workspace,
|
|
27
27
|
notice,
|
|
28
28
|
methods: signInMethods,
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
forgotPassword,
|
|
30
|
+
signUp,
|
|
31
31
|
onBrowse,
|
|
32
32
|
providers: signInProviders,
|
|
33
33
|
onContinueWith: (provider) => void attempt(() => signInSocial(provider), signInMessage),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { RouteLink } from "../primitives/route-link.js";
|
|
1
2
|
import { useAuth } from "./auth-provider.js";
|
|
2
3
|
import { Button, buttonClass } from "../primitives/button.js";
|
|
3
4
|
import { useSignInAddress } from "./use-sign-in-address.js";
|
|
@@ -19,21 +20,24 @@ const Benefits = ({ benefits }) => benefits && benefits.length > 0 ? /* @__PURE_
|
|
|
19
20
|
}) : null;
|
|
20
21
|
const Actions = ({ prompt }) => {
|
|
21
22
|
const { canSignUp } = useAuth();
|
|
22
|
-
const {
|
|
23
|
-
|
|
23
|
+
const { link } = useSignInAddress();
|
|
24
|
+
const primary = buttonClass({ variant: "primary" });
|
|
25
|
+
const signUp = prompt.signUp ? /* @__PURE__ */ jsx("a", {
|
|
24
26
|
href: prompt.signUp.href,
|
|
25
27
|
target: "_blank",
|
|
26
28
|
rel: "noreferrer",
|
|
27
|
-
className:
|
|
29
|
+
className: primary,
|
|
28
30
|
children: prompt.signUp.label
|
|
29
|
-
}) : canSignUp && /* @__PURE__ */ jsx(
|
|
30
|
-
|
|
31
|
+
}) : canSignUp && /* @__PURE__ */ jsx(RouteLink, {
|
|
32
|
+
to: link("sign-up"),
|
|
33
|
+
className: primary,
|
|
31
34
|
children: "Create an account"
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
});
|
|
36
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(RouteLink, {
|
|
37
|
+
to: link(),
|
|
38
|
+
className: signUp ? buttonClass() : primary,
|
|
35
39
|
children: "Sign in"
|
|
36
|
-
})] });
|
|
40
|
+
}), signUp] });
|
|
37
41
|
};
|
|
38
42
|
/**
|
|
39
43
|
* What a visitor who is not signed in is told about something they could use once signed in: the prompt's title, what
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { CodeForm } from "./code-form.js";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
//#region src/auth/sign-up-code-form.tsx
|
|
4
|
+
/** The second step of making an account: the emailed code on its own, before the name and password. */
|
|
5
|
+
const SignUpCodeForm = ({ email, onBack, ...rest }) => /* @__PURE__ */ jsx(CodeForm, {
|
|
6
|
+
title: "Check your email",
|
|
7
|
+
description: "Enter the code we sent to create your account.",
|
|
8
|
+
explanation: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
9
|
+
"A 6-digit code is on its way to ",
|
|
10
|
+
/* @__PURE__ */ jsx("span", {
|
|
11
|
+
className: "font-medium text-foreground",
|
|
12
|
+
children: email
|
|
13
|
+
}),
|
|
14
|
+
". It works for 5 minutes, once. If the address has an account already, the email says so instead."
|
|
15
|
+
] }),
|
|
16
|
+
submitLabel: "Continue",
|
|
17
|
+
onChangeAddress: onBack,
|
|
18
|
+
changeAddressLabel: "Use another address",
|
|
19
|
+
...rest
|
|
20
|
+
});
|
|
21
|
+
//#endregion
|
|
22
|
+
export { SignUpCodeForm };
|
|
@@ -1,129 +1,99 @@
|
|
|
1
1
|
import { Input } from "../primitives/input.js";
|
|
2
2
|
import { Button } from "../primitives/button.js";
|
|
3
|
-
import { CodeInput } from "./code-input.js";
|
|
4
3
|
import { AuthLayout } from "./auth-layout.js";
|
|
5
4
|
import { useId, useState } from "react";
|
|
6
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
6
|
//#region src/auth/sign-up-details-form.tsx
|
|
8
|
-
/** The
|
|
9
|
-
const SignUpDetailsForm = ({ email, onSubmit,
|
|
10
|
-
const [code, setCode] = useState("");
|
|
7
|
+
/** The last step of making an account, once the emailed code was right: the person's name and how they will sign in. */
|
|
8
|
+
const SignUpDetailsForm = ({ email, onSubmit, onBack, methods, busy, error }) => {
|
|
11
9
|
const [name, setName] = useState("");
|
|
12
10
|
const [password, setPassword] = useState("");
|
|
13
11
|
const passwordHint = useId();
|
|
14
12
|
const withPassword = methods.includes("password");
|
|
15
13
|
const passwordOptional = methods.includes("emailCode");
|
|
16
14
|
return /* @__PURE__ */ jsxs(AuthLayout, {
|
|
17
|
-
title: "
|
|
18
|
-
description: "
|
|
19
|
-
children: [
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
name: name
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
15
|
+
title: "Your details",
|
|
16
|
+
description: "One last step to create your account.",
|
|
17
|
+
children: [/* @__PURE__ */ jsxs("p", {
|
|
18
|
+
className: "mb-4 text-[13px] text-muted-foreground",
|
|
19
|
+
children: [
|
|
20
|
+
"The code was right: the account is for ",
|
|
21
|
+
/* @__PURE__ */ jsx("span", {
|
|
22
|
+
className: "font-medium text-foreground",
|
|
23
|
+
children: email
|
|
24
|
+
}),
|
|
25
|
+
"."
|
|
26
|
+
]
|
|
27
|
+
}), /* @__PURE__ */ jsxs("form", {
|
|
28
|
+
className: "flex flex-col gap-4",
|
|
29
|
+
onSubmit: (event) => {
|
|
30
|
+
event.preventDefault();
|
|
31
|
+
onSubmit({
|
|
32
|
+
name: name.trim(),
|
|
33
|
+
...withPassword && password && { password }
|
|
34
|
+
});
|
|
35
|
+
},
|
|
36
|
+
children: [
|
|
37
|
+
/* @__PURE__ */ jsxs("label", {
|
|
38
|
+
className: "flex flex-col gap-1.5 text-[13px] font-medium",
|
|
39
|
+
children: ["Your name", /* @__PURE__ */ jsx(Input, {
|
|
40
|
+
name: "name",
|
|
41
|
+
autoComplete: "name",
|
|
42
|
+
required: true,
|
|
43
|
+
autoFocus: true,
|
|
44
|
+
maxLength: 200,
|
|
45
|
+
value: name,
|
|
46
|
+
onChange: (event) => setName(event.target.value),
|
|
47
|
+
className: "min-h-6"
|
|
48
|
+
})]
|
|
49
|
+
}),
|
|
50
|
+
withPassword && /* @__PURE__ */ jsxs("div", {
|
|
51
|
+
className: "flex flex-col gap-1.5",
|
|
52
|
+
children: [/* @__PURE__ */ jsxs("label", {
|
|
48
53
|
className: "flex flex-col gap-1.5 text-[13px] font-medium",
|
|
49
|
-
children: ["
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
className: "flex flex-col gap-1.5 text-[13px] font-medium",
|
|
60
|
-
children: ["Your name", /* @__PURE__ */ jsx(Input, {
|
|
61
|
-
name: "name",
|
|
62
|
-
autoComplete: "name",
|
|
63
|
-
required: true,
|
|
64
|
-
maxLength: 200,
|
|
65
|
-
value: name,
|
|
66
|
-
onChange: (event) => setName(event.target.value),
|
|
54
|
+
children: [passwordOptional ? "Password (optional)" : "Password", /* @__PURE__ */ jsx(Input, {
|
|
55
|
+
type: "password",
|
|
56
|
+
name: "password",
|
|
57
|
+
autoComplete: "new-password",
|
|
58
|
+
"aria-describedby": passwordHint,
|
|
59
|
+
required: !passwordOptional,
|
|
60
|
+
minLength: 12,
|
|
61
|
+
maxLength: 128,
|
|
62
|
+
value: password,
|
|
63
|
+
onChange: (event) => setPassword(event.target.value),
|
|
67
64
|
className: "min-h-6"
|
|
68
65
|
})]
|
|
69
|
-
}),
|
|
70
|
-
|
|
71
|
-
className: "
|
|
72
|
-
children: [
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
children: error
|
|
101
|
-
}),
|
|
102
|
-
/* @__PURE__ */ jsx(Button, {
|
|
103
|
-
variant: "primary",
|
|
104
|
-
type: "submit",
|
|
105
|
-
loading: busy,
|
|
106
|
-
className: "min-h-10",
|
|
107
|
-
children: "Create account"
|
|
108
|
-
}),
|
|
109
|
-
/* @__PURE__ */ jsxs("div", {
|
|
110
|
-
className: "flex justify-between gap-2",
|
|
111
|
-
children: [/* @__PURE__ */ jsx(Button, {
|
|
112
|
-
variant: "ghost",
|
|
113
|
-
onClick: onBack,
|
|
114
|
-
className: "min-h-10",
|
|
115
|
-
children: "Use another address"
|
|
116
|
-
}), /* @__PURE__ */ jsx(Button, {
|
|
117
|
-
variant: "ghost",
|
|
118
|
-
onClick: onResend,
|
|
119
|
-
disabled: busy,
|
|
120
|
-
className: "min-h-10",
|
|
121
|
-
children: "Send a new code"
|
|
122
|
-
})]
|
|
123
|
-
})
|
|
124
|
-
]
|
|
125
|
-
})
|
|
126
|
-
]
|
|
66
|
+
}), /* @__PURE__ */ jsxs("p", {
|
|
67
|
+
id: passwordHint,
|
|
68
|
+
className: "text-xs text-muted-foreground",
|
|
69
|
+
children: [
|
|
70
|
+
"At least ",
|
|
71
|
+
12,
|
|
72
|
+
" characters.",
|
|
73
|
+
passwordOptional && " Without one, you sign in with a code we email you."
|
|
74
|
+
]
|
|
75
|
+
})]
|
|
76
|
+
}),
|
|
77
|
+
error && /* @__PURE__ */ jsx("p", {
|
|
78
|
+
role: "alert",
|
|
79
|
+
className: "text-xs font-medium text-danger-text",
|
|
80
|
+
children: error
|
|
81
|
+
}),
|
|
82
|
+
/* @__PURE__ */ jsx(Button, {
|
|
83
|
+
variant: "primary",
|
|
84
|
+
type: "submit",
|
|
85
|
+
loading: busy,
|
|
86
|
+
className: "min-h-10",
|
|
87
|
+
children: "Create account"
|
|
88
|
+
}),
|
|
89
|
+
/* @__PURE__ */ jsx(Button, {
|
|
90
|
+
variant: "ghost",
|
|
91
|
+
onClick: onBack,
|
|
92
|
+
className: "min-h-10",
|
|
93
|
+
children: "Use another address"
|
|
94
|
+
})
|
|
95
|
+
]
|
|
96
|
+
})]
|
|
127
97
|
});
|
|
128
98
|
};
|
|
129
99
|
//#endregion
|