Skip to content

Commit

Permalink
🔧 code optimized and chat error messages updated
Browse files Browse the repository at this point in the history
  • Loading branch information
sinanptm committed Sep 25, 2024
1 parent dd803cf commit c572a18
Show file tree
Hide file tree
Showing 13 changed files with 118 additions and 87 deletions.
20 changes: 15 additions & 5 deletions client/app/(patient)/chats/@chatList/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
'use client'
import { ButtonV2 } from "@/components/common/ButtonV2";
import NewChatModal, { ChatModelUser } from "@/components/models/chat/AddChatModel";
import ChatList from "@/components/page-components/chat/ChatList"
import { toast } from "@/components/ui/use-toast";
Expand Down Expand Up @@ -30,11 +31,20 @@ const Page = () => {
setNewChatModalOpen(false)
},
onError: ({ response }) => {
toast({
title: "Creating new Chat Failed ❌",
description: response?.data.message || "Unknown Error Occurred 🚑",
variant: "destructive"
})
if (response?.status === 400 && response.data.message === 'Patient profile or name is missing') {
toast({
title: "Oops! Chat Failed ❌",
description: "You have to register Your some additional data for starting chat.",
variant: "destructive",
action:<ButtonV2 variant={'destructive'} size="sm" onClick={()=>router.push("/register")} >Register</ButtonV2>
})
}else{
toast({
title: "Creating new Chat Failed ❌",
description: response?.data.message || "Unknown Error Occurred 🚑",
variant: "destructive"
})
}
}
})
}
Expand Down
5 changes: 4 additions & 1 deletion client/app/(patient)/profile/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Skeleton } from "@/components/ui/skeleton";
import Image from "next/image";
import { useState } from "react";
import UpdateProfilePatient from "@/components/models/patient/UpdateProfilePatient";
import { useGetPatientProfile } from "@/lib/hooks/patient/usePatient";
import { ButtonV2 } from "@/components/common/ButtonV2";
import dynamic from "next/dynamic";
import Loading from "@/components/skeletons/Loader";

const UpdateProfilePatient = dynamic(()=>import("@/components/models/patient/UpdateProfilePatient"), { loading: () => <Loading /> });

export default function PatientProfilePage() {
const { data: patientData, isLoading, refetch } = useGetPatientProfile();
Expand Down
4 changes: 2 additions & 2 deletions client/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import AboutAyurveda from "@/components/page-components/landing/home/AboutAyurve
import ImageSlider from "@/components/page-components/landing/home/ImageSlider";
import WhyUs from "@/components/page-components/landing/home/WhyUs";
import dynamic from "next/dynamic";
import Loader from "@/components/common/Loader";
import { Spinner } from "@/components/skeletons/spinner";

const FeaturesList = dynamic(() => import("@/components/page-components/landing/home/FeatureList"), {
loading: () => <Loader />,
loading: () => <Spinner className="w-10 h-10 justify-center items-center" size="md" />,
});

const HomePage = () => {
Expand Down
4 changes: 3 additions & 1 deletion client/components/button/NotificationButtonPatient.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
import { Bell } from "lucide-react";
import { Badge } from "@/components/ui/badge";
import { ButtonV2 } from "@/components/common/ButtonV2";
import NotificationModal from "@/components/models/NotificationModel";
import { useState } from "react";
import { useGetAllPatientNotifications, useClearPatientNotification, useClearMultiplePatientNotifications } from "@/lib/hooks/notification/useNotificationPatient";
import { INotification } from "@/types";
import dynamic from "next/dynamic";

const NotificationModal = dynamic(() => import("@/components/models/NotificationModel"), { ssr: false });

const NotificationButtonPatient = () => {
const [isNotificationModalOpen, setIsNotificationModalOpen] = useState(false);
Expand Down
7 changes: 0 additions & 7 deletions client/components/common/Loader.tsx

This file was deleted.

4 changes: 2 additions & 2 deletions client/components/page-components/chat/ChatSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ export default function ChatSection({
<AvatarFallback>{sender.charAt(0).toUpperCase()}</AvatarFallback>
</Avatar>
<div>
<h2 className="text-lg font-semibold text-white">{getSenderData(sender, chat.doctorName!, chat.patientName!)}</h2>
<h2 className="text-lg font-semibold text-white">{getSenderData(sender, chat.doctorName!, chat.patientName!)||"Unknown"}</h2>
<p className="text-sm text-gray-400">{sender.charAt(0).toUpperCase() + sender.slice(1)}</p>
</div>
</div>
Expand All @@ -128,7 +128,7 @@ export default function ChatSection({
<div className="flex items-center gap-2">
<Input
className="flex-1 bg-gray-800 text-white border-gray-700"
placeholder={`Message ${getReceiverData(sender, chat.doctorName!, chat.patientName!)}`}
placeholder={`Message ${getSenderData(sender, chat.doctorName!, chat.patientName!)}`}
value={message}
onChange={(e) => setMessage(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && handleSendMessage()}
Expand Down
116 changes: 57 additions & 59 deletions client/components/page-components/patient/profile/NavSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,72 +3,70 @@
import { useState } from "react";
import Image from "next/image";
import { Card, CardContent } from "@/components/ui/card";
import {IPatient} from "@/types";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { IPatient } from "@/types";
import UploadProfileModel from "@/components/models/patient/UploadProfileModel";
import { ButtonV2 } from "@/components/common/ButtonV2";

interface Props {
setSection: (state: "profile" | "appointments") => void;
patientData: IPatient;
refetch: any;
setSection: (state: "profile" | "appointments") => void;
patientData: IPatient;
refetch: any;
}

export default function NavSection({ setSection, patientData, refetch }: Props) {
const [isFileModel, setFileModel] = useState(false);
const [isFileModel, setFileModel] = useState(false);

const handleClick = (path: "profile" | "appointments") => {
setSection(path);
};
const handleClick = (path: "profile" | "appointments") => {
setSection(path);
};

const handleUploadClick = () => {
setFileModel(!isFileModel);
};
const handleUploadClick = () => {
setFileModel(!isFileModel);
};

return (
<Card className="overflow-hidden">
<div className="relative h-48">
<Image
src="/assets/images/ayurveda1.jpg"
alt="Ayurveda banner"
layout="fill"
objectFit="cover"
className="absolute inset-0"
/>
<div className="absolute inset-0 bg-black bg-opacity-40" />
<div className="absolute bottom-6 left-6 flex flex-row items-center space-y-0 space-x-4">
<div className="relative">
<Image
src={patientData.profile || "/assets/icons/user.svg"}
alt="Patient profile picture"
width={100}
height={100}
className="rounded-full border-4 border-white h-32 w-32"
/>
<ButtonV2
variant="gooeyLeft"
className="absolute bottom-0 right-0 mb-2 mr-2 p-2 bg-white rounded-full"
onClick={handleUploadClick}
>
<Image src="/assets/icons/upload.svg" alt="Upload" width={24} height={24} />
</ButtonV2>
</div>
<div className="text-center sm:text-left">
<h1 className="text-2xl font-bold">{patientData.name}</h1>
<p>{patientData.phone}</p>
</div>
</div>
</div>
<CardContent className="p-4 sm:p-6">
<div className="flex flex-col sm:flex-row space-y-2 sm:space-y-0 sm:space-x-4">
<ButtonV2 variant="shine" onClick={() => handleClick("profile")} className="flex-1">
Profile
</ButtonV2>
<ButtonV2 variant="shine" onClick={() => handleClick("appointments")} className="flex-1">
Appointments
</ButtonV2>
</div>
</CardContent>
<UploadProfileModel open={isFileModel} setOpen={setFileModel} patientData={patientData} refetch={refetch} />
</Card>
);
}
return (
<Card className="overflow-hidden">
<div className="relative h-48">
<Image
src="/assets/images/ayurveda1.jpg"
alt="Ayurveda banner"
layout="fill"
objectFit="cover"
className="absolute inset-0"
/>
<div className="absolute inset-0 bg-black bg-opacity-40" />
<div className="absolute bottom-6 left-6 flex flex-row items-center space-y-0 space-x-4">
<div className="relative">
<Avatar className="h-32 w-32 border-4 border-white">
<AvatarImage src={patientData.profile || "/assets/icons/user.svg"} alt={patientData.name} />
<AvatarFallback>{patientData.name!.charAt(0)}</AvatarFallback>
</Avatar>
<ButtonV2
variant="gooeyLeft"
className="absolute bottom-0 right-0 mb-2 mr-2 p-2 bg-white rounded-full"
onClick={handleUploadClick}
>
<Image src="/assets/icons/upload.svg" alt="Upload" width={24} height={24} />
</ButtonV2>
</div>
<div className="text-center sm:text-left">
<h1 className="text-2xl font-bold text-white">{patientData.name}</h1>
<p className="text-white">{patientData.phone}</p>
</div>
</div>
</div>
<CardContent className="p-4 sm:p-6">
<div className="flex flex-col sm:flex-row space-y-2 sm:space-y-0 sm:space-x-4">
<ButtonV2 variant="shine" onClick={() => handleClick("profile")} className="flex-1">
Profile
</ButtonV2>
<ButtonV2 variant="shine" onClick={() => handleClick("appointments")} className="flex-1">
Appointments
</ButtonV2>
</div>
</CardContent>
<UploadProfileModel open={isFileModel} setOpen={setFileModel} patientData={patientData} refetch={refetch} />
</Card>
);
}
16 changes: 16 additions & 0 deletions client/components/skeletons/Loader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import Image from "next/image"

const Loading = () => (
<div className="flex items-center justify-center h-screen">
<div className="relative w-20 h-20">
<Image
src="/assets/icons/loader-v2.svg"
alt="Loading"
layout="fill"
className="animate-pulse"
/>
</div>
</div>
)

export default Loading
2 changes: 1 addition & 1 deletion client/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { AnimatedCardProps, AppointmentType, NavLinkType } from "@/types";

export const AdminSideBarLinks: NavLinkType[] = [
{
label: "Dcotors",
label: "Doctors",
href: "/admin/doctors",
icon: "/assets/icons/doctor.svg",
},
Expand Down
6 changes: 6 additions & 0 deletions client/public/assets/icons/loader-v2.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 7 additions & 7 deletions server/src/infrastructure/services/JoiService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,11 @@ export default class JoiService implements IValidatorService {
const schema = Joi.array().items(Joi.string().pattern(new RegExp("^[a-fA-F0-9]{24}$")));
const { error } = schema.validate(ids);
if (error) {
throw new CustomError("Invalid ID format", StatusCode.BadRequest);
}
throw new CustomError("Invalid ID format", StatusCode.BadRequest);
}
return true;
}
}

public validatePhoneNumber(phoneNumber: string): boolean {
const schema = Joi.string().min(4).max(15);
const { error } = schema.validate(phoneNumber);
Expand Down Expand Up @@ -102,12 +102,12 @@ export default class JoiService implements IValidatorService {

public validatePassword(password: string): boolean {
const schema = Joi.string()
.min(8)
.pattern(/^(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/);
.min(6)
.pattern(/^(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{6,}$/);
const { error } = schema.validate(password);
if (error) {
throw new CustomError(
"Password must be at least 8 characters, include at least one uppercase letter, one number, and one special character",
"Password must be at least 6 characters, include at least one uppercase letter, one number, and one special character",
StatusCode.UnprocessableEntity
);
}
Expand Down
3 changes: 3 additions & 0 deletions server/src/use_case/chat/CreateChatUseCase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ export default class CreateChatUseCase {
} else if (!doctor) {
throw new CustomError("Invalid doctor id", StatusCode.NotFound);
}
if(!patient.profile|| !patient.name){
throw new CustomError("Patient profile or name is missing", StatusCode.BadRequest);
}
try {
return await this.chatRepository.create(
{ doctorId, patientId, patientName: patient.name, doctorName: doctor.name, patientProfile: patient.profile, doctorProfile: doctor.image }
Expand Down
4 changes: 2 additions & 2 deletions server/src/use_case/chat/GetChatUseCase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ export default class GetChatUseCase {
}

async getPatientsDoctor(): Promise<IPatient[] | []> {
const patients = await this.patientRepository.findAll();
return patients;
const patients = await this.patientRepository.findAll()!;
return patients.filter(patient => patient.profile && patient.name);
}

private async getChatsWithNotSeenMessages(
Expand Down

1 comment on commit c572a18

@vercel
Copy link

@vercel vercel bot commented on c572a18 Sep 25, 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.