1
0
mirror of https://github.com/spacebarchat/client.git synced 2024-11-22 10:22:30 +01:00

auth layout changes

This commit is contained in:
Puyodead1 2023-08-08 18:20:36 -04:00
parent d2a4b4f3cf
commit be4595ddce
No known key found for this signature in database
GPG Key ID: A4FA4FEC0DD353FC
4 changed files with 262 additions and 308 deletions

View File

@ -0,0 +1,156 @@
import styled from "styled-components";
import Button from "./Button";
import Container from "./Container";
export const Wrapper = styled(Container)`
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: var(--background-tertiary);
`;
export const AuthContainer = styled(Container)`
background-color: var(--background-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;
}
`;
export const HeaderContainer = styled.div`
width: 100%;
`;
export const Header = styled.h1`
margin-bottom: 3px;
color: var(--text);
font-weight: 600;
font-size: 24px;
`;
export const SubHeader = styled.h2<{ noBranding?: boolean }>`
margin-top: 3px;
color: var(--text-muted);
font-weight: 400;
font-size: ${(props) => (props.noBranding ? "20px" : "16px")};
`;
export const FormContainer = styled.form`
width: 100%;
`;
export const InputContainer = styled.h1<{ marginBottom: boolean }>`
margin-bottom: ${(props) => (props.marginBottom ? "20px" : "0")};
display: flex;
flex-direction: column;
align-items: flex-start;
`;
export const LabelWrapper = styled.div<{ error?: boolean }>`
display: flex;
flex-direction: row;
margin-bottom: 8px;
color: ${(props) => (props.error ? "var(--error)" : "var(--text)")};
`;
export const InputErrorText = styled.label`
font-size: 14px;
font-weight: 400;
font-style: italic;
`;
export const InputLabel = styled.label`
font-size: 14px;
font-weight: 700;
`;
export const InputWrapper = styled.div`
width: 100%;
display: flex;
`;
// TODO: Fix border hover causing small layout shift
export const Input = styled.input<{ error?: boolean }>`
outline: none;
background: var(--background-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")};
border: ${(props) => (props.error ? "1px solid var(--error)" : "none")};
&:focus {
border: 1px solid var(--primary);
}
`;
export const PasswordResetLink = styled.button`
margin-bottom: 20px;
margin-top: 4px;
padding: 2px 0;
font-size: 14px;
display: flex;
color: var(--text-link);
background: none;
border: none;
&:hover {
text-decoration: underline;
cursor: pointer;
}
`;
export const SubmitButton = styled(Button)`
margin-bottom: 8px;
width: 100%;
min-width: 130px;
min-height: 44px;
font-size: 14px;
`;
export const AuthSwitchPageContainer = styled.div`
margin-top: 4px;
text-align: initial;
`;
export const AuthSwitchPageLabel = styled.label`
font-size: 14px;
`;
export const AuthSwitchPageLink = styled.button`
font-size: 14px;
background: none;
border: none;
color: var(--text-link);
@media (max-width: 480px) {
display: inline-block;
}
&:hover {
text-decoration: underline;
cursor: pointer;
}
`;
export const Divider = styled.span`
padding: 0 4px;
`;

View File

@ -3,12 +3,28 @@ import { Routes } from "@spacebarchat/spacebar-api-types/v9";
import React from "react"; import React from "react";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import styled from "styled-components"; import {
import Button from "../components/Button"; AuthContainer,
import Container from "../components/Container"; AuthSwitchPageContainer,
import HCaptcha from "../components/HCaptcha"; AuthSwitchPageLabel,
AuthSwitchPageLink,
Divider,
FormContainer,
Header,
Input,
InputContainer,
InputErrorText,
InputLabel,
InputWrapper,
LabelWrapper,
PasswordResetLink,
SubHeader,
SubmitButton,
Wrapper,
} from "../components/AuthComponents";
import HCaptcha, { HeaderContainer } from "../components/HCaptcha";
import MFA from "../components/MFA"; import MFA from "../components/MFA";
import { useAppStore } from "../stores/AppStore"; import { AUTH_NO_BRANDING, useAppStore } from "../stores/AppStore";
import { import {
IAPILoginRequest, IAPILoginRequest,
IAPILoginResponse, IAPILoginResponse,
@ -17,151 +33,6 @@ import {
} from "../utils/interfaces/api"; } from "../utils/interfaces/api";
import { messageFromFieldError } from "../utils/messageFromFieldError"; import { messageFromFieldError } from "../utils/messageFromFieldError";
export const Wrapper = styled(Container)`
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: var(--background-tertiary);
`;
export const AuthBox = styled(Container)`
background-color: var(--background-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;
}
`;
export const HeaderContainer = styled.div`
width: 100%;
`;
export const Header = styled.h1`
font-weight: 600;
margin-bottom: 8px;
font-size: 24px;
color: var(--text);
`;
export const SubHeader = styled.h2`
color: var(--text-muted);
font-weight: 400;
font-size: 16px;
`;
export const FormContainer = styled.form`
width: 100%;
`;
export const InputContainer = styled.h1<{ marginBottom: boolean }>`
margin-bottom: ${(props) => (props.marginBottom ? "20px" : "0")};
display: flex;
flex-direction: column;
align-items: flex-start;
`;
export const LabelWrapper = styled.div<{ error?: boolean }>`
display: flex;
flex-direction: row;
margin-bottom: 8px;
color: ${(props) => (props.error ? "var(--error)" : "#b1b5bc")};
`;
export const InputErrorText = styled.label`
font-size: 14px;
font-weight: 400;
font-style: italic;
`;
export const InputLabel = styled.label`
font-size: 14px;
font-weight: 700;
`;
export const InputWrapper = styled.div`
width: 100%;
display: flex;
`;
export const Input = styled.input<{ error?: boolean }>`
outline: none;
background: var(--background-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")};
`;
export const PasswordResetLink = styled.button`
margin-bottom: 20px;
margin-top: 4px;
padding: 2px 0;
font-size: 14px;
display: flex;
color: var(--text-link);
background: none;
border: none;
&:hover {
text-decoration: underline;
cursor: pointer;
}
`;
export const LoginButton = styled(Button)`
margin-bottom: 8px;
width: 100%;
min-width: 130px;
min-height: 44px;
`;
export const RegisterContainer = styled.div`
margin-top: 4px;
text-align: initial;
`;
export const RegisterLabel = styled.label`
font-size: 14px;
`;
export const RegisterLink = styled.button`
font-size: 14px;
background: none;
border: none;
color: var(--text-link);
@media (max-width: 480px) {
display: inline-block;
}
&:hover {
text-decoration: underline;
cursor: pointer;
}
`;
export const Divider = styled.span`
padding: 0 4px;
`;
type FormValues = { type FormValues = {
login: string; login: string;
password: string; password: string;
@ -299,10 +170,22 @@ function LoginPage() {
return ( return (
<Wrapper> <Wrapper>
<AuthBox> <AuthContainer>
<HeaderContainer> <HeaderContainer>
<Header>Welcome Back!</Header> {AUTH_NO_BRANDING ? (
<SubHeader>We're so excited to see you again!</SubHeader> <>
<Header>Login to Spacebar</Header>
</>
) : (
<>
{/* Note: This would need to change depending on the theme */}
<img
src="https://github.com/spacebarchat/spacebarchat/blob/master/branding/png/Spacebar__Logo-White.png?raw=true"
height={48}
/>
<SubHeader noBranding>Log into Spacebar</SubHeader>
</>
)}
</HeaderContainer> </HeaderContainer>
<FormContainer onSubmit={onSubmit}> <FormContainer onSubmit={onSubmit}>
@ -324,6 +207,7 @@ function LoginPage() {
<InputWrapper> <InputWrapper>
<Input <Input
type="email" type="email"
placeholder="Email"
autoFocus autoFocus
{...register("login", { required: true })} {...register("login", { required: true })}
error={!!errors.login} error={!!errors.login}
@ -347,6 +231,7 @@ function LoginPage() {
<InputWrapper> <InputWrapper>
<Input <Input
type="password" type="password"
placeholder="Password"
{...register("password", { required: true })} {...register("password", { required: true })}
error={!!errors.password} error={!!errors.password}
disabled={loading} disabled={loading}
@ -366,29 +251,29 @@ function LoginPage() {
Forgot your password? Forgot your password?
</PasswordResetLink> </PasswordResetLink>
<LoginButton <SubmitButton
variant="primary" variant="primary"
type="submit" type="submit"
disabled={loading} disabled={loading}
> >
Log In Login
</LoginButton> </SubmitButton>
<RegisterContainer> <AuthSwitchPageContainer>
<RegisterLabel> <AuthSwitchPageLabel>
Don't have an account?&nbsp; New to Spacebar?&nbsp;
</RegisterLabel> </AuthSwitchPageLabel>
<RegisterLink <AuthSwitchPageLink
onClick={() => { onClick={() => {
navigate("/register"); navigate("/register");
}} }}
type="button" type="button"
> >
Sign Up Register
</RegisterLink> </AuthSwitchPageLink>
</RegisterContainer> </AuthSwitchPageContainer>
</FormContainer> </FormContainer>
</AuthBox> </AuthContainer>
</Wrapper> </Wrapper>
); );
} }

View File

@ -3,12 +3,27 @@ import { Routes } from "@spacebarchat/spacebar-api-types/v9";
import React from "react"; import React from "react";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import styled from "styled-components"; import {
import Button from "../components/Button"; AuthContainer,
import Container from "../components/Container"; AuthSwitchPageContainer,
AuthSwitchPageLabel,
AuthSwitchPageLink,
Divider,
FormContainer,
Header,
Input,
InputContainer,
InputErrorText,
InputLabel,
InputWrapper,
LabelWrapper,
SubHeader,
SubmitButton,
Wrapper,
} from "../components/AuthComponents";
import DOBInput from "../components/DOBInput"; import DOBInput from "../components/DOBInput";
import HCaptcha from "../components/HCaptcha"; import HCaptcha from "../components/HCaptcha";
import { useAppStore } from "../stores/AppStore"; import { AUTH_NO_BRANDING, useAppStore } from "../stores/AppStore";
import { import {
IAPILoginResponseSuccess, IAPILoginResponseSuccess,
IAPIRegisterRequest, IAPIRegisterRequest,
@ -16,129 +31,6 @@ import {
} from "../utils/interfaces/api"; } from "../utils/interfaces/api";
import { messageFromFieldError } from "../utils/messageFromFieldError"; import { messageFromFieldError } from "../utils/messageFromFieldError";
const Wrapper = styled(Container)`
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: var(--background-tertiary);
`;
const AuthBox = styled(Container)`
background-color: var(--background-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(--background-secondary);
padding: 10px;
font-size: 16px;
border-radius: 12px;
color: var(--text);
margin: 0;
border: none;
aria-invalid: ${(props) => (props.error ? "true" : "false")};
box-sizing: border-box;
width: 100%;
`;
const LoginButton = styled(Button)`
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 FormValues = { type FormValues = {
email: string; email: string;
username: string; username: string;
@ -279,11 +171,21 @@ function RegistrationPage() {
return ( return (
<Wrapper> <Wrapper>
<AuthBox> <AuthContainer>
<HeaderContainer> {AUTH_NO_BRANDING ? (
<Header>Create an account</Header> <>
{/* <SubHeader>We're so excited to see you again!</SubHeader> */} <Header>Create an account</Header>
</HeaderContainer> </>
) : (
<>
{/* Note: This would need to change depending on the theme */}
<img
src="https://github.com/spacebarchat/spacebarchat/blob/master/branding/png/Spacebar__Logo-White.png?raw=true"
height={48}
/>
<SubHeader noBranding>Create an account</SubHeader>
</>
)}
<FormContainer onSubmit={onSubmit}> <FormContainer onSubmit={onSubmit}>
<InputContainer <InputContainer
@ -304,6 +206,7 @@ function RegistrationPage() {
<InputWrapper> <InputWrapper>
<Input <Input
type="email" type="email"
placeholder="Email"
autoFocus autoFocus
{...register("email", { required: true })} {...register("email", { required: true })}
error={!!errors.email} error={!!errors.email}
@ -330,6 +233,7 @@ function RegistrationPage() {
<InputWrapper> <InputWrapper>
<Input <Input
{...register("username", { required: true })} {...register("username", { required: true })}
placeholder="Username"
error={!!errors.username} error={!!errors.username}
disabled={loading} disabled={loading}
/> />
@ -351,6 +255,7 @@ function RegistrationPage() {
<InputWrapper> <InputWrapper>
<Input <Input
type="password" type="password"
placeholder="Password"
{...register("password", { required: true })} {...register("password", { required: true })}
error={!!errors.password} error={!!errors.password}
disabled={loading} disabled={loading}
@ -396,24 +301,29 @@ function RegistrationPage() {
</InputWrapper> </InputWrapper>
</InputContainer> </InputContainer>
<LoginButton <SubmitButton
variant="primary" variant="primary"
type="submit" type="submit"
disabled={loading} disabled={loading}
> >
Create Account Create Account
</LoginButton> </SubmitButton>
<LoginLink <AuthSwitchPageContainer>
onClick={() => { <AuthSwitchPageLabel>
navigate("/login", { replace: true }); Already have an account?&nbsp;
}} </AuthSwitchPageLabel>
type="button" <AuthSwitchPageLink
> onClick={() => {
Already have an account? navigate("/login");
</LoginLink> }}
type="button"
>
Login
</AuthSwitchPageLink>
</AuthSwitchPageContainer>
</FormContainer> </FormContainer>
</AuthBox> </AuthContainer>
</Wrapper> </Wrapper>
); );
} }

View File

@ -12,6 +12,9 @@ import PrivateChannelStore from "./PrivateChannelStore";
import ThemeStore from "./ThemeStore"; import ThemeStore from "./ThemeStore";
import UserStore from "./UserStore"; import UserStore from "./UserStore";
// dev thing to force toggle branding on auth pages for testing.
export const AUTH_NO_BRANDING = false;
export default class AppStore { export default class AppStore {
// whether the gateway is ready // whether the gateway is ready
@observable isGatewayReady = false; @observable isGatewayReady = false;