mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-03 17:08:13 +00:00
Fix login and signup back button links
This commit is contained in:
1 parent
7c64da88da
commit
431f2efcf0
4 files changed
+160
-289
No files matched your search
@@ -124,11 +124,17 @@ export default function LoginScreen() {
|
||||
)}
|
||||
</div>
|
||||
<div className="align-items flex w-full max-w-xl rounded-b-xl bg-ui-controls px-6 py-4">
|
||||
<a
|
||||
{/* <a
|
||||
href="https://storyteller.ai/password-reset"
|
||||
className="grow text-sm font-medium !text-brand-primary-400 transition-all duration-150 hover:!text-brand-primary-300"
|
||||
>
|
||||
Forgot your password?
|
||||
</a> */}
|
||||
<a
|
||||
href="/"
|
||||
className="grow text-sm font-medium !text-brand-primary-400 transition-all duration-150 hover:!text-brand-primary-300"
|
||||
>
|
||||
Back
|
||||
</a>
|
||||
<div className="flex justify-end gap-1 text-sm">
|
||||
<p className="opacity-75">Don't have an account?</p>
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
import { useRef } from "react";
|
||||
import { useNavigate, useSearchParams } from "react-router-dom";
|
||||
import { useSignalEffect, useSignals } from "@preact/signals-react/runtime";
|
||||
|
||||
import { faKey, faUser } from "@fortawesome/pro-solid-svg-icons";
|
||||
|
||||
import { AUTH_STATUS } from "~/enums";
|
||||
import { authentication, login, logout } from "~/signals";
|
||||
|
||||
import {
|
||||
Button,
|
||||
H1,
|
||||
Input,
|
||||
Link,
|
||||
P,
|
||||
LoadingDots,
|
||||
ConfirmationModal,
|
||||
} from "~/components";
|
||||
|
||||
export default function LoginScreen() {
|
||||
useSignals();
|
||||
const navigate = useNavigate();
|
||||
const [searchParams] = useSearchParams();
|
||||
|
||||
const formRef = useRef<HTMLFormElement | null>(null);
|
||||
const { status: authStatus } = authentication;
|
||||
const authLoaderMessage = getAuthLoaderMessage();
|
||||
const shouldShowLoader = checkShouldShowLoader();
|
||||
|
||||
const showNoAccessModal = authStatus.value === AUTH_STATUS.NO_ACCESS;
|
||||
|
||||
const handleOnSumbit = (ev: React.FormEvent<HTMLFormElement>) => {
|
||||
ev.preventDefault();
|
||||
if (formRef.current) {
|
||||
const form = new FormData(formRef.current);
|
||||
const usernameOrEmail = form.get("usernameOrEmail")?.toString();
|
||||
const password = form.get("password")?.toString();
|
||||
if (usernameOrEmail && password && login) {
|
||||
login({
|
||||
usernameOrEmail,
|
||||
password,
|
||||
});
|
||||
}
|
||||
}
|
||||
}; // end handleOnSubmit
|
||||
|
||||
useSignalEffect(() => {
|
||||
const redirectPath = searchParams.get("redirect");
|
||||
if (authStatus.value === AUTH_STATUS.LOGGED_IN) {
|
||||
navigate(redirectPath ? redirectPath : "/");
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="fixed w-full" style={{ height: "calc(100% - 72px)" }}>
|
||||
<div className="mx-auto my-6 w-10/12 max-w-2xl">
|
||||
<H1 className="text-center text-[32px] font-bold">
|
||||
Login to Storyteller
|
||||
</H1>
|
||||
</div>
|
||||
<div className="relative mx-auto my-6 w-10/12 max-w-2xl overflow-hidden rounded-lg border border-ui-panel-border bg-ui-panel p-6">
|
||||
<form
|
||||
ref={formRef}
|
||||
onSubmit={handleOnSumbit}
|
||||
className="flex flex-col gap-4"
|
||||
>
|
||||
<Input
|
||||
label="Username or Email"
|
||||
icon={faUser}
|
||||
name="usernameOrEmail"
|
||||
placeholder="Username or Email"
|
||||
autoComplete="username"
|
||||
required
|
||||
/>
|
||||
<Input
|
||||
label="Password"
|
||||
icon={faKey}
|
||||
type="password"
|
||||
name="password"
|
||||
placeholder="Password"
|
||||
autoComplete="current-password"
|
||||
required
|
||||
/>
|
||||
<div className="align-items mb-3 flex">
|
||||
<a
|
||||
href="https://storyteller.ai/password-reset"
|
||||
className="grow text-sm text-brand-primary transition-all duration-150 hover:text-brand-primary-400"
|
||||
>
|
||||
Forgot your password?
|
||||
</a>
|
||||
<div className="flex justify-end gap-1 text-sm">
|
||||
<P>Don't have an account?</P>
|
||||
<Link
|
||||
to="/signup"
|
||||
reloadDocument={true} // TODO(bt,2025-04-19): Once we have in-page routing, get rid of this.
|
||||
>Sign Up</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Button className="h-11 w-full text-[15px]">Login</Button>
|
||||
</form>
|
||||
<LoadingDots
|
||||
className="absolute left-0 top-0 h-full w-full"
|
||||
isShowing={shouldShowLoader}
|
||||
message={authLoaderMessage}
|
||||
type="bricks"
|
||||
/>
|
||||
<ConfirmationModal
|
||||
text="We're in a closed beta and you'll need a beta key to use this app."
|
||||
title="Unauthorized"
|
||||
open={showNoAccessModal}
|
||||
onClose={handleClose}
|
||||
cancelText="Close"
|
||||
onCancel={handleClose}
|
||||
okText="Get Beta Key"
|
||||
onOk={() => {
|
||||
handleClose();
|
||||
if (window) {
|
||||
window.open("https://storyteller.ai/beta-key/redeem", "_blank");
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
if (authentication.status.value !== AUTH_STATUS.LOGGED_OUT) {
|
||||
logout();
|
||||
}
|
||||
};
|
||||
|
||||
const checkShouldShowLoader = () => {
|
||||
return (
|
||||
authentication.status.value === AUTH_STATUS.LOGGING ||
|
||||
authentication.status.value === AUTH_STATUS.LOGGED_IN
|
||||
);
|
||||
};
|
||||
const getAuthLoaderMessage = () => {
|
||||
if (authentication.status.value === AUTH_STATUS.LOGGED_IN) {
|
||||
return "Authenticated, Redirecting...";
|
||||
}
|
||||
if (authentication.status.value === AUTH_STATUS.GET_USER_INFO) {
|
||||
return "Getting User Info...";
|
||||
}
|
||||
return "Getting Session...";
|
||||
};
|
||||
@@ -1,146 +1,150 @@
|
||||
import { faEnvelope, faKey, faUser } from "@fortawesome/pro-solid-svg-icons";
|
||||
import { Button, H1, Input, Link, P } from "~/components";
|
||||
import { addToast, authentication, signUp } from "~/signals";
|
||||
import { FormEvent, useRef, useState } from "react";
|
||||
import { AUTH_STATUS, ToastTypes } from "~/enums";
|
||||
import { useSignalEffect, useSignals } from "@preact/signals-react/runtime";
|
||||
import { useNavigate, useSearchParams } from "react-router-dom";
|
||||
// import { faEnvelope, faKey, faUser } from "@fortawesome/pro-solid-svg-icons";
|
||||
// import { Button, H1, Input, Link, P } from "~/components";
|
||||
// import { addToast, authentication, signUp } from "~/signals";
|
||||
// import { FormEvent, useRef, useState } from "react";
|
||||
// import { AUTH_STATUS, ToastTypes } from "~/enums";
|
||||
// import { useSignalEffect, useSignals } from "@preact/signals-react/runtime";
|
||||
// import { useNavigate, useSearchParams } from "react-router-dom";
|
||||
|
||||
const regEx =
|
||||
/^(([^<>()[\].,;:\s@"]+(.[^<>()[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{2,})$/i;
|
||||
// const regEx =
|
||||
// /^(([^<>()[\].,;:\s@"]+(.[^<>()[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{2,})$/i;
|
||||
|
||||
export default function SignUpScreen() {
|
||||
useSignals();
|
||||
const navigate = useNavigate();
|
||||
const formRef = useRef<HTMLFormElement | null>(null);
|
||||
const [usernameError, setUsernameError] = useState("");
|
||||
const [emailError, setEmailError] = useState("");
|
||||
const [passwordError, setPasswordError] = useState("");
|
||||
const [passwordConfirmationError, setPasswordConfirmationError] =
|
||||
useState("");
|
||||
const [searchParams] = useSearchParams();
|
||||
const { status: authStatus } = authentication;
|
||||
// export default function SignUpScreen() {
|
||||
// useSignals();
|
||||
// const navigate = useNavigate();
|
||||
// const formRef = useRef<HTMLFormElement | null>(null);
|
||||
// const [usernameError, setUsernameError] = useState("");
|
||||
// const [emailError, setEmailError] = useState("");
|
||||
// const [passwordError, setPasswordError] = useState("");
|
||||
// const [passwordConfirmationError, setPasswordConfirmationError] =
|
||||
// useState("");
|
||||
// const [searchParams] = useSearchParams();
|
||||
// const { status: authStatus } = authentication;
|
||||
|
||||
const handleOnSubmit = (ev: FormEvent<HTMLFormElement>) => {
|
||||
ev.preventDefault();
|
||||
if (formRef.current) {
|
||||
const form = new FormData(formRef.current);
|
||||
const email = form.get("email")?.toString();
|
||||
const password = form.get("password")?.toString();
|
||||
const passwordConfirmation = form
|
||||
.get("password-confirmation")
|
||||
?.toString();
|
||||
const username = form.get("username")?.toString();
|
||||
setUsernameError("");
|
||||
if (!username || username.length < 6) {
|
||||
setUsernameError("Username must be at least 6 characters long");
|
||||
}
|
||||
setEmailError("");
|
||||
if (!email || !email.match(regEx)) {
|
||||
setEmailError("Email must be a valid email address");
|
||||
}
|
||||
setPasswordError("");
|
||||
if (!password || password.length < 8) {
|
||||
setPasswordError("Password must be at least 8 characters long");
|
||||
}
|
||||
setPasswordConfirmationError("");
|
||||
if (!passwordError && passwordConfirmation !== password) {
|
||||
setPasswordConfirmationError("Passwords do not match");
|
||||
}
|
||||
// const handleOnSubmit = (ev: FormEvent<HTMLFormElement>) => {
|
||||
// ev.preventDefault();
|
||||
// if (formRef.current) {
|
||||
// const form = new FormData(formRef.current);
|
||||
// const email = form.get("email")?.toString();
|
||||
// const password = form.get("password")?.toString();
|
||||
// const passwordConfirmation = form
|
||||
// .get("password-confirmation")
|
||||
// ?.toString();
|
||||
// const username = form.get("username")?.toString();
|
||||
// setUsernameError("");
|
||||
// if (!username || username.length < 6) {
|
||||
// setUsernameError("Username must be at least 6 characters long");
|
||||
// }
|
||||
// setEmailError("");
|
||||
// if (!email || !email.match(regEx)) {
|
||||
// setEmailError("Email must be a valid email address");
|
||||
// }
|
||||
// setPasswordError("");
|
||||
// if (!password || password.length < 8) {
|
||||
// setPasswordError("Password must be at least 8 characters long");
|
||||
// }
|
||||
// setPasswordConfirmationError("");
|
||||
// if (!passwordError && passwordConfirmation !== password) {
|
||||
// setPasswordConfirmationError("Passwords do not match");
|
||||
// }
|
||||
|
||||
if (
|
||||
!usernameError &&
|
||||
!passwordError &&
|
||||
!emailError &&
|
||||
!passwordConfirmationError &&
|
||||
signUp
|
||||
) {
|
||||
signUp({
|
||||
username: username!,
|
||||
email: email!,
|
||||
password: password!,
|
||||
passwordConfirmation: passwordConfirmation!,
|
||||
}).then((error) => {
|
||||
console.log("Error occured", error);
|
||||
if (error) {
|
||||
addToast(ToastTypes.ERROR, error);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}; // end handleOnSubmit
|
||||
// if (
|
||||
// !usernameError &&
|
||||
// !passwordError &&
|
||||
// !emailError &&
|
||||
// !passwordConfirmationError &&
|
||||
// signUp
|
||||
// ) {
|
||||
// signUp({
|
||||
// username: username!,
|
||||
// email: email!,
|
||||
// password: password!,
|
||||
// passwordConfirmation: passwordConfirmation!,
|
||||
// }).then((error) => {
|
||||
// console.log("Error occured", error);
|
||||
// if (error) {
|
||||
// addToast(ToastTypes.ERROR, error);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// }; // end handleOnSubmit
|
||||
|
||||
useSignalEffect(() => {
|
||||
const redirectPath = searchParams.get("redirect");
|
||||
if (authStatus.value === AUTH_STATUS.LOGGED_IN) {
|
||||
navigate(redirectPath ? redirectPath : "/");
|
||||
return;
|
||||
}
|
||||
if (authStatus.value === AUTH_STATUS.NO_ACCESS) {
|
||||
window.open("https://storyteller.ai/", "_self");
|
||||
return;
|
||||
}
|
||||
});
|
||||
// useSignalEffect(() => {
|
||||
// const redirectPath = searchParams.get("redirect");
|
||||
// if (authStatus.value === AUTH_STATUS.LOGGED_IN) {
|
||||
// navigate(redirectPath ? redirectPath : "/");
|
||||
// return;
|
||||
// }
|
||||
// if (authStatus.value === AUTH_STATUS.NO_ACCESS) {
|
||||
// window.open("https://storyteller.ai/", "_self");
|
||||
// return;
|
||||
// }
|
||||
// });
|
||||
|
||||
return (
|
||||
<div
|
||||
className="fixed w-full overflow-scroll"
|
||||
style={{ height: "calc(100% - 72px)" }}
|
||||
>
|
||||
<div className="mx-auto my-6 w-10/12 max-w-2xl">
|
||||
<H1 className="text-center">Sign Up to Storyteller</H1>
|
||||
</div>
|
||||
<div className="mx-auto my-6 w-10/12 max-w-2xl rounded-lg border border-ui-panel-border bg-ui-panel p-6">
|
||||
<form ref={formRef} onSubmit={handleOnSubmit}>
|
||||
<Input
|
||||
label="Username"
|
||||
icon={faUser}
|
||||
placeholder="Username"
|
||||
name="username"
|
||||
errorMessage={usernameError}
|
||||
required
|
||||
/>
|
||||
<br />
|
||||
<Input
|
||||
type="email"
|
||||
label="Email"
|
||||
icon={faEnvelope}
|
||||
placeholder="Email"
|
||||
name="email"
|
||||
errorMessage={emailError}
|
||||
required
|
||||
/>
|
||||
<br />
|
||||
<Input
|
||||
type="password"
|
||||
label="Password"
|
||||
icon={faKey}
|
||||
name="password"
|
||||
placeholder="Password"
|
||||
autoComplete="current-password"
|
||||
errorMessage={passwordError}
|
||||
required
|
||||
/>
|
||||
<br />
|
||||
<Input
|
||||
type="password"
|
||||
label="Password Confrimation"
|
||||
icon={faKey}
|
||||
placeholder="Password Confirmation"
|
||||
name="password-confirmation"
|
||||
errorMessage={passwordConfirmationError}
|
||||
required
|
||||
/>
|
||||
<br />
|
||||
<br />
|
||||
<Button>Sign up</Button>
|
||||
<br />
|
||||
<div className="flex gap-2">
|
||||
<P>Already have an account?</P>
|
||||
<Link to="/login">Log in instead</Link>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
// return (
|
||||
// <div
|
||||
// className="fixed w-full overflow-scroll"
|
||||
// style={{ height: "calc(100% - 72px)" }}
|
||||
// >
|
||||
// <div className="mx-auto my-6 w-10/12 max-w-2xl">
|
||||
// <H1 className="text-center">Sign Up to Storyteller</H1>
|
||||
// </div>
|
||||
// <div className="mx-auto my-6 w-10/12 max-w-2xl rounded-lg border border-ui-panel-border bg-ui-panel p-6">
|
||||
// <form ref={formRef} onSubmit={handleOnSubmit}>
|
||||
// <Input
|
||||
// label="Username"
|
||||
// icon={faUser}
|
||||
// placeholder="Username"
|
||||
// name="username"
|
||||
// errorMessage={usernameError}
|
||||
// required
|
||||
// />
|
||||
// <br />
|
||||
// <Input
|
||||
// type="email"
|
||||
// label="Email"
|
||||
// icon={faEnvelope}
|
||||
// placeholder="Email"
|
||||
// name="email"
|
||||
// errorMessage={emailError}
|
||||
// required
|
||||
// />
|
||||
// <br />
|
||||
// <Input
|
||||
// type="password"
|
||||
// label="Password"
|
||||
// icon={faKey}
|
||||
// name="password"
|
||||
// placeholder="Password"
|
||||
// autoComplete="current-password"
|
||||
// errorMessage={passwordError}
|
||||
// required
|
||||
// />
|
||||
// <br />
|
||||
// <Input
|
||||
// type="password"
|
||||
// label="Password Confrimation"
|
||||
// icon={faKey}
|
||||
// placeholder="Password Confirmation"
|
||||
// name="password-confirmation"
|
||||
// errorMessage={passwordConfirmationError}
|
||||
// required
|
||||
// />
|
||||
// <br />
|
||||
// <br />
|
||||
// <Button>Sign up</Button>
|
||||
// <div className="flex gap-2">
|
||||
// <P>Back to home</P>
|
||||
// <Link to="/">Back</Link>
|
||||
// </div>
|
||||
// <br />
|
||||
// <div className="flex gap-2">
|
||||
// <P>Already have an account?</P>
|
||||
// <Link to="/login">Log in instead</Link>
|
||||
// </div>
|
||||
// </form>
|
||||
// </div>
|
||||
// </div>
|
||||
// );
|
||||
// }
|
||||
@@ -160,6 +160,15 @@ export default function SignUpScreen() {
|
||||
</form>
|
||||
</div>
|
||||
<div className="align-items flex w-full max-w-xl rounded-b-xl bg-ui-controls px-6 py-4">
|
||||
<div className="flex w-full justify-start gap-1 text-sm">
|
||||
<p className="opacity-75"></p>
|
||||
<a
|
||||
href="/"
|
||||
className="font-medium text-brand-primary-400 hover:text-brand-primary-300"
|
||||
>
|
||||
Back
|
||||
</a>
|
||||
</div>
|
||||
<div className="flex w-full justify-end gap-1 text-sm">
|
||||
<p className="opacity-75">Already have an account?</p>
|
||||
<a
|
||||
|
||||
Reference in new issue
Block a user