From e0de722e877ac76da44565c23a9442a4ddf34d22 Mon Sep 17 00:00:00 2001 From: Loi Phan Date: Fri, 15 Dec 2023 09:56:42 +0700 Subject: [PATCH 1/2] Implement create account function --- hotel-management/src/App.tsx | 2 ++ .../src/components/Header/index.tsx | 12 +++++--- hotel-management/src/components/Nav/index.tsx | 7 ++++- .../src/constants/formValidateMessage.ts | 4 +-- hotel-management/src/constants/path.ts | 2 ++ hotel-management/src/pages/Login/styled.ts | 2 +- .../src/services/authenticationService.ts | 29 ++++++++++++++++++- hotel-management/src/types/account.ts | 1 + 8 files changed, 50 insertions(+), 9 deletions(-) diff --git a/hotel-management/src/App.tsx b/hotel-management/src/App.tsx index b837bdc..618c22d 100644 --- a/hotel-management/src/App.tsx +++ b/hotel-management/src/App.tsx @@ -19,6 +19,7 @@ import Account from '@src/pages/Account'; // Constants import * as PATH from './constants/path'; +import SignUpAccount from "@src/pages/SignUpAccount"; const queryClient = new QueryClient(); @@ -41,6 +42,7 @@ function App() { } /> } /> } /> + } /> } /> } /> diff --git a/hotel-management/src/components/Header/index.tsx b/hotel-management/src/components/Header/index.tsx index b286703..5cc6e03 100644 --- a/hotel-management/src/components/Header/index.tsx +++ b/hotel-management/src/components/Header/index.tsx @@ -2,17 +2,21 @@ import HeaderMenu from '../HeaderMenu'; // Styled -import { StyledHeader } from './styled'; +import {StyledHeader} from './styled'; interface IHeader { accountName: string; } -const Header = ({ accountName }: IHeader) => { +const Header = ({accountName}: IHeader) => { return ( -

Hi, {accountName}!

- +

Hi, { + accountName + ? accountName + : 'Admin' + }!

+
); }; diff --git a/hotel-management/src/components/Nav/index.tsx b/hotel-management/src/components/Nav/index.tsx index ff938ce..6c9b01a 100644 --- a/hotel-management/src/components/Nav/index.tsx +++ b/hotel-management/src/components/Nav/index.tsx @@ -7,7 +7,8 @@ import { BsHouseDoorFill } from 'react-icons/bs'; import { StyledNav, StyledNavLink } from './styled'; // Constants -import { BOOKING, ROOM, USER } from '@src/constants/path'; +import {BOOKING, ROOM, SIGN_UP_ACCOUNT, USER} from '@src/constants/path'; +import {FaUserPlus} from "react-icons/fa6"; const Nav = () => { return ( @@ -24,6 +25,10 @@ const Nav = () => { Room + + + Create Account + ); }; diff --git a/hotel-management/src/constants/formValidateMessage.ts b/hotel-management/src/constants/formValidateMessage.ts index d731c40..f6e5665 100644 --- a/hotel-management/src/constants/formValidateMessage.ts +++ b/hotel-management/src/constants/formValidateMessage.ts @@ -1,17 +1,16 @@ const INVALID_FIELD = 'This field is invalid format!'; const INVALID_PHONE = 'Phone number is invalid!'; const REQUIRED_FIELD_ERROR = 'This field is required!'; -const INVALID_DISCOUNT = 'Discount should be greater than 0 and less than 100!'; const PASSWORD_CONDITION = 'Your password must have 1 uppercase, 1 lowercase, 1 special character, min 1 number and the length between from 8 to 16!'; const INVALID_PASSWORD = 'Invalid password'; const PASSWORD_NOT_MATCH = 'Password not match!'; const PASSWORD_NOT_MATCH_REQUIREMENT = 'Password not match the requirement!'; const INVALID_EMAIL = 'Invalid email address'; +const INVALID_STRING = 'This field need more than 5 characters!'; export { REQUIRED_FIELD_ERROR, - INVALID_DISCOUNT, INVALID_FIELD, INVALID_PHONE, PASSWORD_CONDITION, @@ -19,4 +18,5 @@ export { PASSWORD_NOT_MATCH, PASSWORD_NOT_MATCH_REQUIREMENT, INVALID_EMAIL, + INVALID_STRING }; diff --git a/hotel-management/src/constants/path.ts b/hotel-management/src/constants/path.ts index 12aa02b..f4a22ab 100644 --- a/hotel-management/src/constants/path.ts +++ b/hotel-management/src/constants/path.ts @@ -2,6 +2,7 @@ const BOOKING = '/booking'; const USER = '/user'; const ROOM = '/room'; const ACCOUNT = '/account'; +const SIGN_UP_ACCOUNT = '/createAccount' const OTHER_PATH = '*'; const LOGIN = 'login'; @@ -12,4 +13,5 @@ export { ACCOUNT, OTHER_PATH, LOGIN, + SIGN_UP_ACCOUNT, } diff --git a/hotel-management/src/pages/Login/styled.ts b/hotel-management/src/pages/Login/styled.ts index a5bfa43..1c583b4 100644 --- a/hotel-management/src/pages/Login/styled.ts +++ b/hotel-management/src/pages/Login/styled.ts @@ -35,7 +35,7 @@ const StyledLoginForm = styled.div` `; const FieldInput = styled.input` - ${CommonInput} + ${CommonInput}; width: 300px; ` diff --git a/hotel-management/src/services/authenticationService.ts b/hotel-management/src/services/authenticationService.ts index ef43fd0..138a4fb 100644 --- a/hotel-management/src/services/authenticationService.ts +++ b/hotel-management/src/services/authenticationService.ts @@ -6,6 +6,7 @@ import supabase from './supabaseService'; // Types import { IAccount } from '@src/types/account'; +import toast from 'react-hot-toast'; /** * Login services @@ -82,4 +83,30 @@ const updateAccount = async ({ fullName, password }: IAccount) => { return data; }; -export { login, logout, getCurrentAccount, updateAccount }; +const createAccount = async ({ email, password }: IAccount) => { + if (!email || !password) { + toast.error('Email and password is not valid!'); + + return; + } + + const { data, error } = await supabase.auth.signUp({ + email, + password, + }); + + if (error) { + console.error(error.message); + throw new Error(error.message); + } + + return data; +}; + +export { + login, + logout, + getCurrentAccount, + updateAccount, + createAccount +}; diff --git a/hotel-management/src/types/account.ts b/hotel-management/src/types/account.ts index 1413d0c..256d87f 100644 --- a/hotel-management/src/types/account.ts +++ b/hotel-management/src/types/account.ts @@ -1,4 +1,5 @@ interface IAccount { + email?: string; fullName?: string; password?: string; } From 98a8b2fa04bc479a2952c635d4aff57c05bae749 Mon Sep 17 00:00:00 2001 From: Loi Phan Date: Fri, 15 Dec 2023 10:00:09 +0700 Subject: [PATCH 2/2] Add create account pages --- hotel-management/src/App.tsx | 7 +- .../hooks/authentication/useSignUpAccount.ts | 17 +++ .../src/pages/SignUpAccount/SignUpForm.tsx | 107 ++++++++++++++++++ .../src/pages/SignUpAccount/index.tsx | 18 +++ .../src/pages/SignUpAccount/styled.ts | 31 +++++ 5 files changed, 178 insertions(+), 2 deletions(-) create mode 100644 hotel-management/src/hooks/authentication/useSignUpAccount.ts create mode 100644 hotel-management/src/pages/SignUpAccount/SignUpForm.tsx create mode 100644 hotel-management/src/pages/SignUpAccount/index.tsx create mode 100644 hotel-management/src/pages/SignUpAccount/styled.ts diff --git a/hotel-management/src/App.tsx b/hotel-management/src/App.tsx index 618c22d..7f685f7 100644 --- a/hotel-management/src/App.tsx +++ b/hotel-management/src/App.tsx @@ -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() { } /> } /> } /> - } /> + } + /> } /> } /> diff --git a/hotel-management/src/hooks/authentication/useSignUpAccount.ts b/hotel-management/src/hooks/authentication/useSignUpAccount.ts new file mode 100644 index 0000000..24e37ae --- /dev/null +++ b/hotel-management/src/hooks/authentication/useSignUpAccount.ts @@ -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 }; diff --git a/hotel-management/src/pages/SignUpAccount/SignUpForm.tsx b/hotel-management/src/pages/SignUpAccount/SignUpForm.tsx new file mode 100644 index 0000000..c9e9d45 --- /dev/null +++ b/hotel-management/src/pages/SignUpAccount/SignUpForm.tsx @@ -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(); + + 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 ( +
+ + + isValidRegex(REGEX.EMAIL, value) || INVALID_EMAIL, + })} + /> + + + + isValidString(value) || INVALID_STRING, + })} + /> + + + + + isValidRegex(REGEX.PASSWORD, v) || + PASSWORD_NOT_MATCH_REQUIREMENT, + }, + })} + /> + + + + + getValues().password === value || PASSWORD_NOT_MATCH, + })} + /> + + + + + Create Account + + +
+ ); +}; + +export default SignUpAccountForm; diff --git a/hotel-management/src/pages/SignUpAccount/index.tsx b/hotel-management/src/pages/SignUpAccount/index.tsx new file mode 100644 index 0000000..7eb96e9 --- /dev/null +++ b/hotel-management/src/pages/SignUpAccount/index.tsx @@ -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 ( + + Create account + + + + + + + ); +} + +export default SignUpAccount; diff --git a/hotel-management/src/pages/SignUpAccount/styled.ts b/hotel-management/src/pages/SignUpAccount/styled.ts new file mode 100644 index 0000000..b70e8d6 --- /dev/null +++ b/hotel-management/src/pages/SignUpAccount/styled.ts @@ -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, +};