From 0bce5f68caaac94815b01efd1c0aa8f2329ea5ea Mon Sep 17 00:00:00 2001 From: Sinan Date: Sat, 31 Aug 2024 21:07:01 +0530 Subject: [PATCH] reset password page setUp completed --- .../(patient)/signin/reset-password/page.tsx | 141 +++++++++++++++++- client/lib/hooks/usePatientAuth.ts | 74 +++++---- client/services/api/patientAuthApis.ts | 5 + .../controllers/PatientController.ts | 2 +- .../routers/patient/AuthPatientRoutes.ts | 2 +- .../use_case/patient/AuthPatientUseCase.ts | 7 +- 6 files changed, 192 insertions(+), 39 deletions(-) diff --git a/client/app/(patient)/signin/reset-password/page.tsx b/client/app/(patient)/signin/reset-password/page.tsx index 983ebb85..88951c65 100644 --- a/client/app/(patient)/signin/reset-password/page.tsx +++ b/client/app/(patient)/signin/reset-password/page.tsx @@ -1,9 +1,136 @@ -import React from 'react' +"use client"; -const page = () => { - return ( -
page
- ) -} +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { z } from "zod"; +import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "@/components/ui/card"; +import CustomFormField from "@/components/common/CustomFormField"; +import { FormFieldType } from "@/types/fromTypes"; +import SubmitButton from "@/components/common/SubmitButton"; +import { useUpdatePassword } from "@/lib/hooks/usePatientAuth"; +import { Form } from "@/components/ui/form"; +import { useAuth } from "@/lib/hooks/useAuth"; +import { useRouter } from "next/navigation"; +import { toast } from "@/components/ui/use-toast"; + +const formSchema = z + .object({ + oldPassword: z + .string() + .trim() + .min(6, "Password must be at least 6 characters long") + .max(25, "Password must be at most 25 characters long") + .regex(/[A-Z]/, "Password must contain at least one uppercase letter") + .regex(/[a-z]/, "Password must contain at least one lowercase letter") + .regex(/[0-9]/, "Password must contain at least one number") + .regex(/[@$!%*?&#]/, "Password must contain at least one special character"), + newPassword: z + .string() + .trim() + .min(6, "Password must be at least 6 characters long") + .max(25, "Password must be at most 25 characters long") + .regex(/[A-Z]/, "Password must contain at least one uppercase letter") + .regex(/[a-z]/, "Password must contain at least one lowercase letter") + .regex(/[0-9]/, "Password must contain at least one number") + .regex(/[@$!%*?&#]/, "Password must contain at least one special character"), + confirmPassword: z.string(), + }) + .superRefine(({ newPassword, confirmPassword }, ctx) => { + if (newPassword !== confirmPassword) { + ctx.addIssue({ + code: "custom", + message: "The passwords do not match", + path: ["confirmPassword"], + }); + } + }); + +type FormValues = z.infer; -export default page \ No newline at end of file +export default function ResetPasswordPage() { + const form = useForm({ + resolver: zodResolver(formSchema), + defaultValues: { + oldPassword: "", + newPassword: "", + confirmPassword: "", + }, + }); + const route = useRouter(); + const { mutate: updatePassword, isPending } = useUpdatePassword(); + const { control, handleSubmit } = form; + const { otpMail, setCredentials } = useAuth(); + const onSubmit = async (values: FormValues) => { + updatePassword( + { + oldPassword: values.oldPassword, + newPassword: values.newPassword, + email:"muhammedsinan0549@gmail.com", + }, + { + onSuccess: () => { + toast({ + title: "Password Updated ✅", + description: "Password Updated Successfully", + }); + setTimeout(() => { + route.push("/signin"); + setCredentials("otpMail", ""); + }, 2000); + }, + onError: (error) => { + toast({ + title: "Updating Failed ❌", + description: error.response?.data.message || "Please try again later.", + variant: "destructive", + }); + }, + } + ); + }; + + return ( +
+ + + Reset Password + + Change your account password here. + + +
+ + + + + + + + + Update Password + + +
+ +
+
+ ); +} diff --git a/client/lib/hooks/usePatientAuth.ts b/client/lib/hooks/usePatientAuth.ts index d2f290df..c590dbe4 100644 --- a/client/lib/hooks/usePatientAuth.ts +++ b/client/lib/hooks/usePatientAuth.ts @@ -1,11 +1,22 @@ import { ErrorResponse, IPatient } from "@/types"; import { useMutation } from "@tanstack/react-query"; -import { forgetPassword, resendOtpPatient, signInPatient, signUpPatient, validateOtpPatient } from "@/services/api/patientAuthApis"; +import { + forgetPassword, + resendOtpPatient, + signInPatient, + signUpPatient, + updatePassword, + validateOtpPatient, +} from "@/services/api/patientAuthApis"; import { AxiosError } from "axios"; import { logoutPatient } from "@/services/api/patientProtectedApis"; +type MessageResponse = { + message: string; +}; + export const useSignUpPatient = () => { - return useMutation<{ message: string }, AxiosError, IPatient>({ + return useMutation, IPatient>({ mutationFn: (patient) => signUpPatient(patient), onError: (error: AxiosError) => { console.log("Error in creating patient:", error); @@ -35,29 +46,38 @@ export const useValidateOtpPatient = () => { }); }; -export const useLogoutMutation = ()=>{ - return useMutation<{message:string},AxiosError,null>({ - mutationFn:logoutPatient, - onError:(error)=>{ - console.log('Error in Logout',error); - } - }) -}; - -export const useResendOtp = ()=>{ - return useMutation<{message:string}, AxiosError,{email:string}>({ - mutationFn:({email})=>resendOtpPatient(email), - onError:(error)=>{ - console.log('Error in resending otp', error); - } - }) -} - -export const useForgetPassword = ()=>{ - return useMutation<{message:string},AxiosError,{email:string}>({ - mutationFn:({email})=>forgetPassword(email), - onError:(error)=>{ - console.log('Error in Sending Reset Mail', error); - } +export const useLogoutMutation = () => { + return useMutation, null>({ + mutationFn: logoutPatient, + onError: (error) => { + console.log("Error in Logout", error); + }, + }); +}; + +export const useResendOtp = () => { + return useMutation, { email: string }>({ + mutationFn: ({ email }) => resendOtpPatient(email), + onError: (error) => { + console.log("Error in resending otp", error); + }, + }); +}; + +export const useForgetPassword = () => { + return useMutation, { email: string }>({ + mutationFn: ({ email }) => forgetPassword(email), + onError: (error) => { + console.log("Error in Sending Reset Mail", error); + }, + }); +}; + +export const useUpdatePassword = () => { + return useMutation,{ email: string; oldPassword: string; newPassword: string }>({ + mutationFn: ({ email, oldPassword, newPassword }) => updatePassword(email, oldPassword, newPassword), + onError: (error) => { + console.log("Error in Updating Password", error); + }, }); -} \ No newline at end of file +}; diff --git a/client/services/api/patientAuthApis.ts b/client/services/api/patientAuthApis.ts index a883e76f..1372f3b9 100644 --- a/client/services/api/patientAuthApis.ts +++ b/client/services/api/patientAuthApis.ts @@ -42,3 +42,8 @@ export const forgetPassword = async (email: string) => { const response = await axiosInstance.post("/forget-password", { email }); return response.data; }; + +export const updatePassword = async (email: string, oldPassword: string, newPassword: string) => { + const response = await axiosInstance.patch("/update-password", { email, oldPassword, newPassword }); + return response.data; +}; diff --git a/server/src/presentation/controllers/PatientController.ts b/server/src/presentation/controllers/PatientController.ts index 7843b962..01fce97d 100644 --- a/server/src/presentation/controllers/PatientController.ts +++ b/server/src/presentation/controllers/PatientController.ts @@ -99,7 +99,7 @@ export default class PatientController { const { email, oldPassword, newPassword } = req.body; if (!email) return res.status(400).json({message:"Email is Required"}); - if (!oldPassword) return res.status(400).json({ message: "Old Password is required" }); + if (!oldPassword.trim()) return res.status(400).json({ message: "Old Password is required" }); if (!newPassword?.trim()) return res.status(400).json({ message: "New Password is required" }); if (!isValidatePassword(newPassword)) return res.status(422).json({ message: "Password is too week" }); diff --git a/server/src/presentation/routers/patient/AuthPatientRoutes.ts b/server/src/presentation/routers/patient/AuthPatientRoutes.ts index 20b4117d..0efac714 100644 --- a/server/src/presentation/routers/patient/AuthPatientRoutes.ts +++ b/server/src/presentation/routers/patient/AuthPatientRoutes.ts @@ -50,7 +50,7 @@ route.get("/refresh", (req, res, next) => { route.post("/forget-password", (req, res, next) => { patientController.forgetPassword(req, res, next); }); -route.post("/update-password", (req, res, next) => { +route.patch("/update-password", (req, res, next) => { patientController.updatePassword(req, res, next); }); route.post("/logout", patientAuthMiddleware.exec, (req, res, next) => { diff --git a/server/src/use_case/patient/AuthPatientUseCase.ts b/server/src/use_case/patient/AuthPatientUseCase.ts index 08b8a00c..fed6139e 100644 --- a/server/src/use_case/patient/AuthPatientUseCase.ts +++ b/server/src/use_case/patient/AuthPatientUseCase.ts @@ -94,11 +94,12 @@ export default class LoginPatientUseCase { } async updatePatientPassword(email: string, oldPassword: string, newPassword: string): Promise { - const patient = await this.patientRepository.findByEmail(email); + const patient = await this.patientRepository.findByEmailWithPassword(email); if (!patient) throw new Error("Patient Not Found"); - if (patient.isBlocked) throw new Error("Patient is Blocked"); + if (patient.isBlocked) throw new Error("Patient is Blocked"); - if (!(await this.passwordService.compare(oldPassword, patient.password!))) throw new Error("Invalid Credentials"); + if (!(await this.passwordService.compare(oldPassword!, patient.password!))) + throw new Error("Invalid Credentials"); patient.password = await this.passwordService.hash(newPassword);