@protobase/ui 0.14.6 → 0.14.7
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/auth/auth-gate.js +4 -1
- package/dist/auth/auth-provider.js +22 -2
- package/dist/auth/sign-in-form.js +14 -1
- package/dist/auth/sign-in-page.js +2 -1
- package/dist/auth/sign-in-prompt.d.ts +2 -1
- package/dist/auth/sign-in-prompt.js +7 -3
- package/dist/auth/sign-up-details-form.js +130 -0
- package/dist/auth/sign-up-email-form.js +74 -0
- package/dist/auth/sign-up-page.js +63 -0
- package/dist/package.js +1 -1
- package/dist/shell/assets/app-BCo2kC5x.js +66 -0
- package/dist/shell/assets/{index-BCqsBT_o.js → index-CeNa43oR.js} +1 -1
- package/dist/shell/assets/{maplibre-gl-CxevrnFA.js → maplibre-gl-cPRHcP5-.js} +1 -1
- package/dist/shell/assets/{record-map-Mn5aTqIF.js → record-map-CEX9WoXA.js} +2 -2
- package/dist/shell/assets/{records-map-BdPiGjmg.js → records-map-B3c6f2Lz.js} +1 -1
- package/dist/shell/assets/{shared-protobase-ui-CRhV6ipQ.js → shared-protobase-ui-C1Dht33B.js} +1 -1
- package/dist/shell/index.html +3 -3
- package/dist/shell/protobase.shell.json +1 -1
- package/package.json +4 -4
- package/dist/shell/assets/app-CYs0l-vz.js +0 -66
package/dist/auth/auth-gate.js
CHANGED
|
@@ -11,6 +11,7 @@ import { ProviderSignInPage } from "./provider-sign-in-page.js";
|
|
|
11
11
|
import { ResetPasswordPage } from "./reset-password-page.js";
|
|
12
12
|
import { SetupRequiredPage } from "./setup-required-page.js";
|
|
13
13
|
import { SignInPage } from "./sign-in-page.js";
|
|
14
|
+
import { SignUpPage } from "./sign-up-page.js";
|
|
14
15
|
import { readStaffLink, withoutStaffLink } from "./staff-link.js";
|
|
15
16
|
import { StaffSignInPage } from "./staff-sign-in-page.js";
|
|
16
17
|
import { TwoFactorPage } from "./two-factor-page.js";
|
|
@@ -58,7 +59,7 @@ const forgetInvitationLink = () => window.history.replaceState(window.history.st
|
|
|
58
59
|
* staff link opened. An invited person with an account signs in first and comes back to the invitation.
|
|
59
60
|
*/
|
|
60
61
|
const AuthGate = ({ workspace, children }) => {
|
|
61
|
-
const { state, recheck, passwordReset, signOut, signInProviders, showSignIn, browse } = useAuth();
|
|
62
|
+
const { state, recheck, passwordReset, signOut, signInProviders, showSignIn, canSignUp, entry, showSignUp, browse } = useAuth();
|
|
62
63
|
const [page, setPage] = useState(firstPage);
|
|
63
64
|
useEffect(() => {
|
|
64
65
|
if (state.kind === "signed-in" || state.kind === "two-factor" || state.kind === "setup-required") setPage((current) => {
|
|
@@ -150,6 +151,7 @@ const AuthGate = ({ workspace, children }) => {
|
|
|
150
151
|
email: page.email,
|
|
151
152
|
onBack: () => setPage({ kind: "sign-in" })
|
|
152
153
|
});
|
|
154
|
+
if (canSignUp && entry === "sign-up" && page.kind === "sign-in") return /* @__PURE__ */ jsx(SignUpPage, { workspace });
|
|
153
155
|
const signIn = page.kind === "sign-in" ? page : { kind: "sign-in" };
|
|
154
156
|
const providerError = signIn.providerError && providerMessage(signIn.providerError, signInProviders.length === 1 ? signInProviders[0].name : "the provider");
|
|
155
157
|
const error = signIn.error ?? providerError;
|
|
@@ -162,6 +164,7 @@ const AuthGate = ({ workspace, children }) => {
|
|
|
162
164
|
kind: "email-code",
|
|
163
165
|
email
|
|
164
166
|
}),
|
|
167
|
+
onSignUp: canSignUp ? showSignUp : void 0,
|
|
165
168
|
onBrowse: browse
|
|
166
169
|
}, error);
|
|
167
170
|
};
|
|
@@ -14,6 +14,8 @@ const AuthProvider = ({ session: given, children }) => {
|
|
|
14
14
|
const [state, setState] = useState({ kind: "loading" });
|
|
15
15
|
const [signInMethods, setSignInMethods] = useState(["password"]);
|
|
16
16
|
const [passwordReset, setPasswordReset] = useState(false);
|
|
17
|
+
const [canSignUp, setCanSignUp] = useState(false);
|
|
18
|
+
const [entry, setEntry] = useState("sign-in");
|
|
17
19
|
const [passkeyDomains, setPasskeyDomains] = useState([]);
|
|
18
20
|
const [socialProviders, setSocialProviders] = useState([]);
|
|
19
21
|
const [platformSignIn, setPlatformSignIn] = useState();
|
|
@@ -27,6 +29,7 @@ const AuthProvider = ({ session: given, children }) => {
|
|
|
27
29
|
const session = useMemo(() => given ?? createAuthSession({ onSignedOut: () => signedOut.current() }), [given]);
|
|
28
30
|
const enter = useCallback(async (user) => {
|
|
29
31
|
const [{ missing }, staff] = await Promise.all([session.account.signInMethods(), session.staff.current()]);
|
|
32
|
+
setEntry("sign-in");
|
|
30
33
|
setState(missing.length > 0 ? {
|
|
31
34
|
kind: "setup-required",
|
|
32
35
|
user,
|
|
@@ -46,6 +49,7 @@ const AuthProvider = ({ session: given, children }) => {
|
|
|
46
49
|
session.status().then(async (status) => {
|
|
47
50
|
setSignInMethods(status.signInMethods);
|
|
48
51
|
setPasswordReset(status.passwordReset);
|
|
52
|
+
setCanSignUp(Boolean(status.signUp));
|
|
49
53
|
setPasskeyDomains(status.passkeyDomains ?? []);
|
|
50
54
|
setSocialProviders(status.socialProviders);
|
|
51
55
|
setPlatformSignIn(status.platformSignIn);
|
|
@@ -66,6 +70,8 @@ const AuthProvider = ({ session: given, children }) => {
|
|
|
66
70
|
session,
|
|
67
71
|
signInMethods,
|
|
68
72
|
passwordReset,
|
|
73
|
+
canSignUp,
|
|
74
|
+
entry,
|
|
69
75
|
passkeyDomains,
|
|
70
76
|
socialProviders,
|
|
71
77
|
signInProviders: socialProviders.map((id) => ({
|
|
@@ -76,11 +82,23 @@ const AuthProvider = ({ session: given, children }) => {
|
|
|
76
82
|
...organizations && { organizations },
|
|
77
83
|
markSignedOut,
|
|
78
84
|
recheck,
|
|
79
|
-
showSignIn: () =>
|
|
80
|
-
|
|
85
|
+
showSignIn: () => {
|
|
86
|
+
setEntry("sign-in");
|
|
87
|
+
setState((current) => current.kind === "visitor" ? { kind: "signed-out" } : current);
|
|
88
|
+
},
|
|
89
|
+
showSignUp: () => {
|
|
90
|
+
setEntry("sign-up");
|
|
91
|
+
setState((current) => current.kind === "visitor" ? { kind: "signed-out" } : current);
|
|
92
|
+
},
|
|
93
|
+
...anonymous && { browse: () => {
|
|
94
|
+
setEntry("sign-in");
|
|
95
|
+
setState((current) => current.kind === "signed-out" ? { kind: "visitor" } : current);
|
|
96
|
+
} },
|
|
81
97
|
signIn: async (email, password) => finish(await session.signIn(email, password)),
|
|
82
98
|
sendSignInCode: (email) => session.sendSignInCode(email),
|
|
83
99
|
signInWithCode: async (email, code) => finish(await session.signInWithCode(email, code)),
|
|
100
|
+
sendSignUpCode: (email) => session.sendSignUpCode(email),
|
|
101
|
+
signUp: async (input) => enter(await session.signUp(input)),
|
|
84
102
|
signInWithPasskey: async (domain) => enter(await session.signInWithPasskey(domain)),
|
|
85
103
|
verifyTwoFactor: async (input) => enter(await session.verifyTwoFactor(input)),
|
|
86
104
|
signInSocial: async (provider) => {
|
|
@@ -102,6 +120,8 @@ const AuthProvider = ({ session: given, children }) => {
|
|
|
102
120
|
session,
|
|
103
121
|
signInMethods,
|
|
104
122
|
passwordReset,
|
|
123
|
+
canSignUp,
|
|
124
|
+
entry,
|
|
105
125
|
passkeyDomains,
|
|
106
126
|
socialProviders,
|
|
107
127
|
platformSignIn,
|
|
@@ -14,7 +14,7 @@ const Divider = () => /* @__PURE__ */ jsxs("div", {
|
|
|
14
14
|
/* @__PURE__ */ jsx("span", { className: "h-px flex-1 bg-border" })
|
|
15
15
|
]
|
|
16
16
|
});
|
|
17
|
-
const SignInForm = ({ onSubmit, busy, error, workspace, notice, methods = ["password"], onSendCode, onPasskey, passkeyDomains = [], onForgotPassword, providers = [], onContinueWith, onBrowse }) => {
|
|
17
|
+
const SignInForm = ({ onSubmit, busy, error, workspace, notice, methods = ["password"], onSendCode, onPasskey, passkeyDomains = [], onForgotPassword, providers = [], onContinueWith, onSignUp, onBrowse }) => {
|
|
18
18
|
const [email, setEmail] = useState("");
|
|
19
19
|
const [password, setPassword] = useState("");
|
|
20
20
|
const emailInput = useRef(null);
|
|
@@ -133,6 +133,19 @@ const SignInForm = ({ onSubmit, busy, error, workspace, notice, methods = ["pass
|
|
|
133
133
|
})
|
|
134
134
|
]
|
|
135
135
|
}),
|
|
136
|
+
onSignUp && /* @__PURE__ */ jsxs("p", {
|
|
137
|
+
className: "mt-4 text-center text-[13px] text-muted-foreground",
|
|
138
|
+
children: [
|
|
139
|
+
"New here?",
|
|
140
|
+
" ",
|
|
141
|
+
/* @__PURE__ */ jsx("button", {
|
|
142
|
+
type: "button",
|
|
143
|
+
onClick: onSignUp,
|
|
144
|
+
className: "font-medium text-primary-text hover:underline",
|
|
145
|
+
children: "Create an account"
|
|
146
|
+
})
|
|
147
|
+
]
|
|
148
|
+
}),
|
|
136
149
|
onBrowse && /* @__PURE__ */ jsx("button", {
|
|
137
150
|
type: "button",
|
|
138
151
|
onClick: onBrowse,
|
|
@@ -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, onForgotPassword, onBrowse, onCodeSent, error: initialError }) => {
|
|
8
|
+
const SignInPage = ({ workspace, notice, onForgotPassword, onSignUp, 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);
|
|
@@ -27,6 +27,7 @@ const SignInPage = ({ workspace, notice, onForgotPassword, onBrowse, onCodeSent,
|
|
|
27
27
|
notice,
|
|
28
28
|
methods: signInMethods,
|
|
29
29
|
onForgotPassword,
|
|
30
|
+
onSignUp,
|
|
30
31
|
onBrowse,
|
|
31
32
|
providers: signInProviders,
|
|
32
33
|
onContinueWith: (provider) => void attempt(() => signInSocial(provider), signInMessage),
|
|
@@ -15,7 +15,8 @@ export type SignInPromptProps = {
|
|
|
15
15
|
});
|
|
16
16
|
/**
|
|
17
17
|
* What a visitor who is not signed in is told about something they could use once signed in: the prompt's title, what
|
|
18
|
-
* signing in gives and its benefits, with "Sign in" and
|
|
18
|
+
* signing in gives and its benefits, with "Sign in" and a way to make an account: the page the prompt names, or the
|
|
19
|
+
* app's own sign-up when the server has it. As a page
|
|
19
20
|
* it stands in for a list the visitor cannot see; as a dialog it answers a press on a button that needs an account.
|
|
20
21
|
*/
|
|
21
22
|
export declare const SignInPrompt: (props: SignInPromptProps) => import("react").JSX.Element;
|
|
@@ -17,13 +17,16 @@ const Benefits = ({ benefits }) => benefits && benefits.length > 0 ? /* @__PURE_
|
|
|
17
17
|
}, benefit))
|
|
18
18
|
}) : null;
|
|
19
19
|
const Actions = ({ prompt }) => {
|
|
20
|
-
const { showSignIn } = useAuth();
|
|
21
|
-
return /* @__PURE__ */ jsxs(Fragment$1, { children: [prompt.signUp
|
|
20
|
+
const { showSignIn, canSignUp, showSignUp } = useAuth();
|
|
21
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [prompt.signUp ? /* @__PURE__ */ jsx("a", {
|
|
22
22
|
href: prompt.signUp.href,
|
|
23
23
|
target: "_blank",
|
|
24
24
|
rel: "noreferrer",
|
|
25
25
|
className: buttonClass(),
|
|
26
26
|
children: prompt.signUp.label
|
|
27
|
+
}) : canSignUp && /* @__PURE__ */ jsx(Button, {
|
|
28
|
+
onClick: showSignUp,
|
|
29
|
+
children: "Create an account"
|
|
27
30
|
}), /* @__PURE__ */ jsx(Button, {
|
|
28
31
|
variant: "primary",
|
|
29
32
|
onClick: showSignIn,
|
|
@@ -32,7 +35,8 @@ const Actions = ({ prompt }) => {
|
|
|
32
35
|
};
|
|
33
36
|
/**
|
|
34
37
|
* What a visitor who is not signed in is told about something they could use once signed in: the prompt's title, what
|
|
35
|
-
* signing in gives and its benefits, with "Sign in" and
|
|
38
|
+
* signing in gives and its benefits, with "Sign in" and a way to make an account: the page the prompt names, or the
|
|
39
|
+
* app's own sign-up when the server has it. As a page
|
|
36
40
|
* it stands in for a list the visitor cannot see; as a dialog it answers a press on a button that needs an account.
|
|
37
41
|
*/
|
|
38
42
|
const SignInPrompt = (props) => {
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { Input } from "../primitives/input.js";
|
|
2
|
+
import { Button } from "../primitives/button.js";
|
|
3
|
+
import { CodeInput } from "./code-input.js";
|
|
4
|
+
import { AuthLayout } from "./auth-layout.js";
|
|
5
|
+
import { useId, useState } from "react";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
//#region src/auth/sign-up-details-form.tsx
|
|
8
|
+
/** The second step of making an account: the emailed code, the person's name and how they will sign in. */
|
|
9
|
+
const SignUpDetailsForm = ({ email, onSubmit, onResend, onBack, methods, busy, error, notice }) => {
|
|
10
|
+
const [code, setCode] = useState("");
|
|
11
|
+
const [name, setName] = useState("");
|
|
12
|
+
const [password, setPassword] = useState("");
|
|
13
|
+
const passwordHint = useId();
|
|
14
|
+
const withPassword = methods.includes("password");
|
|
15
|
+
const passwordOptional = methods.includes("emailCode");
|
|
16
|
+
return /* @__PURE__ */ jsxs(AuthLayout, {
|
|
17
|
+
title: "Check your email",
|
|
18
|
+
description: "Enter the code we sent to create your account.",
|
|
19
|
+
children: [
|
|
20
|
+
/* @__PURE__ */ jsxs("p", {
|
|
21
|
+
className: "mb-4 text-[13px] text-muted-foreground",
|
|
22
|
+
children: [
|
|
23
|
+
"A 6-digit code is on its way to ",
|
|
24
|
+
/* @__PURE__ */ jsx("span", {
|
|
25
|
+
className: "font-medium text-foreground",
|
|
26
|
+
children: email
|
|
27
|
+
}),
|
|
28
|
+
". It works for 5 minutes, once. If the address has an account already, the email says so instead."
|
|
29
|
+
]
|
|
30
|
+
}),
|
|
31
|
+
notice && /* @__PURE__ */ jsx("p", {
|
|
32
|
+
role: "status",
|
|
33
|
+
className: "mb-4 rounded-md bg-success-soft px-3 py-2 text-xs font-medium text-success-text",
|
|
34
|
+
children: notice
|
|
35
|
+
}),
|
|
36
|
+
/* @__PURE__ */ jsxs("form", {
|
|
37
|
+
className: "flex flex-col gap-4",
|
|
38
|
+
onSubmit: (event) => {
|
|
39
|
+
event.preventDefault();
|
|
40
|
+
onSubmit({
|
|
41
|
+
code: code.trim(),
|
|
42
|
+
name: name.trim(),
|
|
43
|
+
...withPassword && password && { password }
|
|
44
|
+
});
|
|
45
|
+
},
|
|
46
|
+
children: [
|
|
47
|
+
/* @__PURE__ */ jsxs("label", {
|
|
48
|
+
className: "flex flex-col gap-1.5 text-[13px] font-medium",
|
|
49
|
+
children: ["Code", /* @__PURE__ */ jsx(CodeInput, {
|
|
50
|
+
name: "code",
|
|
51
|
+
required: true,
|
|
52
|
+
autoFocus: true,
|
|
53
|
+
value: code,
|
|
54
|
+
invalid: Boolean(error),
|
|
55
|
+
onChange: (event) => setCode(event.target.value)
|
|
56
|
+
})]
|
|
57
|
+
}),
|
|
58
|
+
/* @__PURE__ */ jsxs("label", {
|
|
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),
|
|
67
|
+
className: "min-h-6"
|
|
68
|
+
})]
|
|
69
|
+
}),
|
|
70
|
+
withPassword && /* @__PURE__ */ jsxs("div", {
|
|
71
|
+
className: "flex flex-col gap-1.5",
|
|
72
|
+
children: [/* @__PURE__ */ jsxs("label", {
|
|
73
|
+
className: "flex flex-col gap-1.5 text-[13px] font-medium",
|
|
74
|
+
children: [passwordOptional ? "Password (optional)" : "Password", /* @__PURE__ */ jsx(Input, {
|
|
75
|
+
type: "password",
|
|
76
|
+
name: "password",
|
|
77
|
+
autoComplete: "new-password",
|
|
78
|
+
"aria-describedby": passwordHint,
|
|
79
|
+
required: !passwordOptional,
|
|
80
|
+
minLength: 12,
|
|
81
|
+
maxLength: 128,
|
|
82
|
+
value: password,
|
|
83
|
+
onChange: (event) => setPassword(event.target.value),
|
|
84
|
+
className: "min-h-6"
|
|
85
|
+
})]
|
|
86
|
+
}), /* @__PURE__ */ jsxs("p", {
|
|
87
|
+
id: passwordHint,
|
|
88
|
+
className: "text-xs text-muted-foreground",
|
|
89
|
+
children: [
|
|
90
|
+
"At least ",
|
|
91
|
+
12,
|
|
92
|
+
" characters.",
|
|
93
|
+
passwordOptional && " Without one, you sign in with a code we email you."
|
|
94
|
+
]
|
|
95
|
+
})]
|
|
96
|
+
}),
|
|
97
|
+
error && /* @__PURE__ */ jsx("p", {
|
|
98
|
+
role: "alert",
|
|
99
|
+
className: "text-xs font-medium text-danger-text",
|
|
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
|
+
]
|
|
127
|
+
});
|
|
128
|
+
};
|
|
129
|
+
//#endregion
|
|
130
|
+
export { SignUpDetailsForm };
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { Input } from "../primitives/input.js";
|
|
2
|
+
import { Button } from "../primitives/button.js";
|
|
3
|
+
import { AuthLayout } from "./auth-layout.js";
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
import { Mail } from "lucide-react";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
//#region src/auth/sign-up-email-form.tsx
|
|
8
|
+
/** The first step of making an account: the address, which gets a code to prove it is theirs. */
|
|
9
|
+
const SignUpEmailForm = ({ onSubmit, onSignIn, onBrowse, busy, error, workspace }) => {
|
|
10
|
+
const [email, setEmail] = useState("");
|
|
11
|
+
return /* @__PURE__ */ jsxs(AuthLayout, {
|
|
12
|
+
title: "Create an account",
|
|
13
|
+
description: workspace,
|
|
14
|
+
children: [/* @__PURE__ */ jsxs("form", {
|
|
15
|
+
className: "flex flex-col gap-4",
|
|
16
|
+
onSubmit: (event) => {
|
|
17
|
+
event.preventDefault();
|
|
18
|
+
onSubmit(email.trim());
|
|
19
|
+
},
|
|
20
|
+
children: [
|
|
21
|
+
/* @__PURE__ */ jsxs("label", {
|
|
22
|
+
className: "flex flex-col gap-1.5 text-[13px] font-medium",
|
|
23
|
+
children: ["Email", /* @__PURE__ */ jsx(Input, {
|
|
24
|
+
type: "email",
|
|
25
|
+
name: "email",
|
|
26
|
+
autoComplete: "email",
|
|
27
|
+
required: true,
|
|
28
|
+
autoFocus: true,
|
|
29
|
+
value: email,
|
|
30
|
+
invalid: Boolean(error),
|
|
31
|
+
onChange: (event) => setEmail(event.target.value),
|
|
32
|
+
className: "min-h-6"
|
|
33
|
+
})]
|
|
34
|
+
}),
|
|
35
|
+
/* @__PURE__ */ jsx("p", {
|
|
36
|
+
className: "text-[13px] text-muted-foreground",
|
|
37
|
+
children: "We email you a code to make sure the address is yours."
|
|
38
|
+
}),
|
|
39
|
+
error && /* @__PURE__ */ jsx("p", {
|
|
40
|
+
role: "alert",
|
|
41
|
+
className: "text-xs font-medium text-danger-text",
|
|
42
|
+
children: error
|
|
43
|
+
}),
|
|
44
|
+
/* @__PURE__ */ jsxs(Button, {
|
|
45
|
+
variant: "primary",
|
|
46
|
+
type: "submit",
|
|
47
|
+
loading: busy,
|
|
48
|
+
className: "min-h-10",
|
|
49
|
+
children: [/* @__PURE__ */ jsx(Mail, { className: "size-4" }), "Email me a code"]
|
|
50
|
+
}),
|
|
51
|
+
/* @__PURE__ */ jsxs("p", {
|
|
52
|
+
className: "text-center text-[13px] text-muted-foreground",
|
|
53
|
+
children: [
|
|
54
|
+
"Have an account?",
|
|
55
|
+
" ",
|
|
56
|
+
/* @__PURE__ */ jsx("button", {
|
|
57
|
+
type: "button",
|
|
58
|
+
onClick: onSignIn,
|
|
59
|
+
className: "font-medium text-primary-text hover:underline",
|
|
60
|
+
children: "Sign in"
|
|
61
|
+
})
|
|
62
|
+
]
|
|
63
|
+
})
|
|
64
|
+
]
|
|
65
|
+
}), onBrowse && /* @__PURE__ */ jsx("button", {
|
|
66
|
+
type: "button",
|
|
67
|
+
onClick: onBrowse,
|
|
68
|
+
className: "mt-4 w-full text-center text-[13px] font-medium text-muted-foreground hover:text-foreground hover:underline",
|
|
69
|
+
children: "Continue without an account"
|
|
70
|
+
})]
|
|
71
|
+
});
|
|
72
|
+
};
|
|
73
|
+
//#endregion
|
|
74
|
+
export { SignUpEmailForm };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { authMessage } from "./auth-messages.js";
|
|
2
|
+
import { useAuth } from "./auth-provider.js";
|
|
3
|
+
import { SignUpDetailsForm } from "./sign-up-details-form.js";
|
|
4
|
+
import { SignUpEmailForm } from "./sign-up-email-form.js";
|
|
5
|
+
import { useState } from "react";
|
|
6
|
+
import { AuthError } from "@protobase/client";
|
|
7
|
+
import { jsx } from "react/jsx-runtime";
|
|
8
|
+
//#region src/auth/sign-up-page.tsx
|
|
9
|
+
/**
|
|
10
|
+
* Makes an account on a server with open sign-up: the address, then the code emailed to it with the person's name and
|
|
11
|
+
* password. The new account is signed in, and sets up what the sign-in policy requires as after any sign-in.
|
|
12
|
+
*/
|
|
13
|
+
const SignUpPage = ({ workspace }) => {
|
|
14
|
+
const { signInMethods, sendSignUpCode, signUp, showSignIn, browse } = useAuth();
|
|
15
|
+
const [email, setEmail] = useState();
|
|
16
|
+
const [busy, setBusy] = useState(false);
|
|
17
|
+
const [error, setError] = useState();
|
|
18
|
+
const [notice, setNotice] = useState();
|
|
19
|
+
const attempt = async (step) => {
|
|
20
|
+
setBusy(true);
|
|
21
|
+
setError(void 0);
|
|
22
|
+
setNotice(void 0);
|
|
23
|
+
try {
|
|
24
|
+
await step();
|
|
25
|
+
} catch (failure) {
|
|
26
|
+
if (!(failure instanceof AuthError)) throw failure;
|
|
27
|
+
setError(authMessage(failure));
|
|
28
|
+
}
|
|
29
|
+
setBusy(false);
|
|
30
|
+
};
|
|
31
|
+
if (email === void 0) return /* @__PURE__ */ jsx(SignUpEmailForm, {
|
|
32
|
+
workspace,
|
|
33
|
+
busy,
|
|
34
|
+
error,
|
|
35
|
+
onSignIn: showSignIn,
|
|
36
|
+
onBrowse: browse,
|
|
37
|
+
onSubmit: (address) => void attempt(async () => {
|
|
38
|
+
await sendSignUpCode(address);
|
|
39
|
+
setEmail(address);
|
|
40
|
+
})
|
|
41
|
+
});
|
|
42
|
+
return /* @__PURE__ */ jsx(SignUpDetailsForm, {
|
|
43
|
+
email,
|
|
44
|
+
methods: signInMethods,
|
|
45
|
+
busy,
|
|
46
|
+
error,
|
|
47
|
+
notice,
|
|
48
|
+
onBack: () => {
|
|
49
|
+
setError(void 0);
|
|
50
|
+
setEmail(void 0);
|
|
51
|
+
},
|
|
52
|
+
onResend: () => void attempt(async () => {
|
|
53
|
+
await sendSignUpCode(email);
|
|
54
|
+
setNotice("A new code is on its way. Only the newest one works.");
|
|
55
|
+
}),
|
|
56
|
+
onSubmit: (details) => void attempt(() => signUp({
|
|
57
|
+
email,
|
|
58
|
+
...details
|
|
59
|
+
}))
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
//#endregion
|
|
63
|
+
export { SignUpPage };
|
package/dist/package.js
CHANGED