diff --git a/src/App.tsx b/src/App.tsx index 31d6999..9ff66c8 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -31,13 +31,14 @@ function App() { // handles token changes React.useEffect(() => { - if (!app.api.token && !isLoading) { - console.log("TOKEN REMOVED"); - // remove token - secureLocalStorage.removeItem("token"); - // navigate to login page if token is removed - navigate("/login", { replace: true }); - } + // FIXME: this triggers on load and causes a redirect to login no matter what page we actually want to go to + // if (!app.api.token && !isLoading) { + // console.log("TOKEN REMOVED"); + // // remove token + // secureLocalStorage.removeItem("token"); + // // navigate to login page if token is removed + // navigate("/login", { replace: true }); + // } if (app.api.token) { console.log("TOKEN ADDED"); diff --git a/src/contexts/Theme.tsx b/src/contexts/Theme.tsx index 085bec3..df01d5d 100644 --- a/src/contexts/Theme.tsx +++ b/src/contexts/Theme.tsx @@ -11,6 +11,7 @@ export type ThemeVariables = | "tertiary" | "text" | "textMuted" + | "textLink" | "inputBackground" | "error" | "buttonPrimary" @@ -47,6 +48,7 @@ export const ThemePresets: Record = { tertiary: "#e9e2e1", text: "#000000", textMuted: "#232120", + textLink: "#00a8fc", inputBackground: "#757575", error: "#e83f36", buttonPrimary: "", @@ -74,6 +76,7 @@ export const ThemePresets: Record = { tertiary: "#141212", text: "#e9e2e1", textMuted: "#85898f", + textLink: "#00a8fc", inputBackground: "#121212", error: "#e83f36", // buttons diff --git a/src/pages/LoginPage.tsx b/src/pages/LoginPage.tsx index 7da9c1f..fcd1649 100644 --- a/src/pages/LoginPage.tsx +++ b/src/pages/LoginPage.tsx @@ -1,5 +1,6 @@ import { APIError, CaptchaError, MFAError } from "@puyodead1/fosscord-ts"; import { useForm } from "react-hook-form"; +import { useNavigate } from "react-router-dom"; import styled from "styled-components"; import Button from "../components/Button"; import Container from "../components/Container"; @@ -98,13 +99,20 @@ const Input = styled.input<{ error?: boolean }>` aria-invalid: ${(props) => (props.error ? "true" : "false")}; `; -const PasswordResetLink = styled.a` +const PasswordResetLink = styled.button` margin-bottom: 20px; margin-top: 4px; padding: 2px 0; font-size: 14px; display: flex; - text-decoration: none; + color: var(--text-link); + background: none; + border: none; + + &:hover { + text-decoration: underline; + cursor: pointer; + } `; const LoginButton = styled(Button)` @@ -123,13 +131,20 @@ const RegisterLabel = styled.label` font-size: 14px; `; -const RegisterLink = styled.a` +const RegisterLink = styled.button` font-size: 14px; - text-decoration: none; + background: none; + border: none; + color: var(--text-link); @media (max-width: 480px) { display: inline-block; } + + &:hover { + text-decoration: underline; + cursor: pointer; + } `; const Divider = styled.span` @@ -143,6 +158,7 @@ type LoginFormValues = { function LoginPage() { const app = useAppStore(); + const navigate = useNavigate(); const { register, @@ -224,14 +240,23 @@ function LoginPage() { - Forgot your password? + {}} type="button"> + Forgot your password? + Log In Don't have an account?  - Sign Up + { + navigate("/register"); + }} + type="button" + > + Sign Up + diff --git a/src/pages/RegistrationPage.tsx b/src/pages/RegistrationPage.tsx index 513f84a..dd1d892 100644 --- a/src/pages/RegistrationPage.tsx +++ b/src/pages/RegistrationPage.tsx @@ -1,7 +1,260 @@ +import { useForm } from "react-hook-form"; +import { useNavigate } from "react-router-dom"; +import styled from "styled-components"; +import Button from "../components/Button"; import Container from "../components/Container"; +import { useAppStore } from "../stores/AppStore"; + +const Wrapper = styled(Container)` + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + background-color: var(--secondary); +`; + +const LoginBox = styled(Container)` + background-color: var(--primary-alt); + padding: 32px; + font-size: 18px; + color: var(--text-muted); + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + + @media (max-width: 480px) { + width: 100%; + height: 100%; + } + + @media (min-width: 480px) { + width: 480px; + border-radius: 18px; + } +`; + +const HeaderContainer = styled.div` + width: 100%; +`; + +const Header = styled.h1` + font-weight: 600; + margin-bottom: 8px; + font-size: 24px; + color: var(--text); +`; + +const SubHeader = styled.h2` + color: var(--text-muted); + font-weight: 400; + font-size: 16px; +`; + +const FormContainer = styled.form` + width: 100%; +`; + +const InputContainer = styled.h1<{ marginBottom: boolean }>` + margin-bottom: ${(props) => (props.marginBottom ? "20px" : "0")}; + display: flex; + flex-direction: column; + align-items: flex-start; +`; + +const LabelWrapper = styled.div<{ error?: boolean }>` + display: flex; + flex-direction: row; + margin-bottom: 8px; + color: ${(props) => (props.error ? "var(--error)" : "#b1b5bc")}; +`; + +const InputErrorText = styled.label` + font-size: 14px; + font-weight: 400; + font-style: italic; +`; + +const InputLabel = styled.label` + font-size: 14px; + font-weight: 700; +`; + +const InputWrapper = styled.div` + width: 100%; + display: flex; +`; + +const Input = styled.input<{ error?: boolean }>` + outline: none; + background: var(--secondary); + padding: 10px; + font-size: 16px; + flex: 1; + border-radius: 12px; + color: var(--text); + margin: 0; + border: none; + aria-invalid: ${(props) => (props.error ? "true" : "false")}; +`; +const LoginButton = styled(Button)` + margin-top: 20px; + margin-bottom: 8px; + width: 100%; + min-width: 130px; + min-height: 44px; +`; + +const LoginLink = styled.button` + margin-top: 4px; + float: left; + font-size: 14px; + background: none; + border: none; + color: var(--text-link); + + @media (max-width: 480px) { + display: inline-block; + } + + &:hover { + text-decoration: underline; + cursor: pointer; + } +`; + +const Divider = styled.span` + padding: 0 4px; +`; + +type RegisterFormValues = { + email: string; + username: string; + password: string; + date_of_birth: string; +}; function RegistrationPage() { - return RegistrationPage; + const app = useAppStore(); + const navigate = useNavigate(); + + const { + register, + handleSubmit, + watch, + formState: { errors }, + setError, + } = useForm(); + + const onSubmit = handleSubmit((data) => { + // TODO: + // app.api.login(data).catch((e) => { + // if (e instanceof MFAError) { + // console.log("MFA Required", e); + // } else if (e instanceof CaptchaError) { + // console.log("Captcha Required", e); + // } else if (e instanceof APIError) { + // console.log("APIError", e.message, e.code, e.fieldErrors); + // e.fieldErrors.forEach((fieldError) => { + // setError(fieldError.field as any, { + // type: "manual", + // message: fieldError.error, + // }); + // }); + // } else { + // console.log("General Error", e); + // } + // }); + }); + + return ( + + + +
Create an account
+ {/* We're so excited to see you again! */} +
+ + + + + Email + {errors.email && ( + + <> + - + {errors.email.message} + + + )} + + + + + + + + + Username + {errors.username && ( + + <> + - + {errors.username.message} + + + )} + + + + + + + + + Password + {errors.password && ( + + <> + - + {errors.password.message} + + + )} + + + + + + + + Log In + + + { + navigate("/login", { replace: true }); + }} + type="button" + > + Already have an account? + + +
+
+ ); } export default RegistrationPage;