From 5e65f1de7a09b8757cabcabba24e03f7f7f4d916 Mon Sep 17 00:00:00 2001 From: favor-star Date: Tue, 4 Jun 2024 17:48:48 +0200 Subject: [PATCH] [Finshes #187354196] Sign up page --- package.json | 8 +- src/App.tsx | 38 ++-- src/assets/googleIcon.svg | 6 + src/components/Button.tsx | 22 ++ src/components/Input.tsx | 34 ++++ src/components/Select.tsx | 24 +++ src/components/register/InfoTip.tsx | 27 +++ src/components/register/Navbar.tsx | 29 +++ src/components/register/RegisterSection.tsx | 190 ++++++++++++++++++ src/components/register/Success.tsx | 15 ++ src/pages/Register.tsx | 14 ++ src/state/register/registerSlice.ts | 23 +++ src/state/store.ts | 2 + src/utils/index.ts | 6 + tailwind.config.js | 15 +- tsconfig.json | 1 - ....timestamp-1717503390378-4d6707c4e34b1.mjs | 27 +++ 17 files changed, 459 insertions(+), 22 deletions(-) create mode 100644 src/assets/googleIcon.svg create mode 100644 src/components/Button.tsx create mode 100644 src/components/Input.tsx create mode 100644 src/components/Select.tsx create mode 100644 src/components/register/InfoTip.tsx create mode 100644 src/components/register/Navbar.tsx create mode 100644 src/components/register/RegisterSection.tsx create mode 100644 src/components/register/Success.tsx create mode 100644 src/pages/Register.tsx create mode 100644 src/state/register/registerSlice.ts create mode 100644 src/utils/index.ts create mode 100644 vite.config.ts.timestamp-1717503390378-4d6707c4e34b1.mjs diff --git a/package.json b/package.json index 0cfb066..b719e41 100644 --- a/package.json +++ b/package.json @@ -15,13 +15,19 @@ "build-storybook": "storybook build" }, "dependencies": { + "@hookform/resolvers": "^3.6.0", + "@remixicon/react": "^4.2.0", + "clsx": "^2.1.1", "@reduxjs/toolkit": "^2.2.5", "@types/react-redux": "^7.1.33", "lucide-react": "^0.387.0", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-redux": "^9.1.2", + "react-hook-form": "^7.51.5", "react-router-dom": "^6.23.1", + "react-redux": "^9.1.2", + "tailwind-merge": "^2.3.0", + "zod": "^3.23.8", "sass": "^1.77.2" }, "devDependencies": { diff --git a/src/App.tsx b/src/App.tsx index 85b8fde..5787502 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,26 +1,38 @@ -import { RouterProvider, createBrowserRouter } from "react-router-dom"; -import Login from "./pages/Login"; -import LandingPage from "./pages/LandingPage"; +import Register from './pages/Register'; +import Success from './components/register/Success'; +import RegisterSection from './components/register/RegisterSection'; +import { RouterProvider, createBrowserRouter } from 'react-router-dom'; +import Login from './pages/Login'; +import LandingPage from './pages/LandingPage'; const App = () => { const router = createBrowserRouter([ { - path: "/", + path: '/', children: [ { index: true, - element: + element: , }, { - path: "login", - element: - } - ] + path: 'login', + element: , + }, + ], + }, + { + path: 'register', + element: , + children: [ + { + path: '/register', + element: , + }, + { path: 'success', element: }, + ], }, - ]) - return ( - - ); + ]); + return ; }; export default App; diff --git a/src/assets/googleIcon.svg b/src/assets/googleIcon.svg new file mode 100644 index 0000000..17322ec --- /dev/null +++ b/src/assets/googleIcon.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/components/Button.tsx b/src/components/Button.tsx new file mode 100644 index 0000000..9db07d4 --- /dev/null +++ b/src/components/Button.tsx @@ -0,0 +1,22 @@ +import { cn } from "../utils"; + +interface ButtonProps { + text: string; + buttonId?: string; + type?: 'submit' | 'reset' | 'button'; + className?: string; + onClick?: () => void; +} +const Button = ({ text, type, className, onClick }: ButtonProps) => { + return ( + + ); +}; + +export default Button; diff --git a/src/components/Input.tsx b/src/components/Input.tsx new file mode 100644 index 0000000..fec8e95 --- /dev/null +++ b/src/components/Input.tsx @@ -0,0 +1,34 @@ +import { forwardRef } from 'react'; +import { cn } from '../utils'; + +interface InputProps { + type: string; + label: string; + id: string; + placeholder: string; + error?: string; + labelClassName?: string; + inputClasname?: string; +} + +// Use React.forwardRef to forward the ref to the input element +const Input = forwardRef( + ({ type, labelClassName, inputClasname, label, id, placeholder, error = '', ...rest }, ref) => { + return ( + + ); + } +); + +export default Input; diff --git a/src/components/Select.tsx b/src/components/Select.tsx new file mode 100644 index 0000000..42170a8 --- /dev/null +++ b/src/components/Select.tsx @@ -0,0 +1,24 @@ +import { forwardRef } from 'react'; + +interface SelectProps { + placeholder: string; + error?: string; + options: string[]; +} +const Select = forwardRef(({ placeholder, options,error,...rest }, ref) => { + return ( + <> + +

{error}

+ + ); +}); + +export default Select; diff --git a/src/components/register/InfoTip.tsx b/src/components/register/InfoTip.tsx new file mode 100644 index 0000000..1a28e6e --- /dev/null +++ b/src/components/register/InfoTip.tsx @@ -0,0 +1,27 @@ +import { RiCloseLargeFill } from '@remixicon/react'; +import { useState } from 'react'; + +const InfoTip = () => { + const [InfoTipClosed, setInfoTipClosed] = useState(false); + + const handleInfoTipClosing = () => { + setInfoTipClosed(true); + }; + return ( + + ); +}; + +export default InfoTip; diff --git a/src/components/register/Navbar.tsx b/src/components/register/Navbar.tsx new file mode 100644 index 0000000..b6de23b --- /dev/null +++ b/src/components/register/Navbar.tsx @@ -0,0 +1,29 @@ +import { RiMenu2Fill, RiPhoneLine, RiQuestionFill, RiSearch2Line } from '@remixicon/react'; + +const Navbar = () => { + return ( +
+ + Mavericks 🏀 + + + + + + + +
+ + + +250 787 922 900 + + + + Help + +
+
+ ); +}; + +export default Navbar; diff --git a/src/components/register/RegisterSection.tsx b/src/components/register/RegisterSection.tsx new file mode 100644 index 0000000..3c4072e --- /dev/null +++ b/src/components/register/RegisterSection.tsx @@ -0,0 +1,190 @@ +import { zodResolver } from '@hookform/resolvers/zod'; +import GoogleIcon from '../../assets/googleIcon.svg'; +import Button from '../Button'; +import Input from '../Input'; +import Select from '../Select'; +import { SubmitHandler, useForm } from 'react-hook-form'; +import { z } from 'zod'; +import { useNavigate } from 'react-router-dom'; +import { useDispatch } from 'react-redux'; +import { signUp } from '../../state/register/registerSlice'; + +type Formfields = z.infer; +interface ExtendedFormFields extends Formfields { + confirmPassword: string; +} +const dbLinks = { + local: 'http://localhost:8080/api/users/signup', + hosted: 'https://e-commerce-mavericcks-bn-staging-istf.onrender.com/api/users/signup', +}; +const RegisterSection = () => { + const navigate = useNavigate(); + const dispatch = useDispatch(); + + const { + register, + handleSubmit, + setError, + formState: { errors, isSubmitting }, + } = useForm({ + resolver: zodResolver(extendedSchema), + }); + const onSubmit: SubmitHandler = async retrievedData => { + const { password, lastName, firstName, gender, phoneNumber, email } = retrievedData; + try { + const response: Response = await fetch(dbLinks['hosted'], { + method: 'post', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ password, lastName, firstName, gender, phoneNumber, email }), + }); + const result = await response.json(); + if (!result.ok) { + console.log(result); + if (/email is already used/gi.test(result.error)) { + setError('root', { + message: 'Email is already used. Login to continue', + }); + setTimeout(() => { + navigate('/login'); + }, 3000); + return; + } + setError('root', { + message: result.message, + }); + return; + // throw new Error(result.error); + } + dispatch(signUp()); + navigate('/register/success'); + } catch (error: any) { + setError('root', { + message: error, + }); + } + }; + + return ( + <> +
+
+

New Customer?

+

Sign Up to continue

+
+
+ + +
+ + + + + +