mirror of
https://github.com/Nezumi-2711/react-training.git
synced 2026-09-22 20:01:59 +00:00
Add create account pages
This commit is contained in:
@@ -16,10 +16,10 @@ import Room from './pages/Room';
|
||||
import NotFound from './pages/NotFound';
|
||||
import Login from '@src/pages/Login';
|
||||
import Account from '@src/pages/Account';
|
||||
import SignUpAccount from '@src/pages/SignUpAccount';
|
||||
|
||||
// Constants
|
||||
import * as PATH from './constants/path';
|
||||
import SignUpAccount from "@src/pages/SignUpAccount";
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
|
||||
@@ -42,7 +42,10 @@ function App() {
|
||||
<Route path={PATH.USER} element={<User />} />
|
||||
<Route path={PATH.ROOM} element={<Room />} />
|
||||
<Route path={PATH.ACCOUNT} element={<Account />} />
|
||||
<Route path={PATH.SIGN_UP_ACCOUNT} element={<SignUpAccount />} />
|
||||
<Route
|
||||
path={PATH.SIGN_UP_ACCOUNT}
|
||||
element={<SignUpAccount />}
|
||||
/>
|
||||
</Route>
|
||||
<Route path={PATH.LOGIN} element={<Login />} />
|
||||
<Route path={PATH.OTHER_PATH} element={<NotFound />} />
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { createAccount as createAccountFn } from '@src/services/authenticationService.ts';
|
||||
import toast from 'react-hot-toast';
|
||||
|
||||
const useSignUpAccount = () => {
|
||||
const { mutate: createAccount, isPending: isCreating } = useMutation({
|
||||
mutationFn: createAccountFn,
|
||||
onSuccess: (account) => {
|
||||
toast.success(`Create user ${account!.user!.email} successful!`);
|
||||
},
|
||||
onError: (err) => toast.error(err.message),
|
||||
});
|
||||
|
||||
return { createAccount, isCreating };
|
||||
};
|
||||
|
||||
export { useSignUpAccount };
|
||||
@@ -0,0 +1,107 @@
|
||||
import { useForm } from 'react-hook-form';
|
||||
import Form from '@src/components/Form';
|
||||
import Input from '@src/commons/styles/Input.ts';
|
||||
import { isValidRegex, isValidString } from '@src/helpers/validators.ts';
|
||||
import { REGEX } from '@src/constants/commons.ts';
|
||||
import {
|
||||
INVALID_EMAIL,
|
||||
INVALID_STRING,
|
||||
PASSWORD_CONDITION,
|
||||
PASSWORD_NOT_MATCH,
|
||||
PASSWORD_NOT_MATCH_REQUIREMENT,
|
||||
REQUIRED_FIELD_ERROR,
|
||||
} from '@src/constants/formValidateMessage.ts';
|
||||
import { useEffect } from 'react';
|
||||
import toast from 'react-hot-toast';
|
||||
import { useSignUpAccount } from '@src/hooks/authentication/useSignUpAccount.ts';
|
||||
|
||||
interface ISignUpAccountForm {
|
||||
email: string;
|
||||
fullName: string;
|
||||
password: string;
|
||||
confirmPassword: string;
|
||||
}
|
||||
|
||||
const SignUpAccountForm = () => {
|
||||
const { createAccount, isCreating } = useSignUpAccount();
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
formState: { errors },
|
||||
getValues,
|
||||
reset,
|
||||
} = useForm<ISignUpAccountForm>();
|
||||
|
||||
useEffect(() => {
|
||||
if (errors?.password?.message) {
|
||||
toast.error(PASSWORD_CONDITION);
|
||||
}
|
||||
}, [errors?.password?.message]);
|
||||
|
||||
const onSubmit = (data: ISignUpAccountForm) => {
|
||||
createAccount({ email: data.email, password: data.password });
|
||||
|
||||
reset();
|
||||
};
|
||||
|
||||
return (
|
||||
<Form onSubmit={handleSubmit(onSubmit)}>
|
||||
<Form.Row label="Email:" error={errors?.email?.message as string}>
|
||||
<Input
|
||||
id="email"
|
||||
{...register('email', {
|
||||
required: REQUIRED_FIELD_ERROR,
|
||||
validate: (value) =>
|
||||
isValidRegex(REGEX.EMAIL, value) || INVALID_EMAIL,
|
||||
})}
|
||||
/>
|
||||
</Form.Row>
|
||||
|
||||
<Form.Row label="Full Name:" error={errors?.fullName?.message as string}>
|
||||
<Input
|
||||
id="fullName"
|
||||
{...register('fullName', {
|
||||
required: REQUIRED_FIELD_ERROR,
|
||||
validate: (value) => isValidString(value) || INVALID_STRING,
|
||||
})}
|
||||
/>
|
||||
</Form.Row>
|
||||
|
||||
<Form.Row label="Password:" error={errors?.password?.message}>
|
||||
<Input
|
||||
id="password"
|
||||
type="password"
|
||||
{...register('password', {
|
||||
validate: {
|
||||
checkPassword: (v) =>
|
||||
isValidRegex(REGEX.PASSWORD, v) ||
|
||||
PASSWORD_NOT_MATCH_REQUIREMENT,
|
||||
},
|
||||
})}
|
||||
/>
|
||||
</Form.Row>
|
||||
|
||||
<Form.Row
|
||||
label="Confirm Password:"
|
||||
error={errors?.confirmPassword?.message}
|
||||
>
|
||||
<Input
|
||||
id="confirmPassword"
|
||||
type="password"
|
||||
{...register('confirmPassword', {
|
||||
validate: (value) =>
|
||||
getValues().password === value || PASSWORD_NOT_MATCH,
|
||||
})}
|
||||
/>
|
||||
</Form.Row>
|
||||
|
||||
<Form.Action>
|
||||
<Form.Button type="submit" name="submit" disabled={isCreating}>
|
||||
Create Account
|
||||
</Form.Button>
|
||||
</Form.Action>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default SignUpAccountForm;
|
||||
@@ -0,0 +1,18 @@
|
||||
import {FormArea, StyledSignUpAccount, Title} from "@src/pages/SignUpAccount/styled.ts";
|
||||
import SignUpForm from "@src/pages/SignUpAccount/SignUpForm.tsx";
|
||||
|
||||
|
||||
const SignUpAccount = () => {
|
||||
return (
|
||||
<StyledSignUpAccount>
|
||||
<Title>Create account</Title>
|
||||
|
||||
<FormArea>
|
||||
<SignUpForm />
|
||||
</FormArea>
|
||||
|
||||
</StyledSignUpAccount>
|
||||
);
|
||||
}
|
||||
|
||||
export default SignUpAccount;
|
||||
@@ -0,0 +1,31 @@
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Title = styled.h2`
|
||||
font-size: var(--fs-md);
|
||||
color: var(--dark-text);
|
||||
text-transform: capitalize;
|
||||
`;
|
||||
|
||||
const StyledSignUpAccount = styled.div`
|
||||
padding: 20px;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const FormArea = styled.div`
|
||||
border-radius: var(--radius-sm);
|
||||
border: 1px solid var(--border-color);
|
||||
|
||||
padding: 20px 40px;
|
||||
width: 500px;
|
||||
|
||||
margin-top: 50px;
|
||||
`
|
||||
|
||||
export {
|
||||
Title,
|
||||
StyledSignUpAccount,
|
||||
FormArea,
|
||||
};
|
||||
Reference in New Issue
Block a user