From cc286462f015f72b66f757ddd85ff220eeee0cd4 Mon Sep 17 00:00:00 2001 From: Mathis Date: Mon, 17 Jun 2024 09:48:38 +0200 Subject: [PATCH] feat(components): add authentication forms This commit introduces authentication forms for both user login and registration. These forms use zod for data validation and context for state management. Login and registration processes have been implemented as asynchronous functions, handling API requests, and error responses. --- src/components/auth-form.tsx | 235 +++++++++++++++++++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 src/components/auth-form.tsx diff --git a/src/components/auth-form.tsx b/src/components/auth-form.tsx new file mode 100644 index 0000000..05859cb --- /dev/null +++ b/src/components/auth-form.tsx @@ -0,0 +1,235 @@ +"use client"; + +import {Tabs, TabsContent, TabsList, TabsTrigger} from "@/components/ui/tabs"; + +import AutoForm, {AutoFormSubmit} from "@/components/auto-form"; +import {UserDataContext} from "@/components/providers/userdata-provider"; +import type {IApiLoginReq, IApiLoginRes, IApiRegisterReq, IApiRegisterRes} from "@/interfaces/api.interface"; +import type {IUserData} from "@/interfaces/userdata.interface"; +import ApiRequest from "@/services/apiRequest"; +import {EReturnState, type IStandardisedReturn} from "@/services/general.interface"; +import {useLocalStorage} from "@/services/localStorage"; +import {Bug, RefreshCw} from "lucide-react"; +import Link from "next/link"; +import {type Dispatch, type SetStateAction, useContext, useState} from "react"; +import * as z from "zod"; +import {ToastBox, toastType} from "@/components/ui/toast-box"; +import {useToast} from "@/components/ui/use-toast"; + + +const loginSchema = z.object({ + email: z + .string({ + required_error: "Email is needed.", + }) + .email({ + message: "Should be a valid email.", + }) + .describe("Your account email."), + password: z + .string({ + required_error: "Password is needed.", + }) + .describe("Your account password."), +}); + +const registerSchema = z.object({ + firstName: z.string({ + required_error: "", + }), + lastName: z.string(), + age: z.number().min(18).max(120), + pseudo: z.string({ + required_error: "", + }), + city: z.string({ + required_error: "", + }), + + email: z + .string({ + required_error: "Email is needed.", + }) + .email("Should be a valid email."), + password: z + .string({ + required_error: "Password is needed.", + }) + .describe("Your account password."), +}); + +export function AuthForms() { + const [isLoading, setIsLoading] = useState(false); + const [sub, setSub] = useLocalStorage("sub", ""); + const userContext = useContext(UserDataContext); + const { toast } = useToast() + + async function doRegister( + registerData: IApiRegisterReq, + userDataSetter: Dispatch>, + ): Promise> { + console.trace(registerData); + try { + const ReqRes = await ApiRequest.standard.post.json< + IApiRegisterReq, + IApiRegisterRes + >("auth/signup", registerData); + console.trace(ReqRes.data); + if (ReqRes.data.user) { + userDataSetter(ReqRes.data.user); + setSub(ReqRes.data.access_token); + } + console.debug(ReqRes.data.message || "Not additional message from request"); + return { + state: EReturnState.done, + resolved: ReqRes.data, + }; + } catch (error) { + console.error("Error during registration:", error); + return { + state: EReturnState.serverError, + message: error as string, + }; + } + } + + async function doLogin( + loginData: IApiLoginReq, + ): Promise> { + try { + const ReqRes = await ApiRequest.standard.post.json( + "auth/signin", + loginData, + ); + console.trace(ReqRes.data); + if (ReqRes.data.access_token) { + setSub(ReqRes.data.access_token); + } + return { + state: EReturnState.done, + }; + } catch (err) { + console.error("Error during login:", err); + return { + state: EReturnState.serverError, + message: err as string, + }; + } + } + + if (!userContext || !userContext.setUserData) { + return ( +
+ +

It seems that the context is missing..

+
+ ); + } + + return ( + + + Login + Register + + + { + setIsLoading(true); + doLogin(data).then((res) => { + if (res.state !== EReturnState.done) { + toast({ + description: res.message || "An unexpected error occurred..", + variant: "destructive", + }) + setIsLoading(false) + return + } + //toast.custom() + toast({ + description: "Login successful ! \n You will be redirected." + }) + setTimeout(()=>{ + setIsLoading(false) + location.href = "/" + console.log('Moving to home.') + }, 3_000) + }); + }} + fieldConfig={{ + password: { + inputProps: { + type: "password", + placeholder: "••••••••", + }, + }, + }} + > + + {/* biome-ignore lint/style/useTemplate: */} + +

Login

+
+
+
+ + { + setIsLoading(true); + doRegister( + data, + userContext.setUserData as Dispatch>, + ).then((res) => { + if (res.state !== EReturnState.done) { + //toast.custom() + setIsLoading(false) + return + } + //toast.custom() + setTimeout(()=>{ + setIsLoading(false) + //location.href = "/" + console.log('Moving to home.') + }, 5_000) + }); + }} + fieldConfig={{ + password: { + inputProps: { + type: "password", + placeholder: "••••••••", + }, + }, + }} + > + + {/* biome-ignore lint/style/useTemplate: */} + +

Register

+
+

+ By submitting this form, you agree to our{" "} + + terms and conditions + + . +

+
+
+
+ ); +}