Skip to content

Commit

Permalink
reset password page setUp completed
Browse files Browse the repository at this point in the history
  • Loading branch information
sinanptm committed Aug 31, 2024
1 parent b7e9279 commit 0bce5f6
Show file tree
Hide file tree
Showing 6 changed files with 192 additions and 39 deletions.
141 changes: 134 additions & 7 deletions client/app/(patient)/signin/reset-password/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,136 @@
import React from 'react'
"use client";

const page = () => {
return (
<div>page</div>
)
}
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<typeof formSchema>;

export default page
export default function ResetPasswordPage() {
const form = useForm<FormValues>({
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:"[email protected]",
},
{
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 (
<div className="container max-w-md mx-auto mt-48 remove-scrollbar">
<Card>
<CardHeader>
<CardTitle>Reset Password</CardTitle>
<CardDescription>
Change your account password here.
</CardDescription>
</CardHeader>
<Form {...form}>
<form onSubmit={handleSubmit(onSubmit)}>
<CardContent className="space-y-4">
<CustomFormField
control={control}
fieldType={FormFieldType.PASSWORD}
name="oldPassword"
placeholder="Your current password"
label="Current Password"
/>
<CustomFormField
control={control}
fieldType={FormFieldType.PASSWORD}
name="newPassword"
placeholder="Your new password"
label="New Password"
/>
<CustomFormField
control={control}
fieldType={FormFieldType.PASSWORD}
name="confirmPassword"
placeholder="Confirm your new password"
label="Confirm New Password"
/>
</CardContent>
<CardFooter>
<SubmitButton isLoading={isPending} variant={"secondary"}>
Update Password
</SubmitButton>
</CardFooter>
</form>
</Form>
</Card>
</div>
);
}
74 changes: 47 additions & 27 deletions client/lib/hooks/usePatientAuth.ts
Original file line number Diff line number Diff line change
@@ -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<ErrorResponse>, IPatient>({
return useMutation<MessageResponse, AxiosError<ErrorResponse>, IPatient>({
mutationFn: (patient) => signUpPatient(patient),
onError: (error: AxiosError) => {
console.log("Error in creating patient:", error);
Expand Down Expand Up @@ -35,29 +46,38 @@ export const useValidateOtpPatient = () => {
});
};

export const useLogoutMutation = ()=>{
return useMutation<{message:string},AxiosError<ErrorResponse>,null>({
mutationFn:logoutPatient,
onError:(error)=>{
console.log('Error in Logout',error);
}
})
};

export const useResendOtp = ()=>{
return useMutation<{message:string}, AxiosError<ErrorResponse>,{email:string}>({
mutationFn:({email})=>resendOtpPatient(email),
onError:(error)=>{
console.log('Error in resending otp', error);
}
})
}

export const useForgetPassword = ()=>{
return useMutation<{message:string},AxiosError<ErrorResponse>,{email:string}>({
mutationFn:({email})=>forgetPassword(email),
onError:(error)=>{
console.log('Error in Sending Reset Mail', error);
}
export const useLogoutMutation = () => {
return useMutation<MessageResponse, AxiosError<ErrorResponse>, null>({
mutationFn: logoutPatient,
onError: (error) => {
console.log("Error in Logout", error);
},
});
};

export const useResendOtp = () => {
return useMutation<MessageResponse, AxiosError<ErrorResponse>, { email: string }>({
mutationFn: ({ email }) => resendOtpPatient(email),
onError: (error) => {
console.log("Error in resending otp", error);
},
});
};

export const useForgetPassword = () => {
return useMutation<MessageResponse, AxiosError<ErrorResponse>, { email: string }>({
mutationFn: ({ email }) => forgetPassword(email),
onError: (error) => {
console.log("Error in Sending Reset Mail", error);
},
});
};

export const useUpdatePassword = () => {
return useMutation<MessageResponse,AxiosError<ErrorResponse>,{ email: string; oldPassword: string; newPassword: string }>({
mutationFn: ({ email, oldPassword, newPassword }) => updatePassword(email, oldPassword, newPassword),
onError: (error) => {
console.log("Error in Updating Password", error);
},
});
}
};
5 changes: 5 additions & 0 deletions client/services/api/patientAuthApis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
2 changes: 1 addition & 1 deletion server/src/presentation/controllers/PatientController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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" });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
7 changes: 4 additions & 3 deletions server/src/use_case/patient/AuthPatientUseCase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,12 @@ export default class LoginPatientUseCase {
}

async updatePatientPassword(email: string, oldPassword: string, newPassword: string): Promise<void> {
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);

Expand Down

1 comment on commit 0bce5f6

@vercel
Copy link

@vercel vercel bot commented on 0bce5f6 Aug 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.