diff --git a/client/app/(landing-pages)/about/page.tsx b/client/app/(landing-pages)/about/page.tsx index 95cb7eda..5d0d10a6 100644 --- a/client/app/(landing-pages)/about/page.tsx +++ b/client/app/(landing-pages)/about/page.tsx @@ -8,26 +8,26 @@ import WhyChooseUs from "@/components/page-components/landing/about/WhyChooseUs" import { memo } from "react"; export const metadata: Metadata = { - title: "About Us", - description: - "Learn about our commitment to holistic health through Ayurveda. Discover our story, meet our team, and understand our mission to enhance your well-being through ancient healing practices.", - keywords: ["Ayurveda", "Holistic Health", "About Us", "Our Team", "Our Mission", "Ayurvedic Center"], + title: "About Us", + description: + "Learn about our commitment to holistic health through Ayurveda. Discover our story, meet our team, and understand our mission to enhance your well-being through ancient healing practices.", + keywords: ["Ayurveda", "Holistic Health", "About Us", "Our Team", "Our Mission", "Ayurvedic Center"], }; -const AboutPage= () => { - return ( -
-
-

About AVM Ayurveda

- - - - - - +const AboutPage = () => { + return ( +
+
+

About AVM Ayurveda

+ + + + + + +
-
- ); -} + ); +}; -export default memo(AboutPage) \ No newline at end of file +export default memo(AboutPage); diff --git a/client/app/(landing-pages)/clinicians/page.tsx b/client/app/(landing-pages)/clinicians/page.tsx index b8e7d8d1..1811e055 100644 --- a/client/app/(landing-pages)/clinicians/page.tsx +++ b/client/app/(landing-pages)/clinicians/page.tsx @@ -15,13 +15,15 @@ export const metadata: Metadata = { const Page = async () => { const apiUrl = process.env.NEXT_PUBLIC_API_URL; - const response = await fetch(`${apiUrl && apiUrl.trim() ? apiUrl : "https://api.avm-ayurvedic.online/api"}/doctors`, { - next: { revalidate: 60 } - }); + const response = await fetch( + `${apiUrl && apiUrl.trim() ? apiUrl : "https://api.avm-ayurvedic.online/api"}/doctors`, + { + next: { revalidate: 60 }, + } + ); const data = await response.json(); - return (
diff --git a/client/app/(landing-pages)/services/page.tsx b/client/app/(landing-pages)/services/page.tsx index f2a5ce06..150a63e2 100644 --- a/client/app/(landing-pages)/services/page.tsx +++ b/client/app/(landing-pages)/services/page.tsx @@ -1,7 +1,7 @@ import Featured from "@/components/page-components/landing/services/Featured"; import Services from "@/components/page-components/landing/services/Services"; import WhyOurService from "@/components/page-components/landing/services/WhyOurService"; -import Spinner from "@/components/skeletons/Spinner"; +import Spinner from "@/components/skeletons/Spinner"; import { Metadata } from "next"; import dynamic from "next/dynamic"; import { memo } from "react"; @@ -10,7 +10,6 @@ const FeaturesList = dynamic(() => import("@/components/page-components/landing/ loading: () => , }); - export const metadata: Metadata = { title: "Services", description: "Learn about our ayurvedic outpatient and inpatient consulting services", diff --git a/client/app/(patient)/appointments/[id]/page.tsx b/client/app/(patient)/appointments/[id]/page.tsx index c8bf54bd..a3af4756 100644 --- a/client/app/(patient)/appointments/[id]/page.tsx +++ b/client/app/(patient)/appointments/[id]/page.tsx @@ -1,33 +1,37 @@ -'use client' +"use client"; -import { useState } from "react" -import { useParams, notFound } from "next/navigation" -import { format } from "date-fns" -import Image from "next/image" -import { AlertCircle, Calendar, Clock, FileText, Pill } from "lucide-react" -import { useGetAppointmentDetailsPatient, useUpdateAppointmentStatusAndNotesPatient } from "@/lib/hooks/appointment/useAppointmentPatient" -import { useAuth } from "@/lib/hooks/useAuth" -import { AppointmentStatus } from "@/types/enum" -import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "@/components/ui/card" -import { Textarea } from "@/components/ui/textarea" -import { toast } from "@/components/ui/use-toast" -import { Badge } from "@/components/ui/badge" -import { Separator } from "@/components/ui/separator" -import ConfirmCancelAppointmentModelPatient from "@/components/models/appointment/ConfirmCancelAppointmentPatient" -import { ButtonV2 } from "@/components/button/ButtonV2" -import dynamic from "next/dynamic" +import { useState } from "react"; +import { useParams, notFound } from "next/navigation"; +import { format } from "date-fns"; +import Image from "next/image"; +import { AlertCircle, Calendar, Clock, FileText, Pill } from "lucide-react"; +import { + useGetAppointmentDetailsPatient, + useUpdateAppointmentStatusAndNotesPatient, +} from "@/lib/hooks/appointment/useAppointmentPatient"; +import { useAuth } from "@/lib/hooks/useAuth"; +import { AppointmentStatus } from "@/types/enum"; +import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; +import { Textarea } from "@/components/ui/textarea"; +import { toast } from "@/components/ui/use-toast"; +import { Badge } from "@/components/ui/badge"; +import { Separator } from "@/components/ui/separator"; +import ConfirmCancelAppointmentModelPatient from "@/components/models/appointment/ConfirmCancelAppointmentPatient"; +import { ButtonV2 } from "@/components/button/ButtonV2"; +import dynamic from "next/dynamic"; -const DownloadPrescriptionButton = dynamic(() => import("@/components/button/DownloadPrescriptionButton"), { ssr: false }); +const DownloadPrescriptionButton = dynamic(() => import("@/components/button/DownloadPrescriptionButton"), { + ssr: false, +}); export default function AppointmentDetailsPage() { - const id = useParams().id as string - const [isEditingNote, setIsEditingNote] = useState(false) - const [isCancelModelOpen, setCancelModelOpen] = useState(false) - const { data: appointment, refetch } = useGetAppointmentDetailsPatient(id) - const { mutate: update } = useUpdateAppointmentStatusAndNotesPatient() - const [newNote, setNewNote] = useState("") - const { patientToken } = useAuth() - + const id = useParams().id as string; + const [isEditingNote, setIsEditingNote] = useState(false); + const [isCancelModelOpen, setCancelModelOpen] = useState(false); + const { data: appointment, refetch } = useGetAppointmentDetailsPatient(id); + const { mutate: update } = useUpdateAppointmentStatusAndNotesPatient(); + const [newNote, setNewNote] = useState(""); + const { patientToken } = useAuth(); const handleUpdateNote = async () => { if (newNote.trim()) { @@ -38,27 +42,27 @@ export default function AppointmentDetailsPage() { toast({ title: "Note Updated", description: "Your note has been successfully updated.", - }) - setIsEditingNote(false) - refetch() + }); + setIsEditingNote(false); + refetch(); }, onError: () => { toast({ title: "Error", description: "Failed to update the note. Please try again.", variant: "destructive", - }) + }); }, } - ) + ); } else { toast({ title: "Invalid Input", description: "Note cannot be empty. Please enter some text.", variant: "destructive", - }) + }); } - } + }; const handleCancelAppointment = async () => { update( @@ -67,42 +71,43 @@ export default function AppointmentDetailsPage() { onSuccess: () => { toast({ title: "Appointment Cancelled", - description: "Your appointment has been successfully cancelled. Refund will be getting to your account in 10 working days ๐Ÿ’ธ.", - }) - refetch() - setCancelModelOpen(false) + description: + "Your appointment has been successfully cancelled. Refund will be getting to your account in 10 working days ๐Ÿ’ธ.", + }); + refetch(); + setCancelModelOpen(false); }, onError: () => { toast({ title: "Error", description: "Failed to cancel the appointment. Please try again.", variant: "destructive", - }) + }); }, } - ) - } + ); + }; const isCancellable = () => { - if (!appointment?.slot?.startTime || !appointment?.appointmentDate) return false + if (!appointment?.slot?.startTime || !appointment?.appointmentDate) return false; - const appointmentDate = new Date(appointment.appointmentDate) - const [hours, minutes] = appointment.slot.startTime.split(":") - const isPM = appointment.slot.startTime.includes("PM") + const appointmentDate = new Date(appointment.appointmentDate); + const [hours, minutes] = appointment.slot.startTime.split(":"); + const isPM = appointment.slot.startTime.includes("PM"); - appointmentDate.setHours(isPM ? parseInt(hours) + 12 : parseInt(hours), parseInt(minutes.split(" ")[0])) + appointmentDate.setHours(isPM ? parseInt(hours) + 12 : parseInt(hours), parseInt(minutes.split(" ")[0])); - const currentTime = new Date() - const threeHoursBefore = new Date(appointmentDate.getTime() - 3 * 60 * 60 * 1000) - return currentTime < threeHoursBefore - } + const currentTime = new Date(); + const threeHoursBefore = new Date(appointmentDate.getTime() - 3 * 60 * 60 * 1000); + return currentTime < threeHoursBefore; + }; if (!patientToken) { - notFound() + notFound(); } if (!appointment) { - return
Loading appointment details...
+ return
Loading appointment details...
; } return ( @@ -121,18 +126,32 @@ export default function AppointmentDetailsPage() {
- Calendar + Calendar {format(new Date(appointment.appointmentDate!), "PPPP")}
- {appointment.slot?.startTime} - {appointment.slot?.endTime} + + {appointment.slot?.startTime} - {appointment.slot?.endTime} +
{appointment.appointmentType === "video-consulting" ? ( - Video + Video ) : ( - In-person + In-person )} {appointment.appointmentType}
@@ -140,7 +159,13 @@ export default function AppointmentDetailsPage() {

- File + File Reason for Visit

{appointment.reason}

@@ -149,18 +174,24 @@ export default function AppointmentDetailsPage() {

- Notes + Notes Notes { - setNewNote(appointment.notes || "") - setIsEditingNote(true) + setNewNote(appointment.notes || ""); + setIsEditingNote(true); }} > - Edit + Edit Edit

@@ -213,7 +244,9 @@ export default function AppointmentDetailsPage() {

{appointment.doctor?.name}

-

{appointment.doctor?.qualifications?.join(", ")}

+

+ {appointment.doctor?.qualifications?.join(", ")} +

@@ -318,5 +351,5 @@ export default function AppointmentDetailsPage() { handleCancelAppointment={handleCancelAppointment} />
- ) -} \ No newline at end of file + ); +} diff --git a/client/app/(patient)/appointments/page.tsx b/client/app/(patient)/appointments/page.tsx index 8dd962cb..a7551ee4 100644 --- a/client/app/(patient)/appointments/page.tsx +++ b/client/app/(patient)/appointments/page.tsx @@ -1,132 +1,149 @@ -'use client' +"use client"; -import { useEffect, useState } from "react" -import { useRouter } from "next/navigation" -import { format } from "date-fns" -import { FileText, Video, User, Calendar, PlusCircle, InfoIcon } from "lucide-react" -import { useGetAppointmentsPatient } from "@/lib/hooks/appointment/useAppointmentPatient" -import Pagination from "@/components/navigation/Pagination" -import GetStatusBadge from "@/components/page-components/doctor/appointment/GetStatusBadge" -import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "@/components/ui/card" -import { Skeleton } from "@/components/ui/skeleton" -import { ButtonV2 } from "@/components/button/ButtonV2" -import useRedirect from "@/lib/hooks/useRedirect" -import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert" +import { useEffect, useState } from "react"; +import { useRouter } from "next/navigation"; +import { format } from "date-fns"; +import { FileText, Video, User, Calendar, PlusCircle, InfoIcon } from "lucide-react"; +import { useGetAppointmentsPatient } from "@/lib/hooks/appointment/useAppointmentPatient"; +import Pagination from "@/components/navigation/Pagination"; +import GetStatusBadge from "@/components/page-components/doctor/appointment/GetStatusBadge"; +import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; +import { Skeleton } from "@/components/ui/skeleton"; +import { ButtonV2 } from "@/components/button/ButtonV2"; +import useRedirect from "@/lib/hooks/useRedirect"; +import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; export default function AppointmentsPageSection({ searchParams }: { searchParams: { page: number } }) { - const page = +searchParams.page || 1 - const [currentPage, setCurrentPage] = useState(page) - const { data, isLoading } = useGetAppointmentsPatient(page-1, 4) - const router = useRouter() - const redirect = useRedirect() + const page = +searchParams.page || 1; + const [currentPage, setCurrentPage] = useState(page); + const { data, isLoading } = useGetAppointmentsPatient(page - 1, 4); + const router = useRouter(); + const redirect = useRedirect(); - const handlePageChange = (pageIndex: number) => { - if (pageIndex > data?.totalPages! || pageIndex < 1) return null - router.replace(`/appointments?page=${pageIndex}`) - setCurrentPage(pageIndex) - } - - useEffect(() => { - setCurrentPage(page) - }, [page]) - - const handleViewDetails = (appointmentId: string) => { - router.push(`/appointments/${appointmentId}`) - } + const handlePageChange = (pageIndex: number) => { + if (pageIndex > data?.totalPages! || pageIndex < 1) return null; + router.replace(`/appointments?page=${pageIndex}`); + setCurrentPage(pageIndex); + }; - return ( -
-
-

My Appointments

- redirect()} variant="shine" className="flex items-center gap-2 w-full sm:w-auto justify-center sm:justify-start"> - - New Appointment - -
+ useEffect(() => { + setCurrentPage(page); + }, [page]); - - - Important Note - - Your appointments may not be approved by the doctor yet. Please check the status of each appointment for the most up-to-date information. - - + const handleViewDetails = (appointmentId: string) => { + router.push(`/appointments/${appointmentId}`); + }; - {isLoading ? ( -
- {[...Array(4)].map((_, index) => ( - - - - - - - - - - - - - ))} -
- ) : data?.items.length === 0 ? ( - -
- -

No Appointments Yet

-

You haven't scheduled any appointments. Why not book one now?

- redirect()} variant="default" className="flex items-center gap-2 w-full sm:w-auto justify-center"> - - Schedule Your First Appointment + return ( +
+
+

My Appointments

+ redirect()} + variant="shine" + className="flex items-center gap-2 w-full sm:w-auto justify-center sm:justify-start" + > + + New Appointment -
- - ) : ( -
- {data?.items.map((appointment) => ( - - - - Appointment on {format(new Date(appointment.appointmentDate!), "MMMM d, yyyy")} - - - - -
-
- {appointment.appointmentType === "video-consulting" ? ( -
-
- - {appointment.reason} -
-
-
- - handleViewDetails(appointment._id!)} variant="ringHover" className="w-full"> - View Details - - +
+ + + + Important Note + + Your appointments may not be approved by the doctor yet. Please check the status of each appointment for + the most up-to-date information. + + + + {isLoading ? ( +
+ {[...Array(4)].map((_, index) => ( + + + + + + + + + + + + + ))} +
+ ) : data?.items.length === 0 ? ( + +
+ +

No Appointments Yet

+

+ You haven't scheduled any appointments. Why not book one now? +

+ redirect()} + variant="default" + className="flex items-center gap-2 w-full sm:w-auto justify-center" + > + + Schedule Your First Appointment + +
- ))} -
- )} - {!isLoading && data?.items.length! > 0 && ( -
- -
- )} -
- ) -} \ No newline at end of file + ) : ( +
+ {data?.items.map((appointment) => ( + + + + Appointment on {format(new Date(appointment.appointmentDate!), "MMMM d, yyyy")} + + + + +
+
+ {appointment.appointmentType === "video-consulting" ? ( +
+
+ + {appointment.reason} +
+
+
+ + handleViewDetails(appointment._id!)} + variant="ringHover" + className="w-full" + > + View Details + + +
+ ))} +
+ )} + {!isLoading && data?.items.length! > 0 && ( +
+ +
+ )} +
+ ); +} diff --git a/client/app/(patient)/chats/@chat/[chatId]/page.tsx b/client/app/(patient)/chats/@chat/[chatId]/page.tsx index c019a016..54d8b4fc 100644 --- a/client/app/(patient)/chats/@chat/[chatId]/page.tsx +++ b/client/app/(patient)/chats/@chat/[chatId]/page.tsx @@ -1,52 +1,51 @@ -'use client' -import { useParams } from "next/navigation" -import { useEffect, useState } from "react" -import ChatSection from "@/components/page-components/chat/ChatSection" -import useMessages from "@/lib/hooks/useMessages" -import { toast } from "@/components/ui/use-toast" +"use client"; +import { useParams } from "next/navigation"; +import { useEffect, useState } from "react"; +import ChatSection from "@/components/page-components/chat/ChatSection"; +import useMessages from "@/lib/hooks/useMessages"; +import { toast } from "@/components/ui/use-toast"; const Page = () => { - const chatId = useParams().chatId as string; - const [isLoading, setLoading] = useState(true); - const { createMessage, error, messages, chat, markReceived } = useMessages({ role: "patient", chatId }); + const chatId = useParams().chatId as string; + const [isLoading, setLoading] = useState(true); + const { createMessage, error, messages, chat, markReceived } = useMessages({ role: "patient", chatId }); - useEffect(() => { - if (chat && messages) { - setLoading(false); - const filteredMessages = messages.filter(message => { - return message.receiverId === chat.patientId && !message.isReceived - }); + useEffect(() => { + if (chat && messages) { + setLoading(false); + const filteredMessages = messages.filter((message) => { + return message.receiverId === chat.patientId && !message.isReceived; + }); - if (filteredMessages.length > 0) { - markReceived(chatId, chat.patientId!); + if (filteredMessages.length > 0) { + markReceived(chatId, chat.patientId!); + } } - } - }, [messages, chat, markReceived, chatId]); + }, [messages, chat, markReceived, chatId]); - const handleSendMessage = async (newMessage: string) => { - createMessage(chatId, newMessage, chat?.doctorId!) - if (error) { - toast({ - title: `Message sending failed ${error.statusCode && `with ${error.statusCode}`}`, - description: error.message || "Unknown error Occurred", - variant: "destructive" - }) - } - - } + const handleSendMessage = async (newMessage: string) => { + createMessage(chatId, newMessage, chat?.doctorId!); + if (error) { + toast({ + title: `Message sending failed ${error.statusCode && `with ${error.statusCode}`}`, + description: error.message || "Unknown error Occurred", + variant: "destructive", + }); + } + }; - return ( - - ); -} + return ( + + ); +}; export default Page; diff --git a/client/app/(patient)/chats/@chat/default.tsx b/client/app/(patient)/chats/@chat/default.tsx index 9eb0bed9..58eefec6 100644 --- a/client/app/(patient)/chats/@chat/default.tsx +++ b/client/app/(patient)/chats/@chat/default.tsx @@ -1,18 +1,24 @@ -import { Card, CardContent } from "@/components/ui/card" -import Image from "next/image" +import { Card, CardContent } from "@/components/ui/card"; +import Image from "next/image"; export default function ChatDefault() { - return ( -
- - - Chat Default -

Welcome to Your Chat

-

- Select an existing conversation from the sidebar or start a new chat to begin messaging. -

-
-
-
- ) + return ( +
+ + + Chat Default +

Welcome to Your Chat

+

+ Select an existing conversation from the sidebar or start a new chat to begin messaging. +

+
+
+
+ ); } diff --git a/client/app/(patient)/chats/@chatList/default.tsx b/client/app/(patient)/chats/@chatList/default.tsx index 9ee48d7e..df46cfc2 100644 --- a/client/app/(patient)/chats/@chatList/default.tsx +++ b/client/app/(patient)/chats/@chatList/default.tsx @@ -1,5 +1,5 @@ -import ChatList from './page' +import ChatList from "./page"; export default function DefaultChatList() { - return ; -} \ No newline at end of file + return ; +} diff --git a/client/app/(patient)/chats/@chatList/page.tsx b/client/app/(patient)/chats/@chatList/page.tsx index aabf2f81..9fc312b3 100644 --- a/client/app/(patient)/chats/@chatList/page.tsx +++ b/client/app/(patient)/chats/@chatList/page.tsx @@ -1,4 +1,4 @@ -'use client'; +"use client"; import NewChatModal, { ChatModelUser } from "@/components/models/chat/AddChatModel"; import ChatList from "@/components/page-components/chat/ChatList"; import { useGetDoctorsList } from "@/lib/hooks/appointment/useAppointmentDoctor"; @@ -7,59 +7,55 @@ import { useRouter } from "next/navigation"; import { useEffect, useState } from "react"; const Page = () => { - const { data } = useGetDoctorsList(); - const [isNewChatModalOpen, setNewChatModalOpen] = useState(false); - const [isLoading, setLoading] = useState(true); - const { chats, createChat, error, joinChatRoom } = useChats({ role: "patient", messagePath: "/chats" }); - const [doctors, setDoctors] = useState([]); - const router = useRouter(); - - useEffect(() => { - if (chats) { - setLoading(false); - } - setDoctors(data?.items.map(({ _id, image, name }) => ({ _id, name, profilePicture: image })) || []); - }, [chats, data]); - - const handleCloseModal = () => { - setNewChatModalOpen(false); - }; - - - const handleJoinChat = (chatId: string) => { - joinChatRoom(chatId); - setTimeout(() => { - router.refresh(); - }, 0); - }; - - - - const handleAddDoctorChat = (doctorId: string) => { - setNewChatModalOpen(false); - createChat(doctorId); - }; - - return ( - <> - setNewChatModalOpen(true)} - /> - {doctors && ( - - )} - - ); + const { data } = useGetDoctorsList(); + const [isNewChatModalOpen, setNewChatModalOpen] = useState(false); + const [isLoading, setLoading] = useState(true); + const { chats, createChat, error, joinChatRoom } = useChats({ role: "patient", messagePath: "/chats" }); + const [doctors, setDoctors] = useState([]); + const router = useRouter(); + + useEffect(() => { + if (chats) { + setLoading(false); + } + setDoctors(data?.items.map(({ _id, image, name }) => ({ _id, name, profilePicture: image })) || []); + }, [chats, data]); + + const handleCloseModal = () => { + setNewChatModalOpen(false); + }; + + const handleJoinChat = (chatId: string) => { + joinChatRoom(chatId); + setTimeout(() => { + router.refresh(); + }, 0); + }; + + const handleAddDoctorChat = (doctorId: string) => { + setNewChatModalOpen(false); + createChat(doctorId); + }; + + return ( + <> + setNewChatModalOpen(true)} + /> + {doctors && ( + + )} + + ); }; -export default Page - +export default Page; diff --git a/client/app/(patient)/chats/layout.tsx b/client/app/(patient)/chats/layout.tsx index 284edd1e..5cd9e9b6 100644 --- a/client/app/(patient)/chats/layout.tsx +++ b/client/app/(patient)/chats/layout.tsx @@ -1,14 +1,23 @@ -import ChatLayout from "@/components/page-components/chat/ChatLayout" +import ChatLayout from "@/components/page-components/chat/ChatLayout"; import { Metadata } from "next"; -import { ReactNode } from "react" +import { ReactNode } from "react"; export const metadata: Metadata = { - title: 'Chat', - description: 'Chat with your doctor, manage your chats seamlessly with AVM Ayurvedic', - keywords: ['chat', 'messages', 'AVM Ayurvedic', 'healthcare', 'doctor', 'patient', 'chat with doctor', 'chat with patient'], + title: "Chat", + description: "Chat with your doctor, manage your chats seamlessly with AVM Ayurvedic", + keywords: [ + "chat", + "messages", + "AVM Ayurvedic", + "healthcare", + "doctor", + "patient", + "chat with doctor", + "chat with patient", + ], }; const layout = ({ chatList, chat }: { chatList: ReactNode; chat: ReactNode }) => { - return -} + return ; +}; -export default layout \ No newline at end of file +export default layout; diff --git a/client/app/(patient)/chats/page.tsx b/client/app/(patient)/chats/page.tsx index 611891fe..e3deaad9 100644 --- a/client/app/(patient)/chats/page.tsx +++ b/client/app/(patient)/chats/page.tsx @@ -1,5 +1,5 @@ -import ChatUserList from './@chatList/page'; +import ChatUserList from "./@chatList/page"; export default function ChatsPage() { - return ; -} \ No newline at end of file + return ; +} diff --git a/client/app/(patient)/new-appointment/[id]/page.tsx b/client/app/(patient)/new-appointment/[id]/page.tsx index 186df014..3a0043b4 100644 --- a/client/app/(patient)/new-appointment/[id]/page.tsx +++ b/client/app/(patient)/new-appointment/[id]/page.tsx @@ -1,4 +1,4 @@ -'use client'; +"use client"; import { useGetAppointmentSuccessPageDetails } from "@/lib/hooks/appointment/useAppointmentPatient"; import { Skeleton } from "@/components/ui/skeleton"; @@ -6,154 +6,160 @@ import Image from "next/image"; import Link from "next/link"; import { useParams } from "next/navigation"; import { XCircle, Calendar, User, Stethoscope } from "lucide-react"; -import { format } from 'date-fns'; +import { format } from "date-fns"; import { BreadcrumbCollapsed } from "@/components/navigation/BreadCrumbs"; import { Card, CardContent, CardFooter, CardHeader } from "@/components/ui/card"; import { motion } from "framer-motion"; import { ButtonV2 } from "@/components/button/ButtonV2"; export default function AppointmentSuccessPage() { - const paymentId = useParams().id as string; - const { data: appointment, isLoading, error } = useGetAppointmentSuccessPageDetails(paymentId); + const paymentId = useParams().id as string; + const { data: appointment, isLoading, error } = useGetAppointmentSuccessPageDetails(paymentId); - return ( -
- - - AVM Ayurveda Logo - + return ( +
+ + + AVM Ayurveda Logo + - - -

Appointment Status

-
- - {error ? ( - - -

Oops! Something went wrong

-

- {error?.response?.data?.message || - "We couldn't fetch your appointment details. Please try again later."} -

- - Try Booking Again - -
- ) : ( - <> -
- {isLoading ? ( - - ) : ( + + +

Appointment Status

+
+ + {error ? ( - Success + +

Oops! Something went wrong

+

+ {error?.response?.data?.message || + "We couldn't fetch your appointment details. Please try again later."} +

+ + Try Booking Again +
- )} -

- {isLoading ? ( - - ) : ( - <> - Your Appointment request has been successfully - submitted! We will be in touch shortly to confirm. - - )} -

-
+ ) : ( + <> +
+ {isLoading ? ( + + ) : ( + + Success + + )} +

+ {isLoading ? ( + + ) : ( + <> + Your Appointment request has been successfully + submitted! We will be in touch shortly to confirm. + + )} +

+
- {isLoading ? ( -
- {[...Array(3)].map((_, index) => ( -
- -
- - -
-
- ))} -
- ) : appointment ? ( - -
- -
-

Appointment Date

-

- {format(appointment.appointmentDate!, "PPPP")} , {appointment.slot?.startTime} -

-
-
-
- -
-

Doctor

-

{appointment.doctor?.name}

-
-
-
- -
-

Appointment Type

-

- {appointment.appointmentType!.replace("-", " ")} -

-
-
-
- ) : ( -
-

- Appointment details are not available at the moment. If this persists, please contact - support. -

-
- )} - - )} -
- {!isLoading && !error && ( - - - Show Details - - - Book Another Appointment - - - )} -
+ {isLoading ? ( +
+ {[...Array(3)].map((_, index) => ( +
+ +
+ + +
+
+ ))} +
+ ) : appointment ? ( + +
+ +
+

Appointment Date

+

+ {format(appointment.appointmentDate!, "PPPP")} , {appointment.slot?.startTime} +

+
+
+
+ +
+

Doctor

+

{appointment.doctor?.name}

+
+
+
+ +
+

Appointment Type

+

+ {appointment.appointmentType!.replace("-", " ")} +

+
+
+
+ ) : ( +
+

+ Appointment details are not available at the moment. If this persists, please contact + support. +

+
+ )} + + )} + + {!isLoading && !error && ( + + + Show Details + + + Book Another Appointment + + + )} + -

ยฉ 2024 AVM Ayurveda

-
- ); -} \ No newline at end of file +

ยฉ 2024 AVM Ayurveda

+
+ ); +} diff --git a/client/app/(patient)/new-appointment/cancel/[id]/page.tsx b/client/app/(patient)/new-appointment/cancel/[id]/page.tsx index e5b4166d..38f721a5 100644 --- a/client/app/(patient)/new-appointment/cancel/[id]/page.tsx +++ b/client/app/(patient)/new-appointment/cancel/[id]/page.tsx @@ -19,7 +19,13 @@ export default function PaymentFailurePage() { return (
- +

Payment Failed

- We're sorry, but your payment could not be processed. Please try again or contact support if the issue - persists. + We're sorry, but your payment could not be processed. Please try again or contact support if the + issue persists.

diff --git a/client/app/(patient)/profile/page.tsx b/client/app/(patient)/profile/page.tsx index eb483bc5..6f737e65 100644 --- a/client/app/(patient)/profile/page.tsx +++ b/client/app/(patient)/profile/page.tsx @@ -8,7 +8,9 @@ import { ButtonV2 } from "@/components/button/ButtonV2"; import dynamic from "next/dynamic"; import Loading from "@/components/skeletons/Loader"; -const UpdateProfilePatient = dynamic(()=>import("@/components/models/patient/UpdateProfilePatient"), { loading: () => }); +const UpdateProfilePatient = dynamic(() => import("@/components/models/patient/UpdateProfilePatient"), { + loading: () => , +}); export default function PatientProfilePage() { const { data: patientData, isLoading, refetch } = useGetPatientProfile(); diff --git a/client/app/(patient)/signin/page.tsx b/client/app/(patient)/signin/page.tsx index 28058f67..e3ca86a6 100644 --- a/client/app/(patient)/signin/page.tsx +++ b/client/app/(patient)/signin/page.tsx @@ -8,4 +8,4 @@ const SignIn = () => { return ; }; -export default SignIn; \ No newline at end of file +export default SignIn; diff --git a/client/app/(patient)/signup/page.tsx b/client/app/(patient)/signup/page.tsx index c1445d23..1e7ce563 100644 --- a/client/app/(patient)/signup/page.tsx +++ b/client/app/(patient)/signup/page.tsx @@ -9,4 +9,4 @@ const Register = () => { return ; }; -export default Register; \ No newline at end of file +export default Register; diff --git a/client/app/(patient)/video-section/[sectionId]/layout.tsx b/client/app/(patient)/video-section/[sectionId]/layout.tsx index b25cf4b8..84a73150 100644 --- a/client/app/(patient)/video-section/[sectionId]/layout.tsx +++ b/client/app/(patient)/video-section/[sectionId]/layout.tsx @@ -1,19 +1,16 @@ -import PatientVideoLayout from '@/components/page-components/video/PatientVideoLayout'; -import { Metadata } from 'next'; -import { ReactNode } from 'react'; +import PatientVideoLayout from "@/components/page-components/video/PatientVideoLayout"; +import { Metadata } from "next"; +import { ReactNode } from "react"; export const metadata: Metadata = { - title: 'Video Call', - description: 'Video consultation with the doctor.', - keywords: 'video, call, consultation, doctor, patient, ayurveda, health, medicine, chat, video call, video consultation, video chat, video meeting, video consultation, video call ayurveda, video call doctor, video call patient, video call ayurveda doctor, video call ayurveda patient, video call doctor patient, video call ayurveda doctor patient', -} + title: "Video Call", + description: "Video consultation with the doctor.", + keywords: + "video, call, consultation, doctor, patient, ayurveda, health, medicine, chat, video call, video consultation, video chat, video meeting, video consultation, video call ayurveda, video call doctor, video call patient, video call ayurveda doctor, video call ayurveda patient, video call doctor patient, video call ayurveda doctor patient", +}; -const layout = ({ children }: { children: ReactNode; }) => { - return ( - - {children} - - ) -} +const layout = ({ children }: { children: ReactNode }) => { + return {children}; +}; -export default layout \ No newline at end of file +export default layout; diff --git a/client/app/(patient)/video-section/[sectionId]/page.tsx b/client/app/(patient)/video-section/[sectionId]/page.tsx index 60fc942a..e0d6e730 100644 --- a/client/app/(patient)/video-section/[sectionId]/page.tsx +++ b/client/app/(patient)/video-section/[sectionId]/page.tsx @@ -1,46 +1,46 @@ -'use client' +"use client"; -import { useParams } from 'next/navigation'; -import JoinPage from '@/components/page-components/video/JoinVideoCallPage'; -import VideoChat from '@/components/page-components/video/VideoChat'; -import { useGetSectionByIdPatient } from '@/lib/hooks/video/usePatient'; -import { useVideoCall } from '@/lib/hooks/useVideoCall'; +import { useParams } from "next/navigation"; +import JoinPage from "@/components/page-components/video/JoinVideoCallPage"; +import VideoChat from "@/components/page-components/video/VideoChat"; +import { useGetSectionByIdPatient } from "@/lib/hooks/video/usePatient"; +import { useVideoCall } from "@/lib/hooks/useVideoCall"; export default function PatientVideoCallPage() { - const { sectionId } = useParams(); - const { data, isLoading } = useGetSectionByIdPatient(sectionId as string); - const section = data?.section; + const { sectionId } = useParams(); + const { data, isLoading } = useGetSectionByIdPatient(sectionId as string); + const section = data?.section; - const { - hasJoined, - localStream, - remoteStream, - isMuted, - handleJoin, - handleEndCall, - isVideoOff, - toggleMute, - toggleVideo - } = useVideoCall(section, 'patient'); + const { + hasJoined, + localStream, + remoteStream, + isMuted, + handleJoin, + handleEndCall, + isVideoOff, + toggleMute, + toggleVideo, + } = useVideoCall(section, "patient"); - if (isLoading) return
Loading...
; + if (isLoading) return
Loading...
; - if (!hasJoined) { - return ; - } + if (!hasJoined) { + return ; + } - return ( - - ); + return ( + + ); } diff --git a/client/app/@chatbot/default.tsx b/client/app/@chatbot/default.tsx index 61743df5..333c0752 100644 --- a/client/app/@chatbot/default.tsx +++ b/client/app/@chatbot/default.tsx @@ -1,2 +1,2 @@ -import ChatBot from './page'; -export default ChatBot; \ No newline at end of file +import ChatBot from "./page"; +export default ChatBot; diff --git a/client/app/@chatbot/page.tsx b/client/app/@chatbot/page.tsx index 72c2c1a5..e075f989 100644 --- a/client/app/@chatbot/page.tsx +++ b/client/app/@chatbot/page.tsx @@ -1,15 +1,22 @@ -import Chatbot from '@/components/page-components/chatbot/ChatBotButton'; -import { Metadata } from 'next'; +import Chatbot from "@/components/page-components/chatbot/ChatBotButton"; +import { Metadata } from "next"; export const metadata: Metadata = { - keywords: ["chat bot", "open ai", "AI chatbot", "virtual assistant", 'chat', 'messages', 'AVM Ayurvedic', 'healthcare'], - description: "Integrating an OpenAI chatbot into the application to enhance user experience", + keywords: [ + "chat bot", + "open ai", + "AI chatbot", + "virtual assistant", + "chat", + "messages", + "AVM Ayurvedic", + "healthcare", + ], + description: "Integrating an OpenAI chatbot into the application to enhance user experience", }; const page = () => { - return ( - - ) + return ; }; -export default page; \ No newline at end of file +export default page; diff --git a/client/app/admin/(pages)/dashboard/@appointmentStatus/default.tsx b/client/app/admin/(pages)/dashboard/@appointmentStatus/default.tsx index 96de9d79..a66694d7 100644 --- a/client/app/admin/(pages)/dashboard/@appointmentStatus/default.tsx +++ b/client/app/admin/(pages)/dashboard/@appointmentStatus/default.tsx @@ -1,2 +1,2 @@ -import page from './page'; -export default page \ No newline at end of file +import page from "./page"; +export default page; diff --git a/client/app/admin/(pages)/dashboard/@appointmentStatus/error.tsx b/client/app/admin/(pages)/dashboard/@appointmentStatus/error.tsx index f39b7d74..1b7a486c 100644 --- a/client/app/admin/(pages)/dashboard/@appointmentStatus/error.tsx +++ b/client/app/admin/(pages)/dashboard/@appointmentStatus/error.tsx @@ -1,3 +1,3 @@ -'use client' -import Error from '../error'; -export default Error; \ No newline at end of file +"use client"; +import Error from "../error"; +export default Error; diff --git a/client/app/admin/(pages)/dashboard/@appointmentStatus/loading.tsx b/client/app/admin/(pages)/dashboard/@appointmentStatus/loading.tsx index 9b1a5a87..c0ba7d72 100644 --- a/client/app/admin/(pages)/dashboard/@appointmentStatus/loading.tsx +++ b/client/app/admin/(pages)/dashboard/@appointmentStatus/loading.tsx @@ -1,23 +1,23 @@ -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" -import { Skeleton } from "@/components/ui/skeleton" +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Skeleton } from "@/components/ui/skeleton"; export default function AppointmentStatusChartLoading() { - return ( - - - - - - - -
- - - - - -
-
-
- ) -} \ No newline at end of file + return ( + + + + + + + +
+ + + + + +
+
+
+ ); +} diff --git a/client/app/admin/(pages)/dashboard/@appointmentStatus/page.tsx b/client/app/admin/(pages)/dashboard/@appointmentStatus/page.tsx index 95987ad5..f507f2fb 100644 --- a/client/app/admin/(pages)/dashboard/@appointmentStatus/page.tsx +++ b/client/app/admin/(pages)/dashboard/@appointmentStatus/page.tsx @@ -1,82 +1,79 @@ -'use client' +"use client"; -import { BarChart, Bar, XAxis, YAxis, CartesianGrid, ResponsiveContainer, Legend, Cell } from "recharts" -import { CardHeader, CardTitle } from "@/components/ui/card" -import { ChartContainer, ChartTooltip, ChartTooltipContent } from "@/components/ui/chart" -import { useGetAppointmentsStatisticsByStatus } from "@/lib/hooks/admin/useDashboard" -import { AppointmentStatus } from "@/types/enum" -import Loading from './loading' +import { BarChart, Bar, XAxis, YAxis, CartesianGrid, ResponsiveContainer, Legend, Cell } from "recharts"; +import { CardHeader, CardTitle } from "@/components/ui/card"; +import { ChartContainer, ChartTooltip, ChartTooltipContent } from "@/components/ui/chart"; +import { useGetAppointmentsStatisticsByStatus } from "@/lib/hooks/admin/useDashboard"; +import { AppointmentStatus } from "@/types/enum"; +import Loading from "./loading"; export type AppointmentsByStatusStatistics = { - status: AppointmentStatus - count: number -} + status: AppointmentStatus; + count: number; +}; const AppointmentStatusChart = () => { - const { data, isLoading, error } = useGetAppointmentsStatisticsByStatus() + const { data, isLoading, error } = useGetAppointmentsStatisticsByStatus(); - if (error) throw new Error(error.response?.data.message || "Unknown error occurred") - if (!data || isLoading) return + if (error) throw new Error(error.response?.data.message || "Unknown error occurred"); + if (!data || isLoading) return ; - const chartData = data.statistics.map(stat => ({ - status: stat.status.charAt(0).toUpperCase() + stat.status.slice(1).replace('-', ' '), - count: stat.count - })) + const chartData = data.statistics.map((stat) => ({ + status: stat.status.charAt(0).toUpperCase() + stat.status.slice(1).replace("-", " "), + count: stat.count, + })); - const COLORS = { - [AppointmentStatus.PAYMENT_PENDING]: "hsl(var(--chart-1))", - [AppointmentStatus.PENDING]: "hsl(var(--chart-2))", - [AppointmentStatus.CONFIRMED]: "hsl(var(--chart-3))", - [AppointmentStatus.CANCELLED]: "hsl(var(--chart-4))", - [AppointmentStatus.COMPLETED]: "hsl(var(--chart-5))" - } + const COLORS = { + [AppointmentStatus.PAYMENT_PENDING]: "hsl(var(--chart-1))", + [AppointmentStatus.PENDING]: "hsl(var(--chart-2))", + [AppointmentStatus.CONFIRMED]: "hsl(var(--chart-3))", + [AppointmentStatus.CANCELLED]: "hsl(var(--chart-4))", + [AppointmentStatus.COMPLETED]: "hsl(var(--chart-5))", + }; - return ( - <> - - Appointment Status Distribution - - [ - value, - { label: key, color: COLORS[value] } - ]) - )} - className="h-full w-full" - > - - - - - - { - if (Array.isArray(value)) { - return [`${value.join(', ')}`, name]; - } else { - return [`${value} `, name]; - } - }} - /> - } - /> - - - {chartData.map((entry, index) => ( - - ))} - - - - - - ) -} + return ( + <> + + Appointment Status Distribution + + [value, { label: key, color: COLORS[value] }]) + )} + className="h-full w-full" + > + + + + + + { + if (Array.isArray(value)) { + return [`${value.join(", ")}`, name]; + } else { + return [`${value} `, name]; + } + }} + /> + } + /> + + + {chartData.map((entry, index) => ( + + ))} + + + + + + ); +}; -export default AppointmentStatusChart \ No newline at end of file +export default AppointmentStatusChart; diff --git a/client/app/admin/(pages)/dashboard/@appointments/default.tsx b/client/app/admin/(pages)/dashboard/@appointments/default.tsx index 96de9d79..a66694d7 100644 --- a/client/app/admin/(pages)/dashboard/@appointments/default.tsx +++ b/client/app/admin/(pages)/dashboard/@appointments/default.tsx @@ -1,2 +1,2 @@ -import page from './page'; -export default page \ No newline at end of file +import page from "./page"; +export default page; diff --git a/client/app/admin/(pages)/dashboard/@appointments/error.tsx b/client/app/admin/(pages)/dashboard/@appointments/error.tsx index f39b7d74..1b7a486c 100644 --- a/client/app/admin/(pages)/dashboard/@appointments/error.tsx +++ b/client/app/admin/(pages)/dashboard/@appointments/error.tsx @@ -1,3 +1,3 @@ -'use client' -import Error from '../error'; -export default Error; \ No newline at end of file +"use client"; +import Error from "../error"; +export default Error; diff --git a/client/app/admin/(pages)/dashboard/@appointments/loading.tsx b/client/app/admin/(pages)/dashboard/@appointments/loading.tsx index c1a4835e..6d020385 100644 --- a/client/app/admin/(pages)/dashboard/@appointments/loading.tsx +++ b/client/app/admin/(pages)/dashboard/@appointments/loading.tsx @@ -1,23 +1,23 @@ -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" -import { Skeleton } from "@/components/ui/skeleton" +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Skeleton } from "@/components/ui/skeleton"; export default function AppointmentsPerMonthChartLoading() { - return ( - - - - - - - -
- - - - - -
-
-
- ) -} \ No newline at end of file + return ( + + + + + + + +
+ + + + + +
+
+
+ ); +} diff --git a/client/app/admin/(pages)/dashboard/@appointments/page.tsx b/client/app/admin/(pages)/dashboard/@appointments/page.tsx index 20115c7e..6a948cf3 100644 --- a/client/app/admin/(pages)/dashboard/@appointments/page.tsx +++ b/client/app/admin/(pages)/dashboard/@appointments/page.tsx @@ -1,91 +1,88 @@ -'use client' +"use client"; -import { AreaChart, Area, XAxis, YAxis, CartesianGrid, ResponsiveContainer, Legend } from "recharts" -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" -import { ChartContainer, ChartTooltip, ChartTooltipContent } from "@/components/ui/chart" -import { useGetAppointmentsByMonth } from '@/lib/hooks/admin/useDashboard' -import { Months } from "@/types/statistics" -import { ValueType } from "recharts/types/component/DefaultTooltipContent" -import Loading from './loading' +import { AreaChart, Area, XAxis, YAxis, CartesianGrid, ResponsiveContainer, Legend } from "recharts"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { ChartContainer, ChartTooltip, ChartTooltipContent } from "@/components/ui/chart"; +import { useGetAppointmentsByMonth } from "@/lib/hooks/admin/useDashboard"; +import { Months } from "@/types/statistics"; +import { ValueType } from "recharts/types/component/DefaultTooltipContent"; +import Loading from "./loading"; const AppointmentsPerMonthChart = () => { - const { data, isLoading, error } = useGetAppointmentsByMonth(); + const { data, isLoading, error } = useGetAppointmentsByMonth(); - if (error) throw new Error(error.response?.data.message || "Unknown error Occurred") - if (!data || isLoading) return ; + if (error) throw new Error(error.response?.data.message || "Unknown error Occurred"); + if (!data || isLoading) return ; - const chartData = data.statistics.map(stat => ({ - month: stat.month, - count: stat.count - })); + const chartData = data.statistics.map((stat) => ({ + month: stat.month, + count: stat.count, + })); - chartData.sort((a, b) => Object.values(Months).indexOf(a.month as Months) - Object.values(Months).indexOf(b.month as Months)); + chartData.sort( + (a, b) => Object.values(Months).indexOf(a.month as Months) - Object.values(Months).indexOf(b.month as Months) + ); - return ( - <> - - Appointments Per Month - - - - - - - - - - - - value.substring(0, 3)} - interval={0} - angle={-45} - textAnchor="end" - height={60} - tick={{ fontSize: 10 }} - /> - value.toLocaleString()} - tick={{ fontSize: 10 }} - /> - { - if (typeof value === 'number') { - return [value.toLocaleString(), " Appointments"]; - } - return [String(value), " Appointments"]; - }} - /> - } - /> - - - - - - - ) -} + return ( + <> + + Appointments Per Month + + + + + + + + + + + + value.substring(0, 3)} + interval={0} + angle={-45} + textAnchor="end" + height={60} + tick={{ fontSize: 10 }} + /> + value.toLocaleString()} tick={{ fontSize: 10 }} /> + { + if (typeof value === "number") { + return [value.toLocaleString(), " Appointments"]; + } + return [String(value), " Appointments"]; + }} + /> + } + /> + + + + + + + ); +}; -export default AppointmentsPerMonthChart \ No newline at end of file +export default AppointmentsPerMonthChart; diff --git a/client/app/admin/(pages)/dashboard/@patientGender/default.tsx b/client/app/admin/(pages)/dashboard/@patientGender/default.tsx index 96de9d79..a66694d7 100644 --- a/client/app/admin/(pages)/dashboard/@patientGender/default.tsx +++ b/client/app/admin/(pages)/dashboard/@patientGender/default.tsx @@ -1,2 +1,2 @@ -import page from './page'; -export default page \ No newline at end of file +import page from "./page"; +export default page; diff --git a/client/app/admin/(pages)/dashboard/@patientGender/error.tsx b/client/app/admin/(pages)/dashboard/@patientGender/error.tsx index f39b7d74..1b7a486c 100644 --- a/client/app/admin/(pages)/dashboard/@patientGender/error.tsx +++ b/client/app/admin/(pages)/dashboard/@patientGender/error.tsx @@ -1,3 +1,3 @@ -'use client' -import Error from '../error'; -export default Error; \ No newline at end of file +"use client"; +import Error from "../error"; +export default Error; diff --git a/client/app/admin/(pages)/dashboard/@patientGender/loading.tsx b/client/app/admin/(pages)/dashboard/@patientGender/loading.tsx index 384968fd..cacda16c 100644 --- a/client/app/admin/(pages)/dashboard/@patientGender/loading.tsx +++ b/client/app/admin/(pages)/dashboard/@patientGender/loading.tsx @@ -1,19 +1,19 @@ -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" -import { Skeleton } from "@/components/ui/skeleton" +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Skeleton } from "@/components/ui/skeleton"; export default function GenderChartLoading() { - return ( - - - - - - - -
- -
-
-
- ) -} \ No newline at end of file + return ( + + + + + + + +
+ +
+
+
+ ); +} diff --git a/client/app/admin/(pages)/dashboard/@patientGender/page.tsx b/client/app/admin/(pages)/dashboard/@patientGender/page.tsx index 9d64e8db..ed645491 100644 --- a/client/app/admin/(pages)/dashboard/@patientGender/page.tsx +++ b/client/app/admin/(pages)/dashboard/@patientGender/page.tsx @@ -1,65 +1,65 @@ -'use client' +"use client"; -import { PieChart, Pie, Cell, ResponsiveContainer, Legend } from "recharts" -import { CardHeader, CardTitle } from "@/components/ui/card" -import { ChartContainer, ChartTooltip, ChartTooltipContent } from "@/components/ui/chart" -import { useGetPatientGenderStatics } from "@/lib/hooks/admin/useDashboard" -import Loading from './loading' +import { PieChart, Pie, Cell, ResponsiveContainer, Legend } from "recharts"; +import { CardHeader, CardTitle } from "@/components/ui/card"; +import { ChartContainer, ChartTooltip, ChartTooltipContent } from "@/components/ui/chart"; +import { useGetPatientGenderStatics } from "@/lib/hooks/admin/useDashboard"; +import Loading from "./loading"; const GenderChart = () => { - const { data, error, isLoading } = useGetPatientGenderStatics(); + const { data, error, isLoading } = useGetPatientGenderStatics(); - if (error) throw new Error(error.response?.data.message || "Unknown error Occurred") - if (!data || isLoading) return + if (error) throw new Error(error.response?.data.message || "Unknown error Occurred"); + if (!data || isLoading) return ; - const chartData = [ - { name: 'Male', value: data.statistics.male }, - { name: 'Female', value: data.statistics.female }, - { name: 'Others', value: data.statistics.others }, - ]; + const chartData = [ + { name: "Male", value: data.statistics.male }, + { name: "Female", value: data.statistics.female }, + { name: "Others", value: data.statistics.others }, + ]; - const COLORS = ['hsl(var(--chart-1))', 'hsl(var(--chart-2))', 'hsl(var(--chart-3))']; + const COLORS = ["hsl(var(--chart-1))", "hsl(var(--chart-2))", "hsl(var(--chart-3))"]; - return ( - <> - - Patient Gender Distribution - - - - - - {chartData.map((entry, index) => ( - - ))} - - } /> - - - - - - ) -} + return ( + <> + + Patient Gender Distribution + + + + + + {chartData.map((entry, index) => ( + + ))} + + } /> + + + + + + ); +}; -export default GenderChart \ No newline at end of file +export default GenderChart; diff --git a/client/app/admin/(pages)/dashboard/@slotUsage/default.tsx b/client/app/admin/(pages)/dashboard/@slotUsage/default.tsx index 96de9d79..a66694d7 100644 --- a/client/app/admin/(pages)/dashboard/@slotUsage/default.tsx +++ b/client/app/admin/(pages)/dashboard/@slotUsage/default.tsx @@ -1,2 +1,2 @@ -import page from './page'; -export default page \ No newline at end of file +import page from "./page"; +export default page; diff --git a/client/app/admin/(pages)/dashboard/@slotUsage/error.tsx b/client/app/admin/(pages)/dashboard/@slotUsage/error.tsx index f39b7d74..1b7a486c 100644 --- a/client/app/admin/(pages)/dashboard/@slotUsage/error.tsx +++ b/client/app/admin/(pages)/dashboard/@slotUsage/error.tsx @@ -1,3 +1,3 @@ -'use client' -import Error from '../error'; -export default Error; \ No newline at end of file +"use client"; +import Error from "../error"; +export default Error; diff --git a/client/app/admin/(pages)/dashboard/@slotUsage/loading.tsx b/client/app/admin/(pages)/dashboard/@slotUsage/loading.tsx index 3a75548e..98ff4088 100644 --- a/client/app/admin/(pages)/dashboard/@slotUsage/loading.tsx +++ b/client/app/admin/(pages)/dashboard/@slotUsage/loading.tsx @@ -1,21 +1,21 @@ -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" -import { Skeleton } from "@/components/ui/skeleton" +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Skeleton } from "@/components/ui/skeleton"; export default function SlotUsageChartLoading() { - return ( - - - - - - - -
- {[...Array(12)].map((_, i) => ( - - ))} -
-
-
- ) -} \ No newline at end of file + return ( + + + + + + + +
+ {[...Array(12)].map((_, i) => ( + + ))} +
+
+
+ ); +} diff --git a/client/app/admin/(pages)/dashboard/@slotUsage/page.tsx b/client/app/admin/(pages)/dashboard/@slotUsage/page.tsx index fae6aba8..6168b6af 100644 --- a/client/app/admin/(pages)/dashboard/@slotUsage/page.tsx +++ b/client/app/admin/(pages)/dashboard/@slotUsage/page.tsx @@ -1,96 +1,89 @@ -'use client' +"use client"; -import { BarChart, Bar, XAxis, YAxis, CartesianGrid, ResponsiveContainer } from "recharts" -import { CardHeader, CardTitle, CardContent } from "@/components/ui/card" -import { ChartContainer, ChartTooltip, ChartTooltipContent } from "@/components/ui/chart" -import { useGetSlotStatistics } from "@/lib/hooks/admin/useDashboard" -import Loading from './loading' -import { AllSlotTimes } from "@/constants" -import { ValueType } from "recharts/types/component/DefaultTooltipContent" +import { BarChart, Bar, XAxis, YAxis, CartesianGrid, ResponsiveContainer } from "recharts"; +import { CardHeader, CardTitle, CardContent } from "@/components/ui/card"; +import { ChartContainer, ChartTooltip, ChartTooltipContent } from "@/components/ui/chart"; +import { useGetSlotStatistics } from "@/lib/hooks/admin/useDashboard"; +import Loading from "./loading"; +import { AllSlotTimes } from "@/constants"; +import { ValueType } from "recharts/types/component/DefaultTooltipContent"; export type SlotStatistics = { - time: string; - count: number; -} + time: string; + count: number; +}; const SlotUsageChart = () => { - const { data, error, isLoading } = useGetSlotStatistics(); + const { data, error, isLoading } = useGetSlotStatistics(); - if (error) throw new Error(error.response?.data.message || "Unknown error occurred") - if (!data || isLoading) return + if (error) throw new Error(error.response?.data.message || "Unknown error occurred"); + if (!data || isLoading) return ; - const statisticsMap = new Map(data.statistics.map(stat => [stat.time, stat.count])); + const statisticsMap = new Map(data.statistics.map((stat) => [stat.time, stat.count])); - const chartData = AllSlotTimes.map(time => ({ - time, - count: `${statisticsMap.get(time) || 0}` - })); + const chartData = AllSlotTimes.map((time) => ({ + time, + count: `${statisticsMap.get(time) || 0}`, + })); - const sortedData = chartData.sort((a, b) => { - const timeA = new Date(`2000-01-01 ${a.time}`); - const timeB = new Date(`2000-01-01 ${b.time}`); - return timeA.getTime() - timeB.getTime(); - }); + const sortedData = chartData.sort((a, b) => { + const timeA = new Date(`2000-01-01 ${a.time}`); + const timeB = new Date(`2000-01-01 ${b.time}`); + return timeA.getTime() - timeB.getTime(); + }); - const formatXAxisTick = (time: string) => { - const [hours, minutes] = time.split(':'); - const hour = parseInt(hours, 10); - const formattedHour = hour % 12 || 12; - return `${formattedHour}:${minutes}`; - }; + const formatXAxisTick = (time: string) => { + const [hours, minutes] = time.split(":"); + const hour = parseInt(hours, 10); + const formattedHour = hour % 12 || 12; + return `${formattedHour}:${minutes}`; + }; - return ( - <> - - Slot Usage Statistics - - - - - - - value.toLocaleString()} - /> - { - if (typeof value === 'number') { - return [value.toLocaleString(), "Appointments"]; - } - return [String(value), "Appointments"]; - }} - /> - } /> - - - - - - ) -} + return ( + <> + + Slot Usage Statistics + + + + + + + value.toLocaleString()} /> + { + if (typeof value === "number") { + return [value.toLocaleString(), "Appointments"]; + } + return [String(value), "Appointments"]; + }} + /> + } + /> + + + + + + ); +}; -export default SlotUsageChart \ No newline at end of file +export default SlotUsageChart; diff --git a/client/app/admin/(pages)/dashboard/@users/default.tsx b/client/app/admin/(pages)/dashboard/@users/default.tsx index 96de9d79..a66694d7 100644 --- a/client/app/admin/(pages)/dashboard/@users/default.tsx +++ b/client/app/admin/(pages)/dashboard/@users/default.tsx @@ -1,2 +1,2 @@ -import page from './page'; -export default page \ No newline at end of file +import page from "./page"; +export default page; diff --git a/client/app/admin/(pages)/dashboard/@users/error.tsx b/client/app/admin/(pages)/dashboard/@users/error.tsx index f39b7d74..1b7a486c 100644 --- a/client/app/admin/(pages)/dashboard/@users/error.tsx +++ b/client/app/admin/(pages)/dashboard/@users/error.tsx @@ -1,3 +1,3 @@ -'use client' -import Error from '../error'; -export default Error; \ No newline at end of file +"use client"; +import Error from "../error"; +export default Error; diff --git a/client/app/admin/(pages)/dashboard/@users/loading.tsx b/client/app/admin/(pages)/dashboard/@users/loading.tsx index f544e3ff..3a6db68c 100644 --- a/client/app/admin/(pages)/dashboard/@users/loading.tsx +++ b/client/app/admin/(pages)/dashboard/@users/loading.tsx @@ -1,24 +1,24 @@ -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" -import { Skeleton } from "@/components/ui/skeleton" +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Skeleton } from "@/components/ui/skeleton"; export default function UsersChartLoading() { - return ( - - - - - - - -
- {[...Array(6)].map((_, i) => ( -
- - + return ( + + + + + + + +
+ {[...Array(6)].map((_, i) => ( +
+ + +
+ ))}
- ))} -
- - - ) -} \ No newline at end of file + + + ); +} diff --git a/client/app/admin/(pages)/dashboard/@users/page.tsx b/client/app/admin/(pages)/dashboard/@users/page.tsx index 81274dfe..f7b3c3c0 100644 --- a/client/app/admin/(pages)/dashboard/@users/page.tsx +++ b/client/app/admin/(pages)/dashboard/@users/page.tsx @@ -1,64 +1,66 @@ -'use client'; +"use client"; import { BarChart, Bar, XAxis, YAxis, CartesianGrid, ResponsiveContainer, Legend } from "recharts"; import { CardHeader, CardTitle } from "@/components/ui/card"; import { ChartContainer, ChartTooltip, ChartTooltipContent } from "@/components/ui/chart"; import { useGetUsersStatics } from "@/lib/hooks/admin/useDashboard"; import { Months } from "@/types/statistics"; -import Loading from './loading'; +import Loading from "./loading"; const UsersChart = () => { - const { data, error, isLoading } = useGetUsersStatics(); + const { data, error, isLoading } = useGetUsersStatics(); - if (error) throw new Error(error.response?.data.message || "Unknown error Occurred"); - if (!data || isLoading) return ; + if (error) throw new Error(error.response?.data.message || "Unknown error Occurred"); + if (!data || isLoading) return ; - const chartData = data.statistics.map(stat => ({ - month: stat.month, - doctors: stat.doctors, - patients: stat.patients - })); + const chartData = data.statistics.map((stat) => ({ + month: stat.month, + doctors: stat.doctors, + patients: stat.patients, + })); - chartData.sort((a, b) => Object.values(Months).indexOf(a.month as Months) - Object.values(Months).indexOf(b.month as Months)); + chartData.sort( + (a, b) => Object.values(Months).indexOf(a.month as Months) - Object.values(Months).indexOf(b.month as Months) + ); - return ( - <> - - User Growth - - - - - - value.substring(0, 3) } - interval={ 'preserveStartEnd' } - tick={ { fontSize: 10 } } - height={ 40 } - /> - - } /> - - - - - - - - ); + return ( + <> + + User Growth + + + + + + value.substring(0, 3)} + interval={"preserveStartEnd"} + tick={{ fontSize: 10 }} + height={40} + /> + + } /> + + + + + + + + ); }; -export default UsersChart; \ No newline at end of file +export default UsersChart; diff --git a/client/app/admin/(pages)/dashboard/error.tsx b/client/app/admin/(pages)/dashboard/error.tsx index b5343cd7..f87760b8 100644 --- a/client/app/admin/(pages)/dashboard/error.tsx +++ b/client/app/admin/(pages)/dashboard/error.tsx @@ -1,35 +1,26 @@ "use client"; import { useEffect } from "react"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { ButtonColorVariant, ButtonV2 } from "@/components/button/ButtonV2"; import { toast } from "@/components/ui/use-toast"; - const Error = ({ error, reset }: { error: Error & { digest?: string }; reset: () => void }) => { useEffect(() => { toast({ title: "Something went wrong!", variant: "destructive", - description: error.message + description: error.message, }); }, [error]); - - return ( - - Something went wrong! - + Something went wrong! - reset()} - > + reset()}> Try again diff --git a/client/app/admin/(pages)/dashboard/layout.tsx b/client/app/admin/(pages)/dashboard/layout.tsx index b79885d8..fc8ee1b2 100644 --- a/client/app/admin/(pages)/dashboard/layout.tsx +++ b/client/app/admin/(pages)/dashboard/layout.tsx @@ -1,66 +1,51 @@ -import { Card, CardContent } from "@/components/ui/card" -import { Metadata } from "next" -import { AdminDashBoardProps } from "@/types" +import { Card, CardContent } from "@/components/ui/card"; +import { Metadata } from "next"; +import { AdminDashBoardProps } from "@/types"; export const metadata: Metadata = { - title: "Hospital Statistics Overview | AVM Ayurvedic", - description: "View detailed hospital statistics, including patient demographics, appointment statuses, user activity, and slot usage. The Admin Dashboard offers a comprehensive overview to manage hospital operations efficiently.", - keywords: [ - "admin dashboard", - "hospital statistics", - "AVM Ayurvedic admin", - "patient demographics", - "appointment tracking", - "user activity", - "slot usage", - "hospital management", - "statistics overview", - "hospital operations" - ] -} + title: "Hospital Statistics Overview | AVM Ayurvedic", + description: + "View detailed hospital statistics, including patient demographics, appointment statuses, user activity, and slot usage. The Admin Dashboard offers a comprehensive overview to manage hospital operations efficiently.", + keywords: [ + "admin dashboard", + "hospital statistics", + "AVM Ayurvedic admin", + "patient demographics", + "appointment tracking", + "user activity", + "slot usage", + "hospital management", + "statistics overview", + "hospital operations", + ], +}; -const DashboardLayout = ({ - patientGender, - appointmentStatus, - appointments, - users, - slotUsage -}: AdminDashBoardProps) => { +const DashboardLayout = ({ patientGender, appointmentStatus, appointments, users, slotUsage }: AdminDashBoardProps) => { return ( -
-
-
- - - {appointments} - - -
- - - {patientGender} - - - - - {appointmentStatus} - - - - - {users} - - -
- - - {slotUsage} - - -
-
-
- ) -} +
+
+
+ + {appointments} + +
+ + {patientGender} + + + {appointmentStatus} + + + {users} + +
+ + {slotUsage} + +
+
+
+ ); +}; -export default DashboardLayout \ No newline at end of file +export default DashboardLayout; diff --git a/client/app/admin/@signin/default.tsx b/client/app/admin/@signin/default.tsx index 213e1e0e..c23f9905 100644 --- a/client/app/admin/@signin/default.tsx +++ b/client/app/admin/@signin/default.tsx @@ -1,2 +1,2 @@ -import Signin from './page'; -export default Signin; \ No newline at end of file +import Signin from "./page"; +export default Signin; diff --git a/client/app/admin/@signin/not-found.tsx b/client/app/admin/@signin/not-found.tsx index 4ef3852d..ae1e2d0c 100644 --- a/client/app/admin/@signin/not-found.tsx +++ b/client/app/admin/@signin/not-found.tsx @@ -1,8 +1,5 @@ import SignIn from "./page"; export default function NotFound() { - - return ( - - ); + return ; } diff --git a/client/app/admin/@signin/otp-verification/page.tsx b/client/app/admin/@signin/otp-verification/page.tsx index a31f03e7..148a372f 100644 --- a/client/app/admin/@signin/otp-verification/page.tsx +++ b/client/app/admin/@signin/otp-verification/page.tsx @@ -72,32 +72,32 @@ const OtpVerificationPage = () => {
patient

ยฉ 2024 AVM Ayurveda's

- + Go Back
patient diff --git a/client/app/admin/@signin/page.tsx b/client/app/admin/@signin/page.tsx index 3e945166..0303fc27 100644 --- a/client/app/admin/@signin/page.tsx +++ b/client/app/admin/@signin/page.tsx @@ -7,8 +7,8 @@ import Link from "next/link"; export const metadata: Metadata = { title: "Signin", - keywords:['admin dashboard','admin signin','authentication'], - description:"signin page for avm ayurvedic admin dashboard" + keywords: ["admin dashboard", "admin signin", "authentication"], + description: "signin page for avm ayurvedic admin dashboard", }; const SignIn = () => { @@ -17,19 +17,19 @@ const SignIn = () => {
patient

- ยฉ { new Date().getFullYear() } AVM Ayurvedic. + ยฉ {new Date().getFullYear()} AVM Ayurvedic.

- - + + Doctor @@ -37,7 +37,7 @@ const SignIn = () => {
- patient + patient
); }; diff --git a/client/app/admin/layout.tsx b/client/app/admin/layout.tsx index eed6ff1a..2ebcdf52 100644 --- a/client/app/admin/layout.tsx +++ b/client/app/admin/layout.tsx @@ -1,7 +1,7 @@ import { ReactNode, FC } from "react"; import { Metadata } from "next"; import Layout from "@/components/layout/AdminLayout"; -import { metadata as rootMeta } from '@/app/layout'; +import { metadata as rootMeta } from "@/app/layout"; interface AdminLayoutWrapperProps { children: ReactNode; @@ -13,7 +13,7 @@ export const metadata: Metadata = { title: { template: "%s | Admin", default: "Admin Dashboard - Manage Hospital Operations | AVM Ayurvedic", - } + }, }; const AdminLayoutWrapper: FC = ({ children, signin }) => { diff --git a/client/app/doctor/(pages)/appointments/[id]/page.tsx b/client/app/doctor/(pages)/appointments/[id]/page.tsx index 4764b9eb..e9f10725 100644 --- a/client/app/doctor/(pages)/appointments/[id]/page.tsx +++ b/client/app/doctor/(pages)/appointments/[id]/page.tsx @@ -1,324 +1,337 @@ -'use client' +"use client"; -import { useParams } from 'next/navigation' -import Image from 'next/image' -import { useGetAppointmentDetailsDoctor, useUpdateAppointmentStatusDoctor } from '@/lib/hooks/appointment/useAppointmentDoctor' -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' -import { Skeleton } from '@/components/ui/skeleton' -import { AppointmentStatus } from "@/types/enum" -import { toast } from '@/components/ui/use-toast' -import GetStatusBadge from '@/components/page-components/doctor/appointment/GetStatusBadge' -import AppointmentCancellationModal from '@/components/models/appointment/ConfirmCancelAppointmentDoctor' -import { Calendar, Clock, FileText, Video, User, Phone, AlertCircle, Pill } from 'lucide-react' -import { format } from 'date-fns' -import { useCallback, useState } from 'react' -import { ButtonV2, ButtonColorVariant } from '@/components/button/ButtonV2' -import { BreadcrumbCollapsed } from '@/components/navigation/BreadCrumbs' -import PrescriptionModel from '@/components/models/doctor/PrescriptionModel' -import { Separator } from '@/components/ui/separator' +import { useParams } from "next/navigation"; +import Image from "next/image"; +import { + useGetAppointmentDetailsDoctor, + useUpdateAppointmentStatusDoctor, +} from "@/lib/hooks/appointment/useAppointmentDoctor"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Skeleton } from "@/components/ui/skeleton"; +import { AppointmentStatus } from "@/types/enum"; +import { toast } from "@/components/ui/use-toast"; +import GetStatusBadge from "@/components/page-components/doctor/appointment/GetStatusBadge"; +import AppointmentCancellationModal from "@/components/models/appointment/ConfirmCancelAppointmentDoctor"; +import { Calendar, Clock, FileText, Video, User, Phone, AlertCircle, Pill } from "lucide-react"; +import { format } from "date-fns"; +import { useCallback, useState } from "react"; +import { ButtonV2, ButtonColorVariant } from "@/components/button/ButtonV2"; +import { BreadcrumbCollapsed } from "@/components/navigation/BreadCrumbs"; +import PrescriptionModel from "@/components/models/doctor/PrescriptionModel"; +import { Separator } from "@/components/ui/separator"; export default function AppointmentDetailsPage() { - const params = useParams(); - const appointmentId = params.id as string; - const [isCancelModelOpen, setCancelModelOpen] = useState(false); - const [isPrescriptionModelOpen, setPrescriptionModelOpen] = useState(false); - const { data: appointment, isLoading, error, refetch } = useGetAppointmentDetailsDoctor(appointmentId); - const { mutate: updateStatus, isPending } = useUpdateAppointmentStatusDoctor(); + const params = useParams(); + const appointmentId = params.id as string; + const [isCancelModelOpen, setCancelModelOpen] = useState(false); + const [isPrescriptionModelOpen, setPrescriptionModelOpen] = useState(false); + const { data: appointment, isLoading, error, refetch } = useGetAppointmentDetailsDoctor(appointmentId); + const { mutate: updateStatus, isPending } = useUpdateAppointmentStatusDoctor(); - const handleAcceptAppointment = useCallback(() => { - if (!appointmentId) return - updateStatus( - { appointmentId, status: AppointmentStatus.CONFIRMED }, - { - onSuccess: () => { - toast({ - title: "Appointment Confirmed", - description: "The appointment has been successfully confirmed.", - variant: "success", - }) - refetch() - }, - onError: (error) => { - toast({ - title: "Failed to Accept Appointment", - description: error?.response?.data?.message || "An error occurred. Please try again.", - variant: "destructive", - }) - }, - } - ) - }, [appointmentId, updateStatus, refetch]); + const handleAcceptAppointment = useCallback(() => { + if (!appointmentId) return; + updateStatus( + { appointmentId, status: AppointmentStatus.CONFIRMED }, + { + onSuccess: () => { + toast({ + title: "Appointment Confirmed", + description: "The appointment has been successfully confirmed.", + variant: "success", + }); + refetch(); + }, + onError: (error) => { + toast({ + title: "Failed to Accept Appointment", + description: error?.response?.data?.message || "An error occurred. Please try again.", + variant: "destructive", + }); + }, + } + ); + }, [appointmentId, updateStatus, refetch]); - const handleMarkComplete = useCallback(() => { - if (!appointmentId) return - updateStatus( - { appointmentId, status: AppointmentStatus.COMPLETED }, - { - onSuccess: () => { - toast({ - title: "Appointment Marked As Completed", - description: "The appointment has been been completed.", - variant: "success", - }) - refetch() - }, - onError: (error) => { - toast({ - title: "Failed to Mark Completed", - description: error?.response?.data?.message || "An error occurred. Please try again.", - variant: "destructive", - }) - }, - } - ) - }, [appointmentId, updateStatus, refetch]) + const handleMarkComplete = useCallback(() => { + if (!appointmentId) return; + updateStatus( + { appointmentId, status: AppointmentStatus.COMPLETED }, + { + onSuccess: () => { + toast({ + title: "Appointment Marked As Completed", + description: "The appointment has been been completed.", + variant: "success", + }); + refetch(); + }, + onError: (error) => { + toast({ + title: "Failed to Mark Completed", + description: error?.response?.data?.message || "An error occurred. Please try again.", + variant: "destructive", + }); + }, + } + ); + }, [appointmentId, updateStatus, refetch]); - const handleCancelAppointment = useCallback(async () => { - if (!appointmentId) return - updateStatus( - { appointmentId, status: AppointmentStatus.CANCELLED }, - { - onSuccess: () => { - toast({ - title: "Appointment Cancelled", - description: "The appointment has been cancelled.", - variant: "warning", - }) - setCancelModelOpen(false) - refetch() - }, - onError: (error) => { - toast({ - title: "Failed to Cancel Appointment", - description: error?.response?.data?.message || "An error occurred. Please try again.", - variant: "destructive", - }) - }, - } - ) - }, [appointmentId, updateStatus, refetch]); + const handleCancelAppointment = useCallback(async () => { + if (!appointmentId) return; + updateStatus( + { appointmentId, status: AppointmentStatus.CANCELLED }, + { + onSuccess: () => { + toast({ + title: "Appointment Cancelled", + description: "The appointment has been cancelled.", + variant: "warning", + }); + setCancelModelOpen(false); + refetch(); + }, + onError: (error) => { + toast({ + title: "Failed to Cancel Appointment", + description: error?.response?.data?.message || "An error occurred. Please try again.", + variant: "destructive", + }); + }, + } + ); + }, [appointmentId, updateStatus, refetch]); - const handlePrescriptionClick = useCallback(() => setPrescriptionModelOpen(true), []); - let nowDate = new Date() + const handlePrescriptionClick = useCallback(() => setPrescriptionModelOpen(true), []); + let nowDate = new Date(); - if (isLoading) { - return ( -
- - -
- ) - } - - if (error || !appointment) { - return ( -
-

Error loading appointment details. Please try again.

-
- ) - } - - return ( -
-
-

Appointment Details

-
- - {appointment.status === AppointmentStatus.PENDING ? ( - <> - - Accept - - setCancelModelOpen(true)}> - Reject - - - ) : ( - !appointment.prescription ? ( - - Prescription - - ) : ( - new Date(appointment.appointmentDate!) <= nowDate && appointment.status === AppointmentStatus.CONFIRMED && ( - - Mark As Completed - - ) - ) - )} - {appointment.status === AppointmentStatus.CONFIRMED && ( - setCancelModelOpen(true)}> - Cancel - - )} -
-
-
- -
+ if (isLoading) { + return ( +
+ + +
+ ); + } -
- - - - - Appointment Details - - - -
-
- - {format(new Date(appointment.appointmentDate!), "PPPP")} -
-
- - {appointment.slot?.startTime || "N/A"} - {appointment.slot?.endTime || "N/A"} -
-
- {appointment.appointmentType === "video-consulting" ? ( -
-
-
-

- - Reason for Appointment -

-

{appointment.reason}

-
-
-

- - Additional Notes -

-

{appointment.notes || "No additional notes provided"}

-
-
-
+ if (error || !appointment) { + return ( +
+

Error loading appointment details. Please try again.

+
+ ); + } - - - - - Patient Information - - - + return ( +
+
+

Appointment Details

-
- {appointment.patient?.name -
-
-

{appointment.patient?.name}

-

{appointment.patient?.email}

-
+ + {appointment.status === AppointmentStatus.PENDING ? ( + <> + + Accept + + setCancelModelOpen(true)}> + Reject + + + ) : !appointment.prescription ? ( + + Prescription + + ) : ( + new Date(appointment.appointmentDate!) <= nowDate && + appointment.status === AppointmentStatus.CONFIRMED && ( + + Mark As Completed + + ) + )} + {appointment.status === AppointmentStatus.CONFIRMED && ( + setCancelModelOpen(true)} + > + Cancel + + )}
-
-
- - {appointment.patient?.phone} -
-
- - {appointment.patient?.gender} -
-
- - Blood Group: {appointment.patient?.bloodGroup} -
-
- - +
+
+ +
- {appointment.prescription && ( - - - - - Prescription - - - - -
-
-

- - Medications -

- {appointment.prescription?.medications!.map((med, index) => ( -
-

{med.name}

-
-
- - Dosage: {med.dosage} -
-
- - Frequency: {med.frequency} -
-
- - Duration: {med.duration} -
-
- {med.additionalInstructions && med.additionalInstructions.length > 0 && ( -
- -

- Additional Instructions: {med.additionalInstructions} -

-
+
+ + + + + Appointment Details + + + +
+
+ + {format(new Date(appointment.appointmentDate!), "PPPP")} +
+
+ + + {appointment.slot?.startTime || "N/A"} - {appointment.slot?.endTime || "N/A"} + +
+
+ {appointment.appointmentType === "video-consulting" ? ( +
- ))} + {appointment.appointmentType!} +
+
+

+ + Reason for Appointment +

+

{appointment.reason}

+
+
+

+ + Additional Notes +

+

{appointment.notes || "No additional notes provided"}

+
+ + - {appointment.prescription.notes && ( - <> - -
-

- - Notes -

-
-

{appointment.prescription.notes}

-
-
- - )} -
- + + + + + Patient Information + + + +
+
+ {appointment.patient?.name +
+
+

{appointment.patient?.name}

+

{appointment.patient?.email}

+
+
+
+
+ + {appointment.patient?.phone} +
+
+ + {appointment.patient?.gender} +
+
+ + Blood Group: {appointment.patient?.bloodGroup} +
+
+
- - )} -
- + {appointment.prescription && ( + + + + + Prescription + + + + +
+
+

+ + Medications +

+ {appointment.prescription?.medications!.map((med, index) => ( +
+

{med.name}

+
+
+ + Dosage: {med.dosage} +
+
+ + Frequency: {med.frequency} +
+
+ + Duration: {med.duration} +
+
+ {med.additionalInstructions && med.additionalInstructions.length > 0 && ( +
+ +

+ Additional Instructions: {med.additionalInstructions} +

+
+ )} +
+ ))} +
+ + {appointment.prescription.notes && ( + <> + +
+

+ + Notes +

+
+

{appointment.prescription.notes}

+
+
+ + )} +
+
+
+
+ )} +
+ + - -
- ) -} \ No newline at end of file + +
+ ); +} diff --git a/client/app/doctor/(pages)/chats/@chat/[chatId]/page.tsx b/client/app/doctor/(pages)/chats/@chat/[chatId]/page.tsx index e2fd3116..5d76e5ff 100644 --- a/client/app/doctor/(pages)/chats/@chat/[chatId]/page.tsx +++ b/client/app/doctor/(pages)/chats/@chat/[chatId]/page.tsx @@ -1,51 +1,50 @@ -'use client' -import ChatSection from "@/components/page-components/chat/ChatSection" -import { toast } from "@/components/ui/use-toast" -import useMessages from "@/lib/hooks/useMessages" -import { useParams } from "next/navigation" -import { useEffect, useState } from "react" +"use client"; +import ChatSection from "@/components/page-components/chat/ChatSection"; +import { toast } from "@/components/ui/use-toast"; +import useMessages from "@/lib/hooks/useMessages"; +import { useParams } from "next/navigation"; +import { useEffect, useState } from "react"; const Page = () => { - const chatId = useParams().chatId as string; - const [isLoading, setLoading] = useState(true); - const { createMessage, error, messages, chat, markReceived } = useMessages({ role: "doctor", chatId }); + const chatId = useParams().chatId as string; + const [isLoading, setLoading] = useState(true); + const { createMessage, error, messages, chat, markReceived } = useMessages({ role: "doctor", chatId }); - useEffect(() => { - if (chat && messages) { - setLoading(false); - const filteredMessages = messages.filter(message => { - return message.receiverId === chat.doctorId && !message.isReceived - }); + useEffect(() => { + if (chat && messages) { + setLoading(false); + const filteredMessages = messages.filter((message) => { + return message.receiverId === chat.doctorId && !message.isReceived; + }); - if (filteredMessages.length > 0) { - markReceived(chatId, chat.doctorId!); + if (filteredMessages.length > 0) { + markReceived(chatId, chat.doctorId!); + } } - } - }, [messages, chat, chatId, markReceived]) + }, [messages, chat, chatId, markReceived]); - const handleSendMessage = async (newMessage: string) => { - createMessage(chatId, newMessage, chat?.patientId!) - if (error) { - toast({ - title: `Message sending failed ${error.statusCode && `with ${error.statusCode}`}`, - description: error.message || "Unknown error Occurred", - variant: "destructive" - }) - } - - } - return ( - - ); -} + const handleSendMessage = async (newMessage: string) => { + createMessage(chatId, newMessage, chat?.patientId!); + if (error) { + toast({ + title: `Message sending failed ${error.statusCode && `with ${error.statusCode}`}`, + description: error.message || "Unknown error Occurred", + variant: "destructive", + }); + } + }; + return ( + + ); +}; export default Page; diff --git a/client/app/doctor/(pages)/chats/@chat/default.tsx b/client/app/doctor/(pages)/chats/@chat/default.tsx index 9eb0bed9..58eefec6 100644 --- a/client/app/doctor/(pages)/chats/@chat/default.tsx +++ b/client/app/doctor/(pages)/chats/@chat/default.tsx @@ -1,18 +1,24 @@ -import { Card, CardContent } from "@/components/ui/card" -import Image from "next/image" +import { Card, CardContent } from "@/components/ui/card"; +import Image from "next/image"; export default function ChatDefault() { - return ( -
- - - Chat Default -

Welcome to Your Chat

-

- Select an existing conversation from the sidebar or start a new chat to begin messaging. -

-
-
-
- ) + return ( +
+ + + Chat Default +

Welcome to Your Chat

+

+ Select an existing conversation from the sidebar or start a new chat to begin messaging. +

+
+
+
+ ); } diff --git a/client/app/doctor/(pages)/chats/@chatList/default.tsx b/client/app/doctor/(pages)/chats/@chatList/default.tsx index 7e55743b..d76572ff 100644 --- a/client/app/doctor/(pages)/chats/@chatList/default.tsx +++ b/client/app/doctor/(pages)/chats/@chatList/default.tsx @@ -1,3 +1,3 @@ -import ChatList from './page'; -const Default = () => -export default Default \ No newline at end of file +import ChatList from "./page"; +const Default = () => ; +export default Default; diff --git a/client/app/doctor/(pages)/chats/@chatList/page.tsx b/client/app/doctor/(pages)/chats/@chatList/page.tsx index 9f7c2ef8..a3210ca9 100644 --- a/client/app/doctor/(pages)/chats/@chatList/page.tsx +++ b/client/app/doctor/(pages)/chats/@chatList/page.tsx @@ -1,67 +1,65 @@ -'use client' +"use client"; import { useEffect, useState } from "react"; import NewChatModal from "@/components/models/chat/AddChatModel"; -import ChatList from "@/components/page-components/chat/ChatList" +import ChatList from "@/components/page-components/chat/ChatList"; import useChats from "@/lib/hooks/useChats"; import { useRouter } from "next/navigation"; const Page = () => { - const [isNewChatModalOpen, setNewChatModalOpen] = useState(false); - const [isLoading, setLoading] = useState(true) - const { - chats, createChat, error, joinChatRoom, patients, getPatients - } = useChats({ role: "doctor", messagePath: "/doctor/chats" }) - const router = useRouter() + const [isNewChatModalOpen, setNewChatModalOpen] = useState(false); + const [isLoading, setLoading] = useState(true); + const { chats, createChat, error, joinChatRoom, patients, getPatients } = useChats({ + role: "doctor", + messagePath: "/doctor/chats", + }); + const router = useRouter(); - useEffect(() => { - if (chats && patients) { - setLoading(false) - } - }, [chats, patients]); + useEffect(() => { + if (chats && patients) { + setLoading(false); + } + }, [chats, patients]); - const handleJoinChat = (chatId: string) => { - joinChatRoom(chatId); - setTimeout(() => { - router.refresh(); - }, 0) - } + const handleJoinChat = (chatId: string) => { + joinChatRoom(chatId); + setTimeout(() => { + router.refresh(); + }, 0); + }; - const handleCloseModal = () => { - setNewChatModalOpen(false); - } + const handleCloseModal = () => { + setNewChatModalOpen(false); + }; - const handleAddDoctorChat = (patientId: string) => { - setNewChatModalOpen(false); - createChat(patientId); - } - - const handleClickNewChat = () => { - getPatients(); - setNewChatModalOpen(true); - } - - - return ( - <> - - {patients && ( - ({ _id, name, profilePicture: profile }))} - onSelectUser={handleAddDoctorChat} - /> - )} - - ) -} -export default Page + const handleAddDoctorChat = (patientId: string) => { + setNewChatModalOpen(false); + createChat(patientId); + }; + const handleClickNewChat = () => { + getPatients(); + setNewChatModalOpen(true); + }; + return ( + <> + + {patients && ( + ({ _id, name, profilePicture: profile }))} + onSelectUser={handleAddDoctorChat} + /> + )} + + ); +}; +export default Page; diff --git a/client/app/doctor/(pages)/chats/layout.tsx b/client/app/doctor/(pages)/chats/layout.tsx index e948ffa6..a6f53fe1 100644 --- a/client/app/doctor/(pages)/chats/layout.tsx +++ b/client/app/doctor/(pages)/chats/layout.tsx @@ -1,14 +1,14 @@ -import ChatLayout from "@/components/page-components/chat/ChatLayout" +import ChatLayout from "@/components/page-components/chat/ChatLayout"; import { Metadata } from "next"; -import { ReactNode } from "react" +import { ReactNode } from "react"; export const metadata: Metadata = { - title: 'Chat', - description: 'Chat with your patients, manage your chats seamlessly with AVM Ayurvedic', - keywords: ['chat', 'messages', 'AVM Ayurvedic', 'healthcare', 'doctor', 'patient'], + title: "Chat", + description: "Chat with your patients, manage your chats seamlessly with AVM Ayurvedic", + keywords: ["chat", "messages", "AVM Ayurvedic", "healthcare", "doctor", "patient"], }; const layout = ({ chatList, chat }: { chatList: ReactNode; chat: ReactNode }) => { - return -} + return ; +}; -export default layout \ No newline at end of file +export default layout; diff --git a/client/app/doctor/(pages)/patients/[patientId]/page.tsx b/client/app/doctor/(pages)/patients/[patientId]/page.tsx index 498f4aa8..d8e1c5d9 100644 --- a/client/app/doctor/(pages)/patients/[patientId]/page.tsx +++ b/client/app/doctor/(pages)/patients/[patientId]/page.tsx @@ -1,114 +1,115 @@ -'use client' +"use client"; -import { useGetMedicalHistory } from "@/lib/hooks/doctor/useDoctor" -import { useParams, useRouter } from "next/navigation" -import { useEffect, useState } from "react" -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" -import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" -import { Badge } from "@/components/ui/badge" -import { CalendarIcon, ClockIcon, FileTextIcon, PillIcon } from "lucide-react" -import { format } from "date-fns" -import Pagination from "@/components/navigation/Pagination" +import { useGetMedicalHistory } from "@/lib/hooks/doctor/useDoctor"; +import { useParams, useRouter } from "next/navigation"; +import { useEffect, useState } from "react"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; +import { Badge } from "@/components/ui/badge"; +import { CalendarIcon, ClockIcon, FileTextIcon, PillIcon } from "lucide-react"; +import { format } from "date-fns"; +import Pagination from "@/components/navigation/Pagination"; export default function Page({ searchParams }: { searchParams: { page: number } }) { - const page = +searchParams.page || 1; - const [currentPage, setCurrentPage] = useState(page); - const params = useParams(); - const router = useRouter() + const page = +searchParams.page || 1; + const [currentPage, setCurrentPage] = useState(page); + const params = useParams(); + const router = useRouter(); - const { data, refetch } = useGetMedicalHistory(params.patientId as string, page - 1, 10); + const { data, refetch } = useGetMedicalHistory(params.patientId as string, page - 1, 10); - const handlePageChange = (pageIndex: number) => { - if (pageIndex > data?.totalPages! || pageIndex < 1) return null; - setCurrentPage(pageIndex); - router.push(`/doctor/patients/${params.patientId}/medical-history?page=${pageIndex}`); - refetch(); - }; + const handlePageChange = (pageIndex: number) => { + if (pageIndex > data?.totalPages! || pageIndex < 1) return null; + setCurrentPage(pageIndex); + router.push(`/doctor/patients/${params.patientId}/medical-history?page=${pageIndex}`); + refetch(); + }; - useEffect(() => { - setCurrentPage(page); - }, [page]) + useEffect(() => { + setCurrentPage(page); + }, [page]); - return ( -
-

Medical History

- {data?.items&&data?.items.length>0?data?.items.map((item, index) => ( - - -
-
- - - {item.patient!.name?.charAt(0)} - -
- {item.patient!.name} - {item.patient!.email} -
-
- - {item.status} - + return ( +
+

Medical History

+ {data?.items && data?.items.length > 0 ? ( + data?.items.map((item, index) => ( + + +
+
+ + + {item.patient!.name?.charAt(0)} + +
+ {item.patient!.name} + {item.patient!.email} +
- - -
-
-
- - {format(new Date(item.appointmentDate!), 'PPP')} -
-
- - {item.appointmentType} -
-
-
-
- - Reason: {item.reason} -
-
- - Notes: {item.notes} -
-
+ {item.status} +
+ + +
+
+
+ + {format(new Date(item.appointmentDate!), "PPP")} +
+
+ + {item.appointmentType} +
- {item.prescription && ( -
-

Prescription

-
- {item.prescription.medications?.map((med, medIndex) => ( -
- -
- {med.name} - - {med.dosage}, {med.frequency}, {med.duration} - {med.additionalInstructions!.length > 0 && ( -

{med.additionalInstructions}

- )} -
-
- ))} -
-
- )} - - - )):( - - - Patient has no medical history yet - - - )} - -
- ) -} \ No newline at end of file +
+
+ + Reason: {item.reason} +
+
+ + Notes: {item.notes} +
+
+
+ {item.prescription && ( +
+

Prescription

+
+ {item.prescription.medications?.map((med, medIndex) => ( +
+ +
+ {med.name} + + {" "} + - {med.dosage}, {med.frequency}, {med.duration} + + {med.additionalInstructions!.length > 0 && ( +

{med.additionalInstructions}

+ )} +
+
+ ))} +
+
+ )} + +
+ )) + ) : ( + + Patient has no medical history yet + + )} + +
+ ); +} diff --git a/client/app/doctor/(pages)/patients/page.tsx b/client/app/doctor/(pages)/patients/page.tsx index f1a931f9..85ae4ba0 100644 --- a/client/app/doctor/(pages)/patients/page.tsx +++ b/client/app/doctor/(pages)/patients/page.tsx @@ -1,16 +1,14 @@ -import DoctorPatientsTable from "@/components/view/table/DoctorPatientsTable" -import { Metadata } from "next" +import DoctorPatientsTable from "@/components/view/table/DoctorPatientsTable"; +import { Metadata } from "next"; -export const metadata:Metadata = { - title:"Patients", - description:"Medical records of patient ", - keywords:"medical record, patients, appointments" -} +export const metadata: Metadata = { + title: "Patients", + description: "Medical records of patient ", + keywords: "medical record, patients, appointments", +}; const page = ({ searchParams }: { searchParams: { page: number } }) => { - const page = searchParams.page || 1; - return ( - - ) -} + const page = searchParams.page || 1; + return ; +}; -export default page \ No newline at end of file +export default page; diff --git a/client/app/doctor/(pages)/video-call/[sectionId]/page.tsx b/client/app/doctor/(pages)/video-call/[sectionId]/page.tsx index 8d1f5cc2..d5c17b19 100644 --- a/client/app/doctor/(pages)/video-call/[sectionId]/page.tsx +++ b/client/app/doctor/(pages)/video-call/[sectionId]/page.tsx @@ -1,46 +1,46 @@ -'use client' +"use client"; -import { useParams } from 'next/navigation'; -import JoinVideoCallPage from '@/components/page-components/video/JoinVideoCallPage'; -import VideoChat from '@/components/page-components/video/VideoChat'; -import { useGetSectionByIdDoctor } from '@/lib/hooks/video/useDoctor'; -import { useVideoCall } from '@/lib/hooks/useVideoCall'; +import { useParams } from "next/navigation"; +import JoinVideoCallPage from "@/components/page-components/video/JoinVideoCallPage"; +import VideoChat from "@/components/page-components/video/VideoChat"; +import { useGetSectionByIdDoctor } from "@/lib/hooks/video/useDoctor"; +import { useVideoCall } from "@/lib/hooks/useVideoCall"; export default function DoctorVideoCallPage() { - const { sectionId } = useParams(); - const { data, isLoading } = useGetSectionByIdDoctor(sectionId as string); - const section = data?.section; + const { sectionId } = useParams(); + const { data, isLoading } = useGetSectionByIdDoctor(sectionId as string); + const section = data?.section; - const { - hasJoined, - localStream, - remoteStream, - isMuted, - isVideoOff, - handleJoin, - handleEndCall, - toggleMute, - toggleVideo, - } = useVideoCall(section, 'doctor'); + const { + hasJoined, + localStream, + remoteStream, + isMuted, + isVideoOff, + handleJoin, + handleEndCall, + toggleMute, + toggleVideo, + } = useVideoCall(section, "doctor"); - if (isLoading) return
Loading...
; + if (isLoading) return
Loading...
; - if (!hasJoined) { - return ; - } + if (!hasJoined) { + return ; + } - return ( - - ); + return ( + + ); } diff --git a/client/app/doctor/(pages)/video-sections/page.tsx b/client/app/doctor/(pages)/video-sections/page.tsx index c5772d5d..6253747a 100644 --- a/client/app/doctor/(pages)/video-sections/page.tsx +++ b/client/app/doctor/(pages)/video-sections/page.tsx @@ -1,15 +1,13 @@ -import VideoSectionsTable from '@/components/view/table/DoctorVideoSectionsTable'; -import { Metadata } from 'next'; +import VideoSectionsTable from "@/components/view/table/DoctorVideoSectionsTable"; +import { Metadata } from "next"; -export const metadata:Metadata = { - title:"Video Sections", - keywords:["video call", 'video sections', 'doctor dashboard','ayurvedic'] -} +export const metadata: Metadata = { + title: "Video Sections", + keywords: ["video call", "video sections", "doctor dashboard", "ayurvedic"], +}; const Page = () => { - return ( - - ); + return ; }; export default Page; diff --git a/client/app/doctor/@auth/default.tsx b/client/app/doctor/@auth/default.tsx index 213f4944..61ae1582 100644 --- a/client/app/doctor/@auth/default.tsx +++ b/client/app/doctor/@auth/default.tsx @@ -1,2 +1,2 @@ -import Page from './page'; -export default Page; \ No newline at end of file +import Page from "./page"; +export default Page; diff --git a/client/app/doctor/layout.tsx b/client/app/doctor/layout.tsx index d4e471ed..955bd646 100644 --- a/client/app/doctor/layout.tsx +++ b/client/app/doctor/layout.tsx @@ -1,8 +1,7 @@ import { ReactNode, FC } from "react"; import { Metadata } from "next"; import Layout from "@/components/layout/DoctorLayout"; -import { metadata as rootMeta } from '@/app/layout'; - +import { metadata as rootMeta } from "@/app/layout"; interface AdminLayoutWrapperProps { children: ReactNode; diff --git a/client/app/doctor/not-found.tsx b/client/app/doctor/not-found.tsx index 09c9b50d..810297ac 100644 --- a/client/app/doctor/not-found.tsx +++ b/client/app/doctor/not-found.tsx @@ -4,7 +4,7 @@ import { Button } from "@/components/ui/button"; import useRedirect from "@/lib/hooks/useRedirect"; export default function NotFound() { - const redirect = useRedirect() + const redirect = useRedirect(); return (
diff --git a/client/app/layout.tsx b/client/app/layout.tsx index 2b44e267..4880cbcb 100644 --- a/client/app/layout.tsx +++ b/client/app/layout.tsx @@ -1,16 +1,17 @@ import type { Metadata } from "next"; import { ThemeProvider } from "@/lib/providers/ThemeProvider"; import { AuthProvider } from "@/lib/providers/auth-provider"; -import { SpeedInsights } from '@vercel/speed-insights/next'; +import { SpeedInsights } from "@vercel/speed-insights/next"; import QueryProvider from "@/lib/providers/query-provider"; import { Plus_Jakarta_Sans } from "next/font/google"; -import { Analytics } from "@vercel/analytics/react" +import { Analytics } from "@vercel/analytics/react"; import { Toaster } from "@/components/ui/toaster"; import NavBar from "@/components/layout/NavBar"; import Footer from "@/components/layout/Footer"; import { cn } from "@/lib/utils"; import "../styles/globals.css"; import "../styles/chart.css"; +import { MetaKeyWords } from "@/constants"; const inter = Plus_Jakarta_Sans({ subsets: ["latin"], @@ -18,10 +19,63 @@ const inter = Plus_Jakarta_Sans({ variable: "--font-sans", }); +export const metadata: Metadata = { + metadataBase: new URL("https://avm-ayurvedic.online"), + title: { + template: "%s | AVM Ayurvedic", + default: "AVM Ayurvedic - Holistic Ayurveda Health Care & Wellness", + }, + description: + "Experience authentic Ayurvedic treatments at AVM Ayurvedic Hospital. Book online appointments, access video consultations, and embrace holistic healing for a balanced life.", + openGraph: { + title: "AVM Ayurvedic - Holistic Ayurveda Health & Wellness", + description: + "Discover personalized Ayurvedic care with AVM Ayurvedic. Book consultations and experience the benefits of natural healing.", + type: "website", + url: "/", + siteName: "AVM Ayurvedic", + locale: "en_US", + images: [ + { + url: "/og-image.webp", + width: 1200, + height: 630, + alt: "AVM Ayurvedic - Holistic Ayurveda Health Care", + }, + ], + }, + twitter: { + card: "summary_large_image", + title: "AVM Ayurvedic - Holistic Health & Wellness", + description: + "Book Ayurvedic treatments & consultations online. Embrace natural healing and wellness through authentic Ayurveda.", + images: ["/og-image.webp"], + }, + robots: { + index: true, + follow: true, + googleBot: { + index: true, + follow: true, + "max-video-preview": -1, + "max-image-preview": "large", + "max-snippet": -1, + }, + }, + keywords: MetaKeyWords, + alternates: { + canonical: "/", + }, + icons: { + icon: "/favicon.ico", + apple: "/favicon.ico", + }, + category: "health", +}; export default function RootLayout({ children, - chatbot + chatbot, }: Readonly<{ children: React.ReactNode; chatbot: React.ReactNode; @@ -46,76 +100,3 @@ export default function RootLayout({ ); } - - - export const metadata: Metadata = { - metadataBase: new URL('https://avm-ayurvedic.online'), - title: { - template: '%s | AVM Ayurvedic', - default: 'AVM Ayurvedic - Holistic Ayurveda Health Care & Wellness', - }, - description: 'Experience authentic Ayurvedic treatments at AVM Ayurvedic Hospital. Book online appointments, access video consultations, and embrace holistic healing for a balanced life.', - openGraph: { - title: 'AVM Ayurvedic - Holistic Ayurveda Health & Wellness', - description: 'Discover personalized Ayurvedic care with AVM Ayurvedic. Book consultations and experience the benefits of natural healing.', - type: 'website', - url: '/', - siteName: 'AVM Ayurvedic', - locale: 'en_US', - images: [ - { - url: '/og-image.webp', - width: 1200, - height: 630, - alt: 'AVM Ayurvedic - Holistic Ayurveda Health Care', - }, - ], - }, - twitter: { - card: 'summary_large_image', - title: 'AVM Ayurvedic - Holistic Health & Wellness', - description: 'Book Ayurvedic treatments & consultations online. Embrace natural healing and wellness through authentic Ayurveda.', - images: ['/og-image.webp'], - }, - robots: { - index: true, - follow: true, - googleBot: { - index: true, - follow: true, - 'max-video-preview': -1, - 'max-image-preview': 'large', - 'max-snippet': -1, - }, - }, - keywords: [ - 'AVM Ayurvedic', - 'Ayurvedic hospital', - 'Ayurvedic treatments', - 'holistic healing', - 'online Ayurveda consultation', - 'natural medicine', - 'herbal remedies', - 'wellness center', - 'Ayurvedic doctors online', - 'Ayurvedic health care', - 'mental wellness', - 'immune support', - 'Ayurvedic lifestyle', - 'natural therapies', - 'online appointments', - 'virtual consultations', - 'herbal medicine', - 'AI Ayurvedic assistant', - 'wellness tips', - 'video consultations', - ], - alternates: { - canonical: '/', - }, - icons: { - icon: '/favicon.ico', - apple: '/favicon.ico', - }, - category: 'health', - } \ No newline at end of file diff --git a/client/app/not-found.tsx b/client/app/not-found.tsx index c0d8d6ac..c9e63bb7 100644 --- a/client/app/not-found.tsx +++ b/client/app/not-found.tsx @@ -13,7 +13,10 @@ export default function NotFound() {

404

Page Not Found

Oops! The page you're looking for doesn't exist.

- + Go Home
diff --git a/client/app/page.tsx b/client/app/page.tsx index 72a63939..519e9c8c 100644 --- a/client/app/page.tsx +++ b/client/app/page.tsx @@ -8,13 +8,12 @@ import LifestyleTips from "@/components/page-components/landing/home/LifeStyleTi import AyurvedicHerbs from "@/components/page-components/landing/home/Herbs"; import { memo } from "react"; import OurGoals from "@/components/page-components/landing/home/OurGoals"; -import { metadata as rootMeta } from './layout'; +import { metadata as rootMeta } from "./layout"; export const metadata: Metadata = { - ...rootMeta + ...rootMeta, }; - const HomePage = () => { return (
diff --git a/client/components/button/ButtonV2.tsx b/client/components/button/ButtonV2.tsx index 942e3eeb..03b319b8 100644 --- a/client/components/button/ButtonV2.tsx +++ b/client/components/button/ButtonV2.tsx @@ -41,7 +41,8 @@ const buttonVariants = cva( } ); -export const linkHover2 = "relative text-zinc-100 after:absolute after:bg-zinc-100 after:bottom-2 after:h-[1px] after:w-2/3 after:origin-bottom-left after:scale-x-100 hover:after:origin-bottom-right hover:after:scale-x-0 after:transition-transform after:ease-in-out after:duration-300" +export const linkHover2 = + "relative text-zinc-100 after:absolute after:bg-zinc-100 after:bottom-2 after:h-[1px] after:w-2/3 after:origin-bottom-left after:scale-x-100 hover:after:origin-bottom-right hover:after:scale-x-0 after:transition-transform after:ease-in-out after:duration-300"; type ButtonVariantProps = VariantProps; @@ -74,9 +75,7 @@ interface IconRefProps { iconPlacement?: undefined; } -export interface ButtonProps - extends React.ButtonHTMLAttributes, - ButtonVariantProps { +export interface ButtonProps extends React.ButtonHTMLAttributes, ButtonVariantProps { asChild?: boolean; color?: ButtonColorVariant | string; } @@ -100,7 +99,7 @@ const colorVariants: Record = { cyan: "bg-cyan-700 text-white hover:bg-cyan-600", lime: "bg-lime-700 text-white hover:bg-lime-600", emerald: "bg-emerald-700 text-white hover:bg-emerald-600", - link:"text-green-500 underline-offset-4 " + link: "text-green-500 underline-offset-4 ", }; const ButtonV2 = React.forwardRef( @@ -114,14 +113,7 @@ const ButtonV2 = React.forwardRef + {Icon && iconPlacement === "left" && (
@@ -139,4 +131,4 @@ const ButtonV2 = React.forwardRef { - const handleDownload = useCallback(async () => { - try { - const blob = await pdf( - - ).toBlob(); - const url = URL.createObjectURL(blob); - const link = document.createElement('a'); - link.href = url; - link.download = `Prescription_${prescription._id}.pdf`; - link.click(); - URL.revokeObjectURL(url); - } catch (error) { - console.error('Error generating PDF:', error); - } - }, [prescription, doctor, patient]); + const handleDownload = useCallback(async () => { + try { + const blob = await pdf( + + ).toBlob(); + const url = URL.createObjectURL(blob); + const link = document.createElement("a"); + link.href = url; + link.download = `Prescription_${prescription._id}.pdf`; + link.click(); + URL.revokeObjectURL(url); + } catch (error) { + console.error("Error generating PDF:", error); + } + }, [prescription, doctor, patient]); - return ( - - Download Prescription - - ); + return ( + + Download Prescription + + ); }; - -export default memo(DownloadPrescriptionButton); \ No newline at end of file +export default memo(DownloadPrescriptionButton); diff --git a/client/components/button/NotificationButtonDoctor.tsx b/client/components/button/NotificationButtonDoctor.tsx index 3574f4bb..219f7e41 100644 --- a/client/components/button/NotificationButtonDoctor.tsx +++ b/client/components/button/NotificationButtonDoctor.tsx @@ -8,60 +8,57 @@ import useNotification from "@/lib/hooks/useNotification"; const NotificationModal = dynamic(() => import("@/components/models/NotificationModel"), { ssr: false }); const NotificationButtonDoctor = forwardRef((props, ref) => { - const [isNotificationModalOpen, setIsNotificationModalOpen] = useState(false); - const { notifications, clearAllNotifications, clearNotification } = useNotification({ role: "doctor" }); + const [isNotificationModalOpen, setIsNotificationModalOpen] = useState(false); + const { notifications, clearAllNotifications, clearNotification } = useNotification({ role: "doctor" }); - const notificationCount = notifications.length; + const notificationCount = notifications.length; - const handleNotificationClick = useCallback(() => { - setIsNotificationModalOpen(true); - }, []); + const handleNotificationClick = useCallback(() => { + setIsNotificationModalOpen(true); + }, []); - const handleClearSingleNotification = useCallback((notificationId: string) => { - clearNotification(notificationId); - }, [ clearNotification]); + const handleClearSingleNotification = useCallback( + (notificationId: string) => { + clearNotification(notificationId); + }, + [clearNotification] + ); - const handleClearAllNotifications = useCallback(() => { - if (!notifications || notifications.length === 0) return; + const handleClearAllNotifications = useCallback(() => { + if (!notifications || notifications.length === 0) return; - const notificationIds = notifications.map((notification) => notification._id!); - clearAllNotifications(notificationIds); - }, [notifications,clearAllNotifications]); + const notificationIds = notifications.map((notification) => notification._id!); + clearAllNotifications(notificationIds); + }, [notifications, clearAllNotifications]); - return ( - <> - - - {notificationCount > 0 && ( - - {notificationCount} - - )} - View notifications - + return ( + <> + + + {notificationCount > 0 && ( + + {notificationCount} + + )} + View notifications + - {isNotificationModalOpen && ( - - )} - - ); + {isNotificationModalOpen && ( + + )} + + ); }); NotificationButtonDoctor.displayName = "NotificationButtonDoctor"; diff --git a/client/components/button/NotificationButtonPatient.tsx b/client/components/button/NotificationButtonPatient.tsx index 4fa69a2f..78e7b974 100644 --- a/client/components/button/NotificationButtonPatient.tsx +++ b/client/components/button/NotificationButtonPatient.tsx @@ -12,51 +12,54 @@ import { useAuth } from "@/lib/hooks/useAuth"; const NotificationModal = dynamic(() => import("@/components/models/NotificationModel"), { ssr: false }); const NotificationButtonPatient = () => { - const [isNotificationModalOpen, setIsNotificationModalOpen] = useState(false); - const { patientToken } = useAuth(); - const { notifications, clearAllNotifications, clearNotification } = useNotification({ role: "patient" }); - - const notificationCount = notifications.length; - - const handleNotificationClick = useCallback(() => { - setIsNotificationModalOpen(true); - }, []); - - const handleClearSingleNotification = useCallback((notificationId: string) => { - clearNotification(notificationId); - }, [clearNotification]); - - const handleClearAllNotifications = useCallback(() => { - if (!notifications || notifications.length === 0) return; - const notificationsIds = notifications.map(el => el._id!); - clearAllNotifications(notificationsIds); - }, [notifications, clearAllNotifications]); - - return ( - <> - - - {notificationCount > 0 && ( - - {notificationCount} - - )} - View notifications - - - - ); + const [isNotificationModalOpen, setIsNotificationModalOpen] = useState(false); + const { patientToken } = useAuth(); + const { notifications, clearAllNotifications, clearNotification } = useNotification({ role: "patient" }); + + const notificationCount = notifications.length; + + const handleNotificationClick = useCallback(() => { + setIsNotificationModalOpen(true); + }, []); + + const handleClearSingleNotification = useCallback( + (notificationId: string) => { + clearNotification(notificationId); + }, + [clearNotification] + ); + + const handleClearAllNotifications = useCallback(() => { + if (!notifications || notifications.length === 0) return; + const notificationsIds = notifications.map((el) => el._id!); + clearAllNotifications(notificationsIds); + }, [notifications, clearAllNotifications]); + + return ( + <> + + + {notificationCount > 0 && ( + + {notificationCount} + + )} + View notifications + + + + ); }; export default memo(NotificationButtonPatient); diff --git a/client/components/button/VideoSectionButtonDoctor.tsx b/client/components/button/VideoSectionButtonDoctor.tsx index 274bb0e3..a184be0e 100644 --- a/client/components/button/VideoSectionButtonDoctor.tsx +++ b/client/components/button/VideoSectionButtonDoctor.tsx @@ -1,50 +1,50 @@ -'use client'; +"use client"; -import React, { forwardRef, memo, useState } from 'react'; -import { ButtonV2 } from './ButtonV2'; -import Image from 'next/image'; -import { Badge } from '@/components/ui/badge'; -import VideoSectionsModel from '@/components/models/VideoSectionsModel'; -import { useGetSectionsInOneDayDoctor } from '@/lib/hooks/video/useDoctor'; +import React, { forwardRef, memo, useState } from "react"; +import { ButtonV2 } from "./ButtonV2"; +import Image from "next/image"; +import { Badge } from "@/components/ui/badge"; +import VideoSectionsModel from "@/components/models/VideoSectionsModel"; +import { useGetSectionsInOneDayDoctor } from "@/lib/hooks/video/useDoctor"; const VideoSectionButtonDoctor = forwardRef((props, ref) => { - const { data: upcomingSections } = useGetSectionsInOneDayDoctor(); - const [isModalOpen, setIsModalOpen] = useState(false); - const handleClick = () => { - setIsModalOpen(true); - }; + const { data: upcomingSections } = useGetSectionsInOneDayDoctor(); + const [isModalOpen, setIsModalOpen] = useState(false); + const handleClick = () => { + setIsModalOpen(true); + }; - return ( - <> - - Video Calls - {upcomingSections && upcomingSections!.length > 0 && ( - - {upcomingSections!.length} - - )} - View Upcoming Video Calls - - 0 ? upcomingSections : []} - link="/doctor/video-call" - user="doctor" + return ( + <> + + Video Calls - - ); + {upcomingSections && upcomingSections!.length > 0 && ( + + {upcomingSections!.length} + + )} + View Upcoming Video Calls + + 0 ? upcomingSections : []} + link="/doctor/video-call" + user="doctor" + /> + + ); }); -VideoSectionButtonDoctor.displayName = 'VideoSectionButtonDoctor'; +VideoSectionButtonDoctor.displayName = "VideoSectionButtonDoctor"; export default memo(VideoSectionButtonDoctor); diff --git a/client/components/button/VideoSectionButtonPatient.tsx b/client/components/button/VideoSectionButtonPatient.tsx index 052db4d2..b2f0a423 100644 --- a/client/components/button/VideoSectionButtonPatient.tsx +++ b/client/components/button/VideoSectionButtonPatient.tsx @@ -1,47 +1,47 @@ -'use client'; +"use client"; -import React, { memo, useState } from 'react'; -import { ButtonV2 } from './ButtonV2'; -import Image from 'next/image'; -import { Badge } from '@/components/ui/badge' -import { useGetSectionsInOneDayPatient } from '@/lib/hooks/video/usePatient'; -import VideoSectionsModel from '@/components/models/VideoSectionsModel' +import React, { memo, useState } from "react"; +import { ButtonV2 } from "./ButtonV2"; +import Image from "next/image"; +import { Badge } from "@/components/ui/badge"; +import { useGetSectionsInOneDayPatient } from "@/lib/hooks/video/usePatient"; +import VideoSectionsModel from "@/components/models/VideoSectionsModel"; const VideoSectionButtonPatient = () => { - const { data: upcomingSections } = useGetSectionsInOneDayPatient(); - const [isModalOpen, setIsModalOpen] = useState(false); - const handleClick = () => { - setIsModalOpen(true); - } - return ( - <> - - Video Calls - {upcomingSections && upcomingSections!.length > 0 && ( - - {upcomingSections!.length} - - )} - View Upcoming Video Calls - - 0 ? upcomingSections : []} - link="/video-section" - user='patient' - /> - - ) -} + const { data: upcomingSections } = useGetSectionsInOneDayPatient(); + const [isModalOpen, setIsModalOpen] = useState(false); + const handleClick = () => { + setIsModalOpen(true); + }; + return ( + <> + + Video Calls + {upcomingSections && upcomingSections!.length > 0 && ( + + {upcomingSections!.length} + + )} + View Upcoming Video Calls + + 0 ? upcomingSections : []} + link="/video-section" + user="patient" + /> + + ); +}; -export default memo(VideoSectionButtonPatient) \ No newline at end of file +export default memo(VideoSectionButtonPatient); diff --git a/client/components/common/AnimatedCard.tsx b/client/components/common/AnimatedCard.tsx index dc154094..041a1bda 100644 --- a/client/components/common/AnimatedCard.tsx +++ b/client/components/common/AnimatedCard.tsx @@ -1,7 +1,7 @@ "use client"; import Image from "next/image"; -import {memo} from "react"; +import { memo } from "react"; import { CardBody, CardContainer, CardItem } from "@/components/ui/3d-card"; import { AnimatedCardProps } from "@/types"; import Link from "next/link"; diff --git a/client/components/common/OtpForms.tsx b/client/components/common/OtpForms.tsx index dad07066..b880b463 100644 --- a/client/components/common/OtpForms.tsx +++ b/client/components/common/OtpForms.tsx @@ -8,7 +8,6 @@ import { PopoverContent, PopoverTrigger, Popover } from "@/components/ui/popover import { ButtonV2 } from "@/components/button/ButtonV2"; import Image from "next/image"; - export interface Props { handleVerify: (e: FormEvent) => void; handleResend: () => void; @@ -18,51 +17,39 @@ export interface Props { setOtp: (value: string) => void; } -export default function OtpVerificationSection({ - handleVerify, - handleResend, - timer, - isLoading, - otp, - setOtp, -}: Props) { +export default function OtpVerificationSection({ handleVerify, handleResend, timer, isLoading, otp, setOtp }: Props) { return ( -
handleVerify(e) }> + handleVerify(e)}>

OTP Verification

Please enter the OTP sent to your registered Email Address.

- setOtp(value) } className="mb-6"> + setOtp(value)} className="mb-6"> - - - - - - + + + + + +
- +
- Verify OTP + Verify OTP - Dummy user + Dummy user

Tester Credentials:

-

otp: { 777777 }

- setOtp('777777') }> +

otp: {777777}

+ setOtp("777777")}> Fill Credentials
diff --git a/client/components/forms/admin/SigninForm.tsx b/client/components/forms/admin/SigninForm.tsx index 1ba9d495..bfa7ef55 100644 --- a/client/components/forms/admin/SigninForm.tsx +++ b/client/components/forms/admin/SigninForm.tsx @@ -87,7 +87,7 @@ const AdminSigninForm = () => { Dummy user { ); }; -export default AdminSigninForm; \ No newline at end of file +export default AdminSigninForm; diff --git a/client/components/forms/doctor/SigninForm.tsx b/client/components/forms/doctor/SigninForm.tsx index f2e14dd9..6cd7f703 100644 --- a/client/components/forms/doctor/SigninForm.tsx +++ b/client/components/forms/doctor/SigninForm.tsx @@ -112,30 +112,30 @@ const AdminSigninForm = () => {
- Sign In - - - - Dummy user - - - -
-

Tester Credentials:

-

Email: {dummyEmail}

-

Password: {dummyPassword}

- - Fill Credentials + Sign In + + + + Dummy user -
-
-
-
+
+ +
+

Tester Credentials:

+

Email: {dummyEmail}

+

Password: {dummyPassword}

+ + Fill Credentials + +
+
+
+
diff --git a/client/components/forms/doctor/SignupForm.tsx b/client/components/forms/doctor/SignupForm.tsx index daadb617..f15d791f 100644 --- a/client/components/forms/doctor/SignupForm.tsx +++ b/client/components/forms/doctor/SignupForm.tsx @@ -19,7 +19,7 @@ import { Input } from "@/components/ui/input"; import { getPresignedUrlDoctor } from "@/lib/api/doctor/authenticationRoutes"; import axios from "axios"; import { DoctorDegrees } from "@/constants"; -import { MultiSelect } from "@/components/ui/multi-select" +import { MultiSelect } from "@/components/ui/multi-select"; const ALLOWED_FILE_TYPES = ["image/jpeg", "image/png"]; const MAX_FILE_SIZE = 5 * 1024 * 1024; @@ -289,7 +289,7 @@ const SignUpForm = () => { Qualifications * ({ label: degree, value: degree }))} + options={DoctorDegrees.map((degree) => ({ label: degree, value: degree }))} placeholder="Select qualifications" className="w-full" {...field} diff --git a/client/components/forms/patient/AppointmentForm.tsx b/client/components/forms/patient/AppointmentForm.tsx index 14161ecc..a77f5ed5 100644 --- a/client/components/forms/patient/AppointmentForm.tsx +++ b/client/components/forms/patient/AppointmentForm.tsx @@ -95,34 +95,33 @@ const AppointmentForm = () => { if (status === 403 || status === 401) { toast({ title: "Appointment Creation Failed โŒ", - description: 'This action is only allowed for verified users. ๐Ÿ˜Š', + description: "This action is only allowed for verified users. ๐Ÿ˜Š", variant: "destructive", action: ( signin ), - }) - return + }); + return; } - if(message==='Profile is missing'){ + if (message === "Profile is missing") { toast({ title: "Appointment Creation Failed โŒ", description: "Please upload your personal information and try again", variant: "destructive", action: ( - + register ), - }) - return + }); + return; } toast({ title: "Appointment Creation Failed โŒ", description: message, variant: "destructive", - }); }, } @@ -136,7 +135,12 @@ const AppointmentForm = () => {

New Appointment

Request New Appointment in 10 seconds

- +
{/* Appointment Date Field */} @@ -223,10 +227,11 @@ const AppointmentForm = () => { key={slot._id} variant="gooeyRight" onClick={() => form.setValue("slotId", slot._id!, { shouldValidate: true })} - className={`w-full justify-center py-1 px-2 text-xs font-medium transition-all duration-200 border ${field.value === slot._id + className={`w-full justify-center py-1 px-2 text-xs font-medium transition-all duration-200 border ${ + field.value === slot._id ? "bg-primary text-primary-foreground border-primary shadow-md scale-105" : "bg-gray-700 text-gray-200 border-gray-600" - }`} + }`} > {slot.startTime} - {slot.endTime}
diff --git a/client/components/forms/patient/SigninForm.tsx b/client/components/forms/patient/SigninForm.tsx index f61eb807..ff0a2566 100644 --- a/client/components/forms/patient/SigninForm.tsx +++ b/client/components/forms/patient/SigninForm.tsx @@ -19,7 +19,6 @@ import { PopoverContent, PopoverTrigger, Popover } from "@/components/ui/popover import { ButtonV2 } from "@/components/button/ButtonV2"; import Image from "next/image"; - const LoginForm = () => { const [error, setError] = useState(""); const { toast } = useToast(); @@ -37,7 +36,7 @@ const LoginForm = () => { password: "", }, }); - + const onSubmit = async ({ email, password }: z.infer) => { signIn( { email, password }, @@ -62,11 +61,11 @@ const LoginForm = () => { } ); }; - - const setDummyData = () => { - form.setValue("email", dummyEmail); - form.setValue("password", dummyPassword); - }; + + const setDummyData = () => { + form.setValue("email", dummyEmail); + form.setValue("password", dummyPassword); + }; return (
@@ -112,7 +111,7 @@ const LoginForm = () => { Dummy user - AVM + AVM {sideBarLinks.map((item) => ( @@ -166,7 +160,7 @@ const AdminLayoutWithSideBar = ({ AVM diff --git a/client/components/layout/DoctorLayout.tsx b/client/components/layout/DoctorLayout.tsx index 7a42e1df..4e9eaa43 100644 --- a/client/components/layout/DoctorLayout.tsx +++ b/client/components/layout/DoctorLayout.tsx @@ -1,63 +1,59 @@ -'use client' +"use client"; -import DoctorLayoutWithSideBar from "@/components/layout/DoctorLayoutWithSideBar" -import UniversalSkelton from "@/components/skeletons/Universal" -import { DoctorsSidebarLinks } from "@/constants" -import { useAuth } from "@/lib/hooks/useAuth" -import { usePathname, useRouter } from "next/navigation" -import { ReactNode, useEffect, useState } from "react" +import DoctorLayoutWithSideBar from "@/components/layout/DoctorLayoutWithSideBar"; +import UniversalSkelton from "@/components/skeletons/Universal"; +import { DoctorsSidebarLinks } from "@/constants"; +import { useAuth } from "@/lib/hooks/useAuth"; +import { usePathname, useRouter } from "next/navigation"; +import { ReactNode, useEffect, useState } from "react"; type Props = { - children: ReactNode - auth: ReactNode -} + children: ReactNode; + auth: ReactNode; +}; export default function Layout({ children, auth }: Props) { - const { doctorToken } = useAuth() - const [isLoading, setLoading] = useState(true) - const path = usePathname() - const router = useRouter() - const isChat = path.includes("/chats") + const { doctorToken } = useAuth(); + const [isLoading, setLoading] = useState(true); + const path = usePathname(); + const router = useRouter(); + const isChat = path.includes("/chats"); useEffect(() => { if ( doctorToken && (path.includes("/otp-verification") || path.includes("/signup") || path.includes("/reset-password")) ) { - router.replace("/doctor") + router.replace("/doctor"); } - }, [doctorToken, path, router]) + }, [doctorToken, path, router]); useEffect(() => { const timer = setTimeout(() => { - setLoading(false) - }, 0) - return () => clearTimeout(timer) - }, []) + setLoading(false); + }, 0); + return () => clearTimeout(timer); + }, []); if (isLoading) { - return + return ; } return ( <> {doctorToken ? ( -
-
- {children} -
+
{children}
) : ( auth )} - ) -} \ No newline at end of file + ); +} diff --git a/client/components/layout/DoctorLayoutWithSideBar.tsx b/client/components/layout/DoctorLayoutWithSideBar.tsx index 2fa909f0..87b70eb5 100644 --- a/client/components/layout/DoctorLayoutWithSideBar.tsx +++ b/client/components/layout/DoctorLayoutWithSideBar.tsx @@ -1,4 +1,4 @@ -'use client'; +"use client"; import { ReactNode, useState, useCallback } from "react"; import Image from "next/image"; @@ -9,12 +9,12 @@ import { PanelLeft } from "lucide-react"; import { Button } from "@/components/ui/button"; import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuLabel, - DropdownMenuTrigger, - DropdownMenuSeparator, + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuTrigger, + DropdownMenuSeparator, } from "@/components/ui/dropdown-menu"; import { NavLinkType } from "@/types"; import { Sheet, SheetContent, SheetTitle, SheetTrigger } from "@/components/ui/sheet"; @@ -29,247 +29,232 @@ import VideoSectionButtonDoctor from "../button/VideoSectionButtonDoctor"; import useRedirect from "@/lib/hooks/useRedirect"; const AdminLayoutWithSideBar = ({ - children, - sideBarLinks, + children, + sideBarLinks, }: { - children: ReactNode[] | ReactNode; - sideBarLinks: NavLinkType[]; + children: ReactNode[] | ReactNode; + sideBarLinks: NavLinkType[]; }) => { - const pathname = usePathname(); - const [open, setOpen] = useState(false); - const [isLogoutOpen, setLogoutOpen] = useState(false); - const { mutate: logout } = useLogoutDoctor(); - const { setCredentials } = useAuth(); - const redirect = useRedirect(); + const pathname = usePathname(); + const [open, setOpen] = useState(false); + const [isLogoutOpen, setLogoutOpen] = useState(false); + const { mutate: logout } = useLogoutDoctor(); + const { setCredentials } = useAuth(); + const redirect = useRedirect(); - const isVideoCall = pathname.includes("/video-call/"); + const isVideoCall = pathname.includes("/video-call/"); - const handleLogout = useCallback(() => { - logout( - {}, - { - onSuccess: () => { - toast({ - title: "Logout Successfully๐Ÿ‘‹", - variant: "success", - }); - setCredentials("doctorToken", ""); - redirect("/doctor"); - }, - onError: (error) => { - toast({ - title: "Logout Failed โŒ", - description: error.response?.data.message || "An Unknown Error Occurred", - variant: "destructive", - }); - }, - } - ); - }, [logout, setCredentials, redirect]); + const handleLogout = useCallback(() => { + logout( + {}, + { + onSuccess: () => { + toast({ + title: "Logout Successfully๐Ÿ‘‹", + variant: "success", + }); + setCredentials("doctorToken", ""); + redirect("/doctor"); + }, + onError: (error) => { + toast({ + title: "Logout Failed โŒ", + description: error.response?.data.message || "An Unknown Error Occurred", + variant: "destructive", + }); + }, + } + ); + }, [logout, setCredentials, redirect]); - const toggleLogoutModal = useCallback(() => { - setLogoutOpen((prev) => !prev); - }, []); + const toggleLogoutModal = useCallback(() => { + setLogoutOpen((prev) => !prev); + }, []); - const renderSidebarLink = useCallback((item: NavLinkType) => ( - - - - {item.label} - {item.label} - - - - {item.label} - - - ), [pathname]); - - return ( -
- - - -
-
- - - - - - Navigation Menu - - - +
+ + + + + + Video Sections + + + + + + + + Notifications + + + + + + + + + + + Settings + + + + + + + + +
+ + +
+
+ + + + + + Navigation Menu + + + + + +
+
+
+ + + + + + + + + {/* My Account */} - Logout - - -
-
- {children} + Logout + + +
+
+ {children} +
+
- -
- ); + ); }; -export default AdminLayoutWithSideBar; \ No newline at end of file +export default AdminLayoutWithSideBar; diff --git a/client/components/layout/Footer.tsx b/client/components/layout/Footer.tsx index da86cbb6..99885276 100644 --- a/client/components/layout/Footer.tsx +++ b/client/components/layout/Footer.tsx @@ -28,13 +28,7 @@ const Footer = () => {
- AVM + AVM AVM Ayurvedic

Holistic Ayurveda Health Care for your well-being.

@@ -42,10 +36,26 @@ const Footer = () => {

Quick Links

    -
  • Home
  • -
  • About Us
  • -
  • Services
  • -
  • Contact
  • +
  • + + Home + +
  • +
  • + + About Us + +
  • +
  • + + Services + +
  • +
  • + + Contact + +
@@ -57,7 +67,7 @@ const Footer = () => {
  • - + Video Consultation
  • @@ -76,9 +86,12 @@ const Footer = () => {

    Connect With Us

    - + linkedin { Github { WhatsApp { instagram { ); }; -export default Footer; \ No newline at end of file +export default Footer; diff --git a/client/components/layout/NavBar.tsx b/client/components/layout/NavBar.tsx index c7656e72..e3fb272a 100644 --- a/client/components/layout/NavBar.tsx +++ b/client/components/layout/NavBar.tsx @@ -5,25 +5,20 @@ import Link from "next/link"; import Image from "next/image"; import { usePathname, useRouter } from "next/navigation"; import { toast } from "@/components/ui/use-toast"; -import { - Sheet, - SheetTrigger, - SheetContent, - SheetTitle, -} from "@/components/ui/sheet"; +import { Sheet, SheetTrigger, SheetContent, SheetTitle } from "@/components/ui/sheet"; import { Button } from "@/components/ui/button"; import { - DropdownMenu, - DropdownMenuTrigger, - DropdownMenuContent, - DropdownMenuLabel, - DropdownMenuSeparator, - DropdownMenuItem, - DropdownMenuSub, - DropdownMenuSubTrigger, - DropdownMenuSubContent, - DropdownMenuRadioGroup, - DropdownMenuRadioItem, + DropdownMenu, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuItem, + DropdownMenuSub, + DropdownMenuSubTrigger, + DropdownMenuSubContent, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, } from "@/components/ui/dropdown-menu"; import { NavLinks } from "@/constants"; import { useAuth } from "@/lib/hooks/useAuth"; @@ -35,204 +30,209 @@ import NotificationButtonPatient from "../button/NotificationButtonPatient"; import VideoSectionButtonPatient from "../button/VideoSectionButtonPatient"; export const NavBar = () => { - const path = usePathname(); - const redirect = useRedirect(); - const { mutate: logoutFunc } = useLogoutMutation(); - const { patientToken, setCredentials, logout } = useAuth(); - const [isLogoutModelOpen, setLogoutModelOpen] = useState(false); - const [isSheetOpen, setIsSheetOpen] = useState(false); - const [currentRole, setCurrentRole] = useState("patient"); - const isAuthorized = !!patientToken; - - const shouldRenderNavBar = !path.includes("signup") && !path.includes("admin") && !path.includes("signin") && !path.includes("doctor"); + const path = usePathname(); + const redirect = useRedirect(); + const { mutate: logoutFunc } = useLogoutMutation(); + const { patientToken, setCredentials, logout } = useAuth(); + const [isLogoutModelOpen, setLogoutModelOpen] = useState(false); + const [isSheetOpen, setIsSheetOpen] = useState(false); + const [currentRole, setCurrentRole] = useState("patient"); + const isAuthorized = !!patientToken; - const handleLogoutClick = () => { - setLogoutModelOpen(true); - }; + const shouldRenderNavBar = + !path.includes("signup") && !path.includes("admin") && !path.includes("signin") && !path.includes("doctor"); - useEffect(() => { - if (!path.includes('/admin') && !path.includes("/doctor")) { - setCurrentRole("patient"); - } - }, [path, setCurrentRole]); + const handleLogoutClick = () => { + setLogoutModelOpen(true); + }; - const handleLogoutConfirm = useCallback(() => { - try { - logoutFunc(null, { - onSuccess: () => { - toast({ - title: "Logout Successful", - description: "We hope to see you again soon!", - variant: "info", - }); - setCredentials("patientToken", ""); - redirect("/"); - }, - onError: () => { - toast({ - title: "Logout Failed", - description: "An error occurred during logout. Please try again.", - variant: "destructive", - }); - logout("patientToken"); - }, - }); - setLogoutModelOpen(false); - } catch (error) { - console.log(error); - } - }, [logoutFunc, redirect, setCredentials, logout]); + useEffect(() => { + if (!path.includes("/admin") && !path.includes("/doctor")) { + setCurrentRole("patient"); + } + }, [path, setCurrentRole]); - const handleLinkHome = useCallback(() => { - setIsSheetOpen(false); - }, []); + const handleLogoutConfirm = useCallback(() => { + try { + logoutFunc(null, { + onSuccess: () => { + toast({ + title: "Logout Successful", + description: "We hope to see you again soon!", + variant: "info", + }); + setCredentials("patientToken", ""); + redirect("/"); + }, + onError: () => { + toast({ + title: "Logout Failed", + description: "An error occurred during logout. Please try again.", + variant: "destructive", + }); + logout("patientToken"); + }, + }); + setLogoutModelOpen(false); + } catch (error) { + console.log(error); + } + }, [logoutFunc, redirect, setCredentials, logout]); - const handleLinkClick = useCallback((link: string) => { - redirect(link); - setIsSheetOpen(false); - }, [redirect]); + const handleLinkHome = useCallback(() => { + setIsSheetOpen(false); + }, []); - const handleRoleChange = (role: string) => { - setCurrentRole(role); - toast({ - title: "Role Changed", - description: `You are now viewing as ${role}`, - variant: "info", - }); - const roleRoutes: Record = { - admin: "/admin/dashboard", - doctor: "/doctor/slots", - patient: "/", - }; - redirect(roleRoutes[role]); - }; + const handleLinkClick = useCallback( + (link: string) => { + redirect(link); + setIsSheetOpen(false); + }, + [redirect] + ); - if (!shouldRenderNavBar) return null; + const handleRoleChange = (role: string) => { + setCurrentRole(role); + toast({ + title: "Role Changed", + description: `You are now viewing as ${role}`, + variant: "info", + }); + const roleRoutes: Record = { + admin: "/admin/dashboard", + doctor: "/doctor/slots", + patient: "/", + }; + redirect(roleRoutes[role]); + }; - return ( -
    - + if (!shouldRenderNavBar) return null; - - - - - - - Navigation Menu - - + + + + + + + + Navigation Menu + + + + -
    - - - - - - Avatar - Toggle user menu - - - - {isAuthorized ? ( - <> - redirect('/profile')}> - My Account - - redirect('/appointments')}> - Appointments - - - - - Role: {currentRole} - - - - Patient - Doctor - Admin - - - - - - Logout - - - ) : ( - <> - - - Role: {currentRole} - - - - Patient - Doctor - Admin - - - - - redirect("/signin")}> - Sign In - - - )} - - +
    + + + + + + Avatar + Toggle user menu + + + + {isAuthorized ? ( + <> + redirect("/profile")}> + My Account + + redirect("/appointments")}> + Appointments + + + + Role: {currentRole} + + + Patient + Doctor + Admin + + + + + + Logout + + + ) : ( + <> + + Role: {currentRole} + + + Patient + Doctor + Admin + + + + + redirect("/signin")}> + Sign In + + + )} + + - -
    -
    - ); + +
    + + ); }; export default NavBar; diff --git a/client/components/models/NotificationModel.tsx b/client/components/models/NotificationModel.tsx index d1fc0bb3..43ba048f 100644 --- a/client/components/models/NotificationModel.tsx +++ b/client/components/models/NotificationModel.tsx @@ -1,142 +1,156 @@ -'use client' +"use client"; -import { Dispatch, SetStateAction } from "react" -import Image from "next/image" -import Link from "next/link" -import { XIcon, Trash2Icon } from "lucide-react" +import { Dispatch, SetStateAction } from "react"; +import Image from "next/image"; +import Link from "next/link"; +import { XIcon, Trash2Icon } from "lucide-react"; import { - AlertDialog, - AlertDialogContent, - AlertDialogDescription, - AlertDialogFooter, - AlertDialogHeader, - AlertDialogTitle, -} from "@/components/ui/alert-dialog" -import { Card, CardContent } from "@/components/ui/card" -import { ScrollArea } from "@/components/ui/scroll-area" -import { ButtonV2 } from "@/components/button/ButtonV2" -import { INotification } from "@/types/entities" -import getNotificationDetails from "@/lib/utils/getNotificationDetails" + AlertDialog, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, +} from "@/components/ui/alert-dialog"; +import { Card, CardContent } from "@/components/ui/card"; +import { ScrollArea } from "@/components/ui/scroll-area"; +import { ButtonV2 } from "@/components/button/ButtonV2"; +import { INotification } from "@/types/entities"; +import getNotificationDetails from "@/lib/utils/getNotificationDetails"; type Props = { - open: boolean - setOpen: Dispatch> - notifications: INotification[] - isUnauthorized: boolean - handleClearSingleNotification: (notificationId: string) => void - handleClearAllNotifications: () => void - link: string -} + open: boolean; + setOpen: Dispatch>; + notifications: INotification[]; + isUnauthorized: boolean; + handleClearSingleNotification: (notificationId: string) => void; + handleClearAllNotifications: () => void; + link: string; +}; export default function NotificationModal({ - open, - setOpen, - notifications, - isUnauthorized, - handleClearSingleNotification, - handleClearAllNotifications, - link + open, + setOpen, + notifications, + isUnauthorized, + handleClearSingleNotification, + handleClearAllNotifications, + link, }: Props) { - const closeModal = () => { - setOpen(false) - } + const closeModal = () => { + setOpen(false); + }; + + return ( + + + + + Notifications + + + + + + Your notifications - return ( - - - - - Notifications - - - - - - Your notifications - - {isUnauthorized ? ( -
    - Unauthorized -

    - You are not authorized to view these notifications. -

    -
    - ) : notifications.length > 0 ? ( - -
    - {notifications.map((notification) => { - const { icon, title } = getNotificationDetails(notification.type!) - return ( - - - -
    - {title} -
    -

    {title}

    -

    {notification.message}

    -
    -
    - { - e.stopPropagation() - e.preventDefault() - handleClearSingleNotification(notification._id!) - }} - iconPlacement="left" - Icon={Trash2Icon} - className="text-muted-foreground hover:text-primary" - aria-label="Clear notification" - > - Clear - -
    -
    - - ) - })} -
    -
    - ) : ( -
    - No Notifications -

    - You're all caught up! No new notifications. -

    -
    - )} - - -
    - {notifications.length > 1 && ( - - Clear All - + {isUnauthorized ? ( +
    + Unauthorized +

    + You are not authorized to view these notifications. +

    +
    + ) : notifications.length > 0 ? ( + +
    + {notifications.map((notification) => { + const { icon, title } = getNotificationDetails(notification.type!); + return ( + + + +
    + {title} +
    +

    {title}

    +

    + {notification.message} +

    +
    +
    + { + e.stopPropagation(); + e.preventDefault(); + handleClearSingleNotification(notification._id!); + }} + iconPlacement="left" + Icon={Trash2Icon} + className="text-muted-foreground hover:text-primary" + aria-label="Clear notification" + > + Clear + +
    +
    + + ); + })} +
    +
    + ) : ( +
    + No Notifications +

    + You're all caught up! No new notifications. +

    +
    )} - Close -
    -
    -
    -
    - ) -} \ No newline at end of file + + +
    + {notifications.length > 1 && ( + + Clear All + + )} + + Close + +
    +
    +
    +
    + ); +} diff --git a/client/components/models/VideoSectionsModel.tsx b/client/components/models/VideoSectionsModel.tsx index 92f4f8ff..a0873da7 100644 --- a/client/components/models/VideoSectionsModel.tsx +++ b/client/components/models/VideoSectionsModel.tsx @@ -1,112 +1,112 @@ -'use client' +"use client"; -import { Dispatch, SetStateAction } from "react" -import Image from "next/image" -import Link from "next/link" -import { XIcon, Video } from "lucide-react" +import { Dispatch, SetStateAction } from "react"; +import Image from "next/image"; +import Link from "next/link"; +import { XIcon, Video } from "lucide-react"; import { - AlertDialog, - AlertDialogContent, - AlertDialogDescription, - AlertDialogFooter, - AlertDialogHeader, - AlertDialogTitle, -} from "@/components/ui/alert-dialog" -import { Card, CardContent } from "@/components/ui/card" -import { ScrollArea } from "@/components/ui/scroll-area" -import { ButtonV2 } from "@/components/button/ButtonV2" -import { IVideoSection } from "@/types/entities" -import { format } from "date-fns" + AlertDialog, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, +} from "@/components/ui/alert-dialog"; +import { Card, CardContent } from "@/components/ui/card"; +import { ScrollArea } from "@/components/ui/scroll-area"; +import { ButtonV2 } from "@/components/button/ButtonV2"; +import { IVideoSection } from "@/types/entities"; +import { format } from "date-fns"; type Props = { - open: boolean - setOpen: Dispatch> - sections: IVideoSection[] - link: string - user: "patient" | "doctor" -} + open: boolean; + setOpen: Dispatch>; + sections: IVideoSection[]; + link: string; + user: "patient" | "doctor"; +}; -export default function VideoCallModal({ - open, - setOpen, - sections, - link, - user -}: Props) { - const closeModal = () => { - setOpen(false) - } +export default function VideoCallModal({ open, setOpen, sections, link, user }: Props) { + const closeModal = () => { + setOpen(false); + }; - return ( - - - - - Upcoming Online Appointments - - Close - - - - List of upcoming online appointments + return ( + + + + + Upcoming Online Appointments + + Close + + + + List of upcoming online appointments - {sections.length > 0 ? ( - -
    - {sections.map((section) => ( - - - -
    -
    - - Join - -
    -
    - - ))} -
    -
    - ) : ( -
    - No Upcoming Appointments -

    - No upcoming video appointments in the next hour. -

    -
    - )} + {sections.length > 0 ? ( + +
    + {sections.map((section) => ( + + + +
    +
    + + Join + +
    +
    + + ))} +
    +
    + ) : ( +
    + No Upcoming Appointments +

    + No upcoming video appointments in the next hour. +

    +
    + )} - -
    - Close -
    -
    -
    -
    - ) -} \ No newline at end of file + +
    + + Close + +
    +
    +
    +
    + ); +} diff --git a/client/components/models/admin/PatientProfileModel.tsx b/client/components/models/admin/PatientProfileModel.tsx index 15b79c09..eff05659 100644 --- a/client/components/models/admin/PatientProfileModel.tsx +++ b/client/components/models/admin/PatientProfileModel.tsx @@ -46,7 +46,7 @@ const AdminPatientProfileModel = ({ open, setOpen, patient, refetch }: Props) => toast({ title: "Error in Updating Patient Status", description: error.response?.data.message || "Unknown Error Occurred", - variant:"destructive" + variant: "destructive", }); }, } diff --git a/client/components/models/appointment/ConfirmCancelAppointmentDoctor.tsx b/client/components/models/appointment/ConfirmCancelAppointmentDoctor.tsx index 42bf1a84..fe5ed5ec 100644 --- a/client/components/models/appointment/ConfirmCancelAppointmentDoctor.tsx +++ b/client/components/models/appointment/ConfirmCancelAppointmentDoctor.tsx @@ -18,7 +18,7 @@ interface Props { handleCancelAppointment: () => void; } -const AppointmentCancellationModal = ({ open, setOpen, handleCancelAppointment }: Props) =>{ +const AppointmentCancellationModal = ({ open, setOpen, handleCancelAppointment }: Props) => { return ( @@ -58,6 +58,6 @@ const AppointmentCancellationModal = ({ open, setOpen, handleCancelAppointment ); -} +}; -export default memo(AppointmentCancellationModal) \ No newline at end of file +export default memo(AppointmentCancellationModal); diff --git a/client/components/models/chat/AddChatModel.tsx b/client/components/models/chat/AddChatModel.tsx index 7d66a7e4..fc564694 100644 --- a/client/components/models/chat/AddChatModel.tsx +++ b/client/components/models/chat/AddChatModel.tsx @@ -1,48 +1,48 @@ -import { useState } from 'react' -import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog" -import { ScrollArea } from "@/components/ui/scroll-area" -import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" -import { Button } from "@/components/ui/button" +import { useState } from "react"; +import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog"; +import { ScrollArea } from "@/components/ui/scroll-area"; +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; +import { Button } from "@/components/ui/button"; export interface ChatModelUser { - _id?: string; - name?: string; - profilePicture?: string; + _id?: string; + name?: string; + profilePicture?: string; } interface NewChatModalProps { - isOpen: boolean; - onClose: () => void; - users: ChatModelUser[]; - onSelectUser: (userId: string) => void; + isOpen: boolean; + onClose: () => void; + users: ChatModelUser[]; + onSelectUser: (userId: string) => void; } export default function NewChatModal({ isOpen, onClose, users, onSelectUser }: NewChatModalProps) { - return ( - - - - Start a New Chat - - -
    - {users.map((user) => ( - - ))} -
    -
    -
    -
    - ) -} \ No newline at end of file + return ( + + + + Start a New Chat + + +
    + {users.map((user) => ( + + ))} +
    +
    +
    +
    + ); +} diff --git a/client/components/models/doctor/PrescriptionModel.tsx b/client/components/models/doctor/PrescriptionModel.tsx index c4758408..82e199aa 100644 --- a/client/components/models/doctor/PrescriptionModel.tsx +++ b/client/components/models/doctor/PrescriptionModel.tsx @@ -1,153 +1,156 @@ -'use client' +"use client"; -import { ButtonV2 } from "@/components/button/ButtonV2" -import { AlertDialog, AlertDialogHeader, AlertDialogContent, AlertDialogTitle } from "@/components/ui/alert-dialog" -import { AlertDialogDescription } from "@radix-ui/react-alert-dialog" -import Image from "next/image" -import { Dispatch, memo, SetStateAction, useCallback } from "react" -import { VisuallyHidden } from "@radix-ui/react-visually-hidden" -import { Form } from "@/components/ui/form" -import { useForm } from "react-hook-form" -import { z } from "zod" -import { zodResolver } from "@hookform/resolvers/zod" -import { FormFieldType } from "@/types/enum" -import { PlusIcon } from "lucide-react" -import CustomFormField from "@/components/common/CustomFormField" -import { ScrollArea } from "@/components/ui/scroll-area" -import { prescriptionSchema } from "@/lib/form-schema/doctorSchema" -import SubmitButton from "@/components/button/SubmitButton" -import { useCreatePrescription } from "@/lib/hooks/prescription/usePrescription" -import { toast } from "@/components/ui/use-toast" +import { ButtonV2 } from "@/components/button/ButtonV2"; +import { AlertDialog, AlertDialogHeader, AlertDialogContent, AlertDialogTitle } from "@/components/ui/alert-dialog"; +import { AlertDialogDescription } from "@radix-ui/react-alert-dialog"; +import Image from "next/image"; +import { Dispatch, memo, SetStateAction, useCallback } from "react"; +import { VisuallyHidden } from "@radix-ui/react-visually-hidden"; +import { Form } from "@/components/ui/form"; +import { useForm } from "react-hook-form"; +import { z } from "zod"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { FormFieldType } from "@/types/enum"; +import { PlusIcon } from "lucide-react"; +import CustomFormField from "@/components/common/CustomFormField"; +import { ScrollArea } from "@/components/ui/scroll-area"; +import { prescriptionSchema } from "@/lib/form-schema/doctorSchema"; +import SubmitButton from "@/components/button/SubmitButton"; +import { useCreatePrescription } from "@/lib/hooks/prescription/usePrescription"; +import { toast } from "@/components/ui/use-toast"; type Props = { - isOpen: boolean; - setOpen: Dispatch>; - appointmentId: string; - patientId: string; - refetch: any; -} + isOpen: boolean; + setOpen: Dispatch>; + appointmentId: string; + patientId: string; + refetch: any; +}; -type PrescriptionFormValues = z.infer +type PrescriptionFormValues = z.infer; const PrescriptionModal = ({ isOpen, setOpen, appointmentId, patientId, refetch }: Props) => { - const closeModal = useCallback(() => setOpen(false), [setOpen]); - const { mutate: create, isPending } = useCreatePrescription() + const closeModal = useCallback(() => setOpen(false), [setOpen]); + const { mutate: create, isPending } = useCreatePrescription(); - const form = useForm({ - resolver: zodResolver(prescriptionSchema), - defaultValues: { - medications: [{ name: '', dosage: '', frequency: '', duration: '', additionalInstructions: '' }], - notes: '', - }, - }) + const form = useForm({ + resolver: zodResolver(prescriptionSchema), + defaultValues: { + medications: [{ name: "", dosage: "", frequency: "", duration: "", additionalInstructions: "" }], + notes: "", + }, + }); - const onSubmit = (data: PrescriptionFormValues) => { - create( - { prescription: { ...data, patientId, appointmentId } }, - { - onError: (error) => { - toast({ - title: "Error in creating Prescription", - description: error.response?.data.message || "Unknown error Occurred", - variant: "destructive" - }) - }, - onSuccess: ({message}) => { - toast({ - title: "Prescription creation successful", - variant: "success" - }) - closeModal(); - refetch(); - } + const onSubmit = (data: PrescriptionFormValues) => { + create( + { prescription: { ...data, patientId, appointmentId } }, + { + onError: (error) => { + toast({ + title: "Error in creating Prescription", + description: error.response?.data.message || "Unknown error Occurred", + variant: "destructive", + }); }, - ); - } + onSuccess: ({ message }) => { + toast({ + title: "Prescription creation successful", + variant: "success", + }); + closeModal(); + refetch(); + }, + } + ); + }; - return ( - - - - - Add Prescription - - Close + return ( + + + + + Add Prescription + + Close + + + + +
    +
    + + {form.watch("medications").map((_, index) => ( +
    + + + + + +
    + ))} + + form.setValue("medications", [ + ...form.watch("medications"), + { name: "", dosage: "", frequency: "", duration: "", additionalInstructions: "" }, + ]) + } + className="flex items-center" + > + Add Another Medication - - - -
    - - - {form.watch('medications').map((_, index) => ( -
    - - - - - -
    - ))} - form.setValue('medications', [...form.watch('medications'), { name: '', dosage: '', frequency: '', duration: '', additionalInstructions: '' }])} - className="flex items-center" - > - Add Another Medication - - - - Save Prescription - - - -
    -
    - - - - - - ) -} + + Save Prescription + + +
    +
    + + + +
    +
    + ); +}; -export default memo(PrescriptionModal) \ No newline at end of file +export default memo(PrescriptionModal); diff --git a/client/components/models/patient/UpdateProfilePatient.tsx b/client/components/models/patient/UpdateProfilePatient.tsx index c3095783..242b3182 100644 --- a/client/components/models/patient/UpdateProfilePatient.tsx +++ b/client/components/models/patient/UpdateProfilePatient.tsx @@ -1,9 +1,15 @@ "use client"; import { Dispatch, SetStateAction } from "react"; import Image from "next/image"; -import { AlertDialog, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription } from "@/components/ui/alert-dialog"; +import { + AlertDialog, + AlertDialogContent, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogDescription, +} from "@/components/ui/alert-dialog"; import { updateProfileFormSchema } from "@/lib/form-schema/patientSchema"; -import { VisuallyHidden } from "@radix-ui/react-visually-hidden" +import { VisuallyHidden } from "@radix-ui/react-visually-hidden"; import { Form, FormControl } from "../../ui/form"; import { useForm } from "react-hook-form"; import { z } from "zod"; diff --git a/client/components/models/patient/UploadProfileModel.tsx b/client/components/models/patient/UploadProfileModel.tsx index a88e2b98..51284def 100644 --- a/client/components/models/patient/UploadProfileModel.tsx +++ b/client/components/models/patient/UploadProfileModel.tsx @@ -2,7 +2,13 @@ import { Dispatch, SetStateAction, useState } from "react"; import Image from "next/image"; -import { AlertDialog, AlertDialogContent, AlertDialogDescription, AlertDialogHeader, AlertDialogTitle } from "@/components/ui/alert-dialog"; +import { + AlertDialog, + AlertDialogContent, + AlertDialogDescription, + AlertDialogHeader, + AlertDialogTitle, +} from "@/components/ui/alert-dialog"; import { Form, FormLabel } from "../../ui/form"; import { useForm, SubmitHandler } from "react-hook-form"; import { z } from "zod"; @@ -16,8 +22,7 @@ import CropImage from "@/components/common/CropImage"; import useCrop from "@/lib/hooks/useCrop"; import axios from "axios"; import { getUpdateProfileUrl, updateProfileImage } from "@/lib/api/patient/authorizedRoutes"; -import { VisuallyHidden } from "@radix-ui/react-visually-hidden" - +import { VisuallyHidden } from "@radix-ui/react-visually-hidden"; type Props = { open: boolean; diff --git a/client/components/navigation/BreadCrumbs.tsx b/client/components/navigation/BreadCrumbs.tsx index cbbb8f20..dc5d3ace 100644 --- a/client/components/navigation/BreadCrumbs.tsx +++ b/client/components/navigation/BreadCrumbs.tsx @@ -1,36 +1,36 @@ -import Link from "next/link" +import Link from "next/link"; import { - Breadcrumb, - BreadcrumbItem, - BreadcrumbLink, - BreadcrumbList, - BreadcrumbSeparator, -} from "@/components/ui/breadcrumb" -import { Fragment } from "react" + Breadcrumb, + BreadcrumbItem, + BreadcrumbLink, + BreadcrumbList, + BreadcrumbSeparator, +} from "@/components/ui/breadcrumb"; +import { Fragment } from "react"; interface BreadcrumbCollapsedProps { - items: { - href: string - label: string - }[] + items: { + href: string; + label: string; + }[]; } export function BreadcrumbCollapsed({ items }: BreadcrumbCollapsedProps) { - return ( - - - {items.map((item, index) => ( - - - - {item.label} - - - {index < items.length - 1 && } - - ))} - - - ) + return ( + + + {items.map((item, index) => ( + + + + {item.label} + + + {index < items.length - 1 && } + + ))} + + + ); } diff --git a/client/components/navigation/Pagination.tsx b/client/components/navigation/Pagination.tsx index 4bb31412..e2505323 100644 --- a/client/components/navigation/Pagination.tsx +++ b/client/components/navigation/Pagination.tsx @@ -17,12 +17,7 @@ type Props = { hasNextPage: boolean; }; -export default function Pagination({ - currentPage, - handlePageChange, - totalPages, - className, -}: Props) { +export default function Pagination({ currentPage, handlePageChange, totalPages, className }: Props) { if (totalPages <= 1) return null; const getPageRange = () => { diff --git a/client/components/page-components/chat/ChatLayout.tsx b/client/components/page-components/chat/ChatLayout.tsx index 7bdc85f9..1ee87ef4 100644 --- a/client/components/page-components/chat/ChatLayout.tsx +++ b/client/components/page-components/chat/ChatLayout.tsx @@ -1,72 +1,71 @@ -'use client' +"use client"; -import { ReactNode, useEffect, useState } from 'react' -import { usePathname } from 'next/navigation' -import { useAuth } from '@/lib/hooks/useAuth' -import ChatLayoutSkeleton from '@/components/skeletons/ChatSkelton' -import NotAuthenticated from './NotAuthenticated' +import { ReactNode, useEffect, useState } from "react"; +import { usePathname } from "next/navigation"; +import { useAuth } from "@/lib/hooks/useAuth"; +import ChatLayoutSkeleton from "@/components/skeletons/ChatSkelton"; +import NotAuthenticated from "./NotAuthenticated"; export default function ChatLayout({ - chatList, - chat, - isPatient + chatList, + chat, + isPatient, }: { - chatList: ReactNode - chat: ReactNode - isPatient: boolean + chatList: ReactNode; + chat: ReactNode; + isPatient: boolean; }) { - const pathname = usePathname(); - const [isLoading, setLoading] = useState(true); - const [isInChatView, setIsInChatView] = useState(false) - const { patientToken } = useAuth(); + const pathname = usePathname(); + const [isLoading, setLoading] = useState(true); + const [isInChatView, setIsInChatView] = useState(false); + const { patientToken } = useAuth(); - useEffect(() => { - setIsInChatView(pathname.includes('/chats/')) - }, [pathname]) + useEffect(() => { + setIsInChatView(pathname.includes("/chats/")); + }, [pathname]); - useEffect(() => { - if (isPatient) { - const timer = setTimeout(() => { - setLoading(false) - }, 0) - return () => clearTimeout(timer) - } else { - setLoading(false) - } - }, [isPatient]); + useEffect(() => { + if (isPatient) { + const timer = setTimeout(() => { + setLoading(false); + }, 0); + return () => clearTimeout(timer); + } else { + setLoading(false); + } + }, [isPatient]); + if (isLoading) { + return ; + } - if (isLoading) { - return - } + if (isPatient && !!!patientToken) { + return ; + } - if (isPatient && !!!patientToken) { - return - } - - return ( -
    - -
    - {chat || ( -
    -
    -

    Welcome to Your Messages

    -

    - Select a chat to start messaging or create a new one. -

    -
    -
    - )} -
    -
    - ) -} \ No newline at end of file + +
    + {chat || ( +
    +
    +

    Welcome to Your Messages

    +

    + Select a chat to start messaging or create a new one. +

    +
    +
    + )} +
    +
    + ); +} diff --git a/client/components/page-components/chat/ChatList.tsx b/client/components/page-components/chat/ChatList.tsx index d9d1e94e..119b8fa1 100644 --- a/client/components/page-components/chat/ChatList.tsx +++ b/client/components/page-components/chat/ChatList.tsx @@ -1,67 +1,74 @@ -'use client' +"use client"; -import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" -import { ScrollArea } from "@/components/ui/scroll-area" -import { PlusCircle } from "lucide-react" -import { IChat } from "@/types/entities" -import { getSenderData } from './getUserData' -import ChatListSkeleton from "@/components/skeletons/ChatList" -import { ButtonV2 } from "@/components/button/ButtonV2" +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; +import { ScrollArea } from "@/components/ui/scroll-area"; +import { PlusCircle } from "lucide-react"; +import { IChat } from "@/types/entities"; +import { getSenderData } from "./getUserData"; +import ChatListSkeleton from "@/components/skeletons/ChatList"; +import { ButtonV2 } from "@/components/button/ButtonV2"; interface ChatListProps { - chats: IChat[]; - onSelectChat: (id: string) => void; - onNewChat: () => void; - isLoading: boolean; - sender: "doctor" | "patient"; - skeltonCount: number; + chats: IChat[]; + onSelectChat: (id: string) => void; + onNewChat: () => void; + isLoading: boolean; + sender: "doctor" | "patient"; + skeltonCount: number; } export default function ChatList({ chats, onSelectChat, onNewChat, isLoading, sender, skeltonCount }: ChatListProps) { - - return ( -
    -
    - - - New Chat - + return ( +
    +
    + + + New Chat + +
    + +
    + {isLoading ? ( + + ) : ( + chats.map(({ _id, doctorName, patientName, doctorProfile, patientProfile, notSeenMessages }, i) => ( +
    onSelectChat(_id!)} + > + + + + {getSenderData(sender, doctorName!, patientName!)?.charAt(0)} + + +
    +
    +

    + {getSenderData(sender, doctorName!, patientName!)} +

    + {notSeenMessages! > 0 && ( + + {notSeenMessages} + + )} +
    +
    +
    + )) + )} +
    +
    + {!isLoading && chats.length === 0 && ( +
    No chats found
    + )}
    - -
    - {isLoading ? ( - - ) : ( - chats.map(({ _id, doctorName, patientName, doctorProfile, patientProfile, notSeenMessages }, i) => ( -
    onSelectChat(_id!)} - > - - - {getSenderData(sender, doctorName!, patientName!)?.charAt(0)} - -
    -
    -

    {getSenderData(sender, doctorName!, patientName!)}

    - {notSeenMessages! > 0 && ( - - {notSeenMessages} - - )} -
    -
    -
    - )) - )} -
    -
    - {!isLoading && chats.length === 0 && ( -
    - No chats found -
    - )} -
    - ) -} \ No newline at end of file + ); +} diff --git a/client/components/page-components/chat/ChatSection.tsx b/client/components/page-components/chat/ChatSection.tsx index 9dbc8185..f83d64d7 100644 --- a/client/components/page-components/chat/ChatSection.tsx +++ b/client/components/page-components/chat/ChatSection.tsx @@ -1,169 +1,174 @@ -"use client" +"use client"; -import { useRef, useEffect, useState } from "react" -import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" -import { Input } from "@/components/ui/input" -import { ArrowLeft, Send, AlertCircle, Smile } from "lucide-react" -import { IChat, IMessage } from "@/types/entities" -import { useRouter } from "next/navigation" -import Spinner from "@/components/skeletons/Spinner"; -import { getSenderData } from "./getUserData" -import dynamic from 'next/dynamic' -import { EmojiClickData, Theme } from 'emoji-picker-react' -import { ButtonV2 } from "@/components/button/ButtonV2" -import Messages from "./Messages" -import { useQueryClient } from "@tanstack/react-query" +import { useRef, useEffect, useState } from "react"; +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; +import { Input } from "@/components/ui/input"; +import { ArrowLeft, Send, AlertCircle, Smile } from "lucide-react"; +import { IChat, IMessage } from "@/types/entities"; +import { useRouter } from "next/navigation"; +import Spinner from "@/components/skeletons/Spinner"; +import { getSenderData } from "./getUserData"; +import dynamic from "next/dynamic"; +import { EmojiClickData, Theme } from "emoji-picker-react"; +import { ButtonV2 } from "@/components/button/ButtonV2"; +import Messages from "./Messages"; +import { useQueryClient } from "@tanstack/react-query"; -const EmojiPicker = dynamic(() => import('emoji-picker-react'), { ssr: false }) +const EmojiPicker = dynamic(() => import("emoji-picker-react"), { ssr: false }); interface ChatSectionProps { - sender: "doctor" | "patient" - messages: IMessage[] - onSendMessage: (message: string) => void - isError: boolean - isPending: boolean - isLoading: boolean - chat: IChat - error?: string + sender: "doctor" | "patient"; + messages: IMessage[]; + onSendMessage: (message: string) => void; + isError: boolean; + isPending: boolean; + isLoading: boolean; + chat: IChat; + error?: string; } export default function ChatSection({ - messages, - onSendMessage, - sender, - error, - isError, - isLoading, - chat, - isPending, + messages, + onSendMessage, + sender, + error, + isError, + isLoading, + chat, + isPending, }: ChatSectionProps) { - const [message, setMessage] = useState("") - const [showEmojiPicker, setShowEmojiPicker] = useState(false) - const router = useRouter() - const scrollAreaRef = useRef(null); - const emojiButtonRef = useRef(null); - const emojiPickerRef = useRef(null); - const query = useQueryClient(); + const [message, setMessage] = useState(""); + const [showEmojiPicker, setShowEmojiPicker] = useState(false); + const router = useRouter(); + const scrollAreaRef = useRef(null); + const emojiButtonRef = useRef(null); + const emojiPickerRef = useRef(null); + const query = useQueryClient(); - const handleSendMessage = () => { - if (message.trim()) { - onSendMessage(message) - setMessage("") - setShowEmojiPicker(false) - query.invalidateQueries({ queryKey: ['messages', chat._id] }) - } - } - - const handleEmojiClick = (emojiData: EmojiClickData) => { - setMessage((prevMessage) => prevMessage + emojiData.emoji) - } + const handleSendMessage = () => { + if (message.trim()) { + onSendMessage(message); + setMessage(""); + setShowEmojiPicker(false); + query.invalidateQueries({ queryKey: ["messages", chat._id] }); + } + }; - useEffect(() => { - if (scrollAreaRef.current) { - scrollAreaRef.current.scrollTop = scrollAreaRef.current.scrollHeight - } - }, [messages]) + const handleEmojiClick = (emojiData: EmojiClickData) => { + setMessage((prevMessage) => prevMessage + emojiData.emoji); + }; - useEffect(() => { - const handleClickOutside = (event: MouseEvent) => { - if ( - emojiButtonRef.current && - !emojiButtonRef.current.contains(event.target as Node) && - emojiPickerRef.current && - !emojiPickerRef.current.contains(event.target as Node) - ) { - setShowEmojiPicker(false) + useEffect(() => { + if (scrollAreaRef.current) { + scrollAreaRef.current.scrollTop = scrollAreaRef.current.scrollHeight; } - } + }, [messages]); - document.addEventListener('mousedown', handleClickOutside) - return () => { - document.removeEventListener('mousedown', handleClickOutside) - } - }, []); + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if ( + emojiButtonRef.current && + !emojiButtonRef.current.contains(event.target as Node) && + emojiPickerRef.current && + !emojiPickerRef.current.contains(event.target as Node) + ) { + setShowEmojiPicker(false); + } + }; - const handleBackClick = ()=>{ - router.back() - router.refresh(); - } + document.addEventListener("mousedown", handleClickOutside); + return () => { + document.removeEventListener("mousedown", handleClickOutside); + }; + }, []); - if (isLoading) { - return ( -
    - -
    - ) - } + const handleBackClick = () => { + router.back(); + router.refresh(); + }; - if (isError) { - return ( -
    -
    - -

    Error loading chat

    -

    {error || "An unknown error occurred"}

    -
    -
    - ) - } + if (isLoading) { + return ( +
    + +
    + ); + } - return ( -
    -
    -
    - - - Back to chat list - - - - {sender.charAt(0).toUpperCase()} - -
    -

    {getSenderData(sender, chat.doctorName!, chat.patientName!) || "Unknown"}

    -

    {sender.charAt(0).toUpperCase() + sender.slice(1)}

    -
    -
    -
    - -
    -
    - setMessage(e.target.value)} - onKeyDown={(e) => e.key === 'Enter' && handleSendMessage()} - /> -
    - setShowEmojiPicker(!showEmojiPicker)} - ref={emojiButtonRef} - aria-label="Add emoji" - > - - - {showEmojiPicker && ( -
    - -
    - )} -
    - - - Send - -
    -
    -
    - ) -} \ No newline at end of file + if (isError) { + return ( +
    +
    + +

    Error loading chat

    +

    {error || "An unknown error occurred"}

    +
    +
    + ); + } + + return ( +
    +
    +
    + + + Back to chat list + + + + {sender.charAt(0).toUpperCase()} + +
    +

    + {getSenderData(sender, chat.doctorName!, chat.patientName!) || "Unknown"} +

    +

    {sender.charAt(0).toUpperCase() + sender.slice(1)}

    +
    +
    +
    + +
    +
    + setMessage(e.target.value)} + onKeyDown={(e) => e.key === "Enter" && handleSendMessage()} + /> +
    + setShowEmojiPicker(!showEmojiPicker)} + ref={emojiButtonRef} + aria-label="Add emoji" + > + + + {showEmojiPicker && ( +
    + +
    + )} +
    + + + Send + +
    +
    +
    + ); +} diff --git a/client/components/page-components/chat/Messages.tsx b/client/components/page-components/chat/Messages.tsx index 25429a15..672c3e34 100644 --- a/client/components/page-components/chat/Messages.tsx +++ b/client/components/page-components/chat/Messages.tsx @@ -1,73 +1,87 @@ -'use client' +"use client"; -import { useRef, useEffect } from 'react' -import { ScrollArea } from "@/components/ui/scroll-area" -import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" -import { format } from "date-fns" -import { IChat, IMessage } from "@/types/entities" -import { getReceiverData, getSenderData } from './getUserData' +import { useRef, useEffect } from "react"; +import { ScrollArea } from "@/components/ui/scroll-area"; +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; +import { format } from "date-fns"; +import { IChat, IMessage } from "@/types/entities"; +import { getReceiverData, getSenderData } from "./getUserData"; interface ChatSectionProps { - sender: "doctor" | "patient" - messages: IMessage[] - chat: IChat + sender: "doctor" | "patient"; + messages: IMessage[]; + chat: IChat; } export default function Messages({ messages, sender, chat }: ChatSectionProps) { - const scrollAreaRef = useRef(null); - const bottomRef = useRef(null); + const scrollAreaRef = useRef(null); + const bottomRef = useRef(null); - const scrollToBottom = () => { - bottomRef.current?.scrollIntoView({ behavior: 'auto' }); - }; + const scrollToBottom = () => { + bottomRef.current?.scrollIntoView({ behavior: "auto" }); + }; - useEffect(() => { - scrollToBottom(); - }, [messages]); + useEffect(() => { + scrollToBottom(); + }, [messages]); - return ( - -
    - {messages.map(({ _id, message, senderId, createdAt, isReceived }, i) => { - const isSenderMessage = senderId === (sender === 'patient' ? chat.patientId : chat.doctorId); - if (isSenderMessage) { - return ( -
    - - - {getSenderData(sender, chat.doctorName!, chat.patientName!).charAt(0)} - -
    -
    -

    {message}

    -
    - - {format(new Date(createdAt!), "hh:mm a")} - -
    -
    - ); - } else { - return ( -
    -
    -
    -

    {message}

    -
    - - {format(new Date(createdAt!), "hh:mm a")} {isReceived && 'โœ”๏ธ'} - -
    - - - {getReceiverData(sender, chat.doctorName!, chat.patientName!).charAt(0)} - -
    - ); - } - })} -
    -
    - - ) -} \ No newline at end of file + return ( + +
    + {messages.map(({ _id, message, senderId, createdAt, isReceived }, i) => { + const isSenderMessage = senderId === (sender === "patient" ? chat.patientId : chat.doctorId); + if (isSenderMessage) { + return ( +
    + + + + {getSenderData(sender, chat.doctorName!, chat.patientName!).charAt(0)} + + +
    +
    +

    {message}

    +
    + {format(new Date(createdAt!), "hh:mm a")} +
    +
    + ); + } else { + return ( +
    +
    +
    +

    {message}

    +
    + + {format(new Date(createdAt!), "hh:mm a")} {isReceived && "โœ”๏ธ"} + +
    + + + + {getReceiverData(sender, chat.doctorName!, chat.patientName!).charAt(0)} + + +
    + ); + } + })} +
    +
    + + ); +} diff --git a/client/components/page-components/chat/NotAuthenticated.tsx b/client/components/page-components/chat/NotAuthenticated.tsx index 2fa00650..4dcd8111 100644 --- a/client/components/page-components/chat/NotAuthenticated.tsx +++ b/client/components/page-components/chat/NotAuthenticated.tsx @@ -1,27 +1,25 @@ -import { ButtonV2 } from "@/components/button/ButtonV2" -import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card" -import { LogIn } from "lucide-react" -import Link from "next/link" +import { ButtonV2 } from "@/components/button/ButtonV2"; +import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; +import { LogIn } from "lucide-react"; +import Link from "next/link"; export default function NotAuthenticated() { - return ( -
    - - - Authentication Required - Please log in to access your messages - - - - - - - - signin - - - - -
    - ) -} \ No newline at end of file + return ( +
    + + + Authentication Required + Please log in to access your messages + + + + + + + signin + + + +
    + ); +} diff --git a/client/components/page-components/chat/getUserData.ts b/client/components/page-components/chat/getUserData.ts index 5a9b79dc..6b21bc4e 100644 --- a/client/components/page-components/chat/getUserData.ts +++ b/client/components/page-components/chat/getUserData.ts @@ -1,18 +1,17 @@ export const getSenderData = (sender: "doctor" | "patient", doctorData: string, patientData: string): string => { - if (sender === 'patient') { - return patientData - } else if (sender === 'doctor') { - return doctorData; - } - return 'Unknown' -} - + if (sender === "patient") { + return patientData; + } else if (sender === "doctor") { + return doctorData; + } + return "Unknown"; +}; export const getReceiverData = (sender: "doctor" | "patient", doctorData: string, patientData: string): string => { - if (sender === 'patient') { - return doctorData - } else if (sender === 'doctor') { - return patientData; - } - return 'Unknown' -} \ No newline at end of file + if (sender === "patient") { + return doctorData; + } else if (sender === "doctor") { + return patientData; + } + return "Unknown"; +}; diff --git a/client/components/page-components/chatbot/ChatBotButton.tsx b/client/components/page-components/chatbot/ChatBotButton.tsx index 7772a739..5dbadb73 100644 --- a/client/components/page-components/chatbot/ChatBotButton.tsx +++ b/client/components/page-components/chatbot/ChatBotButton.tsx @@ -1,62 +1,58 @@ -'use client'; +"use client"; -import { memo, useState } from 'react' -import { motion, AnimatePresence } from "framer-motion" -import { ButtonV2 } from '@/components/button/ButtonV2'; -import Image from 'next/image'; -import { usePathname } from 'next/navigation'; -import { useAuth } from '@/lib/hooks/useAuth'; -import dynamic from 'next/dynamic'; +import { memo, useState } from "react"; +import { motion, AnimatePresence } from "framer-motion"; +import { ButtonV2 } from "@/components/button/ButtonV2"; +import Image from "next/image"; +import { usePathname } from "next/navigation"; +import { useAuth } from "@/lib/hooks/useAuth"; +import dynamic from "next/dynamic"; -const ChatSection = dynamic(() => import('./ChatSection'), { ssr: false }) +const ChatSection = dynamic(() => import("./ChatSection"), { ssr: false }); const Chatbot = () => { - const path = usePathname(); - const { patientToken, isChatBotOpen, setChatBotOpen } = useAuth(); + const path = usePathname(); + const { patientToken, isChatBotOpen, setChatBotOpen } = useAuth(); - if ( - path.includes("/chats") || - path.includes("/register") || - path.includes("/signup") || - path.includes("/video-section") || - path.includes("/doctor") || - path.includes("/admin") || - path.includes("signin") || - path.includes("opt-verification") - ) { - return null; - } - return ( -
    - - {!isChatBotOpen && ( - - setChatBotOpen(true)} - variant={"ringHover"} - className="rounded-full w-16 h-16 md:w-20 md:h-20 bg-green-600 shadow-lg hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2" - aria-label="Open chat" - > - Robot - - - )} - - {isChatBotOpen && - - } -
    - ) -} + if ( + path.includes("/chats") || + path.includes("/register") || + path.includes("/signup") || + path.includes("/video-section") || + path.includes("/doctor") || + path.includes("/admin") || + path.includes("signin") || + path.includes("opt-verification") + ) { + return null; + } + return ( +
    + + {!isChatBotOpen && ( + + setChatBotOpen(true)} + variant={"ringHover"} + className="rounded-full w-16 h-16 md:w-20 md:h-20 bg-green-600 shadow-lg hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2" + aria-label="Open chat" + > + Robot + + + )} + + {isChatBotOpen && ( + + )} +
    + ); +}; -export default memo(Chatbot) +export default memo(Chatbot); diff --git a/client/components/page-components/chatbot/ChatBotCardHeader.tsx b/client/components/page-components/chatbot/ChatBotCardHeader.tsx index 382f2984..d982e6e1 100644 --- a/client/components/page-components/chatbot/ChatBotCardHeader.tsx +++ b/client/components/page-components/chatbot/ChatBotCardHeader.tsx @@ -1,38 +1,32 @@ -import { ButtonV2 } from "@/components/button/ButtonV2" -import { CardHeader } from "@/components/ui/card" -import Image from "next/image" +import { ButtonV2 } from "@/components/button/ButtonV2"; +import { CardHeader } from "@/components/ui/card"; +import Image from "next/image"; import { memo } from "react"; const ChatBotCardHeader = ({ handleClose }: { handleClose: () => void }) => { - return ( - -
    - Robot -

    Ayurvedic Assistant

    -
    - - Close - -
    - ) -} + return ( + +
    + Robot +

    Ayurvedic Assistant

    +
    + + Close + +
    + ); +}; -export default memo(ChatBotCardHeader); \ No newline at end of file +export default memo(ChatBotCardHeader); diff --git a/client/components/page-components/chatbot/ChatBotController.tsx b/client/components/page-components/chatbot/ChatBotController.tsx index 7b0a4902..7bc1f58e 100644 --- a/client/components/page-components/chatbot/ChatBotController.tsx +++ b/client/components/page-components/chatbot/ChatBotController.tsx @@ -5,49 +5,49 @@ import { Send } from "lucide-react"; import { memo } from "react"; type ChatBotControllerProps = { - inputMessage: string; - setInputMessage: (value: string) => void; - sendMessage: () => void; - isSending: boolean; + inputMessage: string; + setInputMessage: (value: string) => void; + sendMessage: () => void; + isSending: boolean; }; const ChatBotController = ({ inputMessage, setInputMessage, sendMessage, isSending }: ChatBotControllerProps) => { - return ( - -
    { - e.preventDefault(); - if (!isSending) sendMessage(); - }} - className="flex w-full items-center space-x-2 sm:space-x-3" + return ( + + { + e.preventDefault(); + if (!isSending) sendMessage(); + }} + className="flex w-full items-center space-x-2 sm:space-x-3" + > + setInputMessage(e.target.value)} + className="flex-grow bg-dark-100 text-white placeholder-gray-400 border-gray-600 focus:border-green-500 focus:ring-green-500 text-xs sm:text-sm py-2 sm:py-3 rounded-full" + aria-label="Type your message" + onKeyDown={(e) => { + if (e.key === "Enter" && !e.shiftKey) { + e.preventDefault(); + sendMessage(); + } + }} + /> + - setInputMessage(e.target.value)} - className="flex-grow bg-dark-100 text-white placeholder-gray-400 border-gray-600 focus:border-green-500 focus:ring-green-500 text-xs sm:text-sm py-2 sm:py-3 rounded-full" - aria-label="Type your message" - onKeyDown={(e) => { - if (e.key === 'Enter' && !e.shiftKey) { - e.preventDefault(); - sendMessage(); - } - }} - /> - - - - -
    - ); + + + +
    + ); }; -export default memo(ChatBotController); \ No newline at end of file +export default memo(ChatBotController); diff --git a/client/components/page-components/chatbot/ChatSection.tsx b/client/components/page-components/chatbot/ChatSection.tsx index 32ddf4d8..534f8218 100644 --- a/client/components/page-components/chatbot/ChatSection.tsx +++ b/client/components/page-components/chatbot/ChatSection.tsx @@ -1,104 +1,105 @@ -'use client'; +"use client"; -import { useState, useEffect, memo, useCallback } from 'react'; +import { useState, useEffect, memo, useCallback } from "react"; import { Card } from "@/components/ui/card"; import { motion, AnimatePresence } from "framer-motion"; -import ChatBotController from './ChatBotController'; -import MessageDisplay from './MessageDisplay'; -import NotAuthenticated from './NotAuthenticated'; -import { IChatBotMessage } from '@/types/entities'; -import { useCreateMessage, useGetMessage } from '@/lib/hooks/chatbot/useChatBot'; -import { toast } from '@/components/ui/use-toast'; -import { getRandomId } from '@/lib/utils'; +import ChatBotController from "./ChatBotController"; +import MessageDisplay from "./MessageDisplay"; +import NotAuthenticated from "./NotAuthenticated"; +import { IChatBotMessage } from "@/types/entities"; +import { useCreateMessage, useGetMessage } from "@/lib/hooks/chatbot/useChatBot"; +import { toast } from "@/components/ui/use-toast"; +import { getRandomId } from "@/lib/utils"; type Props = { - isVisible: boolean; - setIsOpen: (value: boolean) => void; - isAuthenticated: boolean; + isVisible: boolean; + setIsOpen: (value: boolean) => void; + isAuthenticated: boolean; }; const ChatSection = ({ isVisible, setIsOpen, isAuthenticated }: Props) => { - const { data, isLoading } = useGetMessage(); - const [messages, setMessages] = useState([]); - const [inputMessage, setInputMessage] = useState(''); - const { mutate: createMessage, isPending } = useCreateMessage(); - const [isTyping, setIsTyping] = useState(false); + const { data, isLoading } = useGetMessage(); + const [messages, setMessages] = useState([]); + const [inputMessage, setInputMessage] = useState(""); + const { mutate: createMessage, isPending } = useCreateMessage(); + const [isTyping, setIsTyping] = useState(false); - useEffect(() => { - if (data && data?.length > 0) { - setMessages(data); - } - }, [data]); + useEffect(() => { + if (data && data?.length > 0) { + setMessages(data); + } + }, [data]); - const handleClose = useCallback(() => { - setIsOpen(false); - }, [setIsOpen]); + const handleClose = useCallback(() => { + setIsOpen(false); + }, [setIsOpen]); - const sendMessage = useCallback(() => { - if (inputMessage.trim()) { - const id = getRandomId(); - const tempMessage: IChatBotMessage = { - isBotMessage: false, - message: inputMessage, - _id: id, - patientId: id - }; - setMessages(prev => [...prev, tempMessage]); - setInputMessage(""); - setIsTyping(true); + const sendMessage = useCallback(() => { + if (inputMessage.trim()) { + const id = getRandomId(); + const tempMessage: IChatBotMessage = { + isBotMessage: false, + message: inputMessage, + _id: id, + patientId: id, + }; + setMessages((prev) => [...prev, tempMessage]); + setInputMessage(""); + setIsTyping(true); - createMessage({ message: inputMessage }, - { - onSuccess: (newMessage) => { - setIsTyping(false); - setMessages(prev => [...prev, newMessage]); - }, - onError: (error) => { - setIsTyping(false); - toast({ - title: "Error Occurred while sending message", - variant: "destructive", - description: error.response?.data.message || "Unknown error Occurred" - }); - setInputMessage(tempMessage.message!); - } - } - ); - } - }, [inputMessage, setInputMessage, setIsTyping, createMessage]); + createMessage( + { message: inputMessage }, + { + onSuccess: (newMessage) => { + setIsTyping(false); + setMessages((prev) => [...prev, newMessage]); + }, + onError: (error) => { + setIsTyping(false); + toast({ + title: "Error Occurred while sending message", + variant: "destructive", + description: error.response?.data.message || "Unknown error Occurred", + }); + setInputMessage(tempMessage.message!); + }, + } + ); + } + }, [inputMessage, setInputMessage, setIsTyping, createMessage]); - return ( - setIsOpen(false)}> - {isVisible && ( - - {isAuthenticated ? ( - - - - - ) : ( - - )} - - )} - - ); + return ( + setIsOpen(false)}> + {isVisible && ( + + {isAuthenticated ? ( + + + + + ) : ( + + )} + + )} + + ); }; -export default memo(ChatSection); \ No newline at end of file +export default memo(ChatSection); diff --git a/client/components/page-components/chatbot/MessageDisplay.tsx b/client/components/page-components/chatbot/MessageDisplay.tsx index 97e5abbd..2bd73abc 100644 --- a/client/components/page-components/chatbot/MessageDisplay.tsx +++ b/client/components/page-components/chatbot/MessageDisplay.tsx @@ -4,123 +4,131 @@ import Image from "next/image"; import ChatBotCardHeader from "./ChatBotCardHeader"; import { IChatBotMessage } from "@/types/entities"; import { useEffect, useRef, useState, useMemo, useCallback } from "react"; -import ReactMarkdown from 'react-markdown'; -import { motion, AnimatePresence } from 'framer-motion'; +import ReactMarkdown from "react-markdown"; +import { motion, AnimatePresence } from "framer-motion"; type Props = { - handleClose: () => void; - messages: IChatBotMessage[]; - isLoading: boolean; - isTyping: boolean; + handleClose: () => void; + messages: IChatBotMessage[]; + isLoading: boolean; + isTyping: boolean; }; const MessageDisplay = ({ handleClose, messages, isLoading, isTyping }: Props) => { - const scrollAreaRef = useRef(null); - const bottomRef = useRef(null); - const [expandedMessages, setExpandedMessages] = useState>(new Set()); + const scrollAreaRef = useRef(null); + const bottomRef = useRef(null); + const [expandedMessages, setExpandedMessages] = useState>(new Set()); - const scrollToBottom = useCallback(() => { - bottomRef.current?.scrollIntoView({ behavior: 'smooth' }); - }, []); + const scrollToBottom = useCallback(() => { + bottomRef.current?.scrollIntoView({ behavior: "smooth" }); + }, []); - useEffect(() => { - scrollToBottom(); - }, [messages, isTyping, scrollToBottom]); + useEffect(() => { + scrollToBottom(); + }, [messages, isTyping, scrollToBottom]); - const toggleMessageExpansion = useCallback((id: string) => { - setExpandedMessages(prev => { - const newSet = new Set(prev); - if (newSet.has(id)) { - newSet.delete(id); - } else { - newSet.add(id); - } - return newSet; - }); - }, []); + const toggleMessageExpansion = useCallback((id: string) => { + setExpandedMessages((prev) => { + const newSet = new Set(prev); + if (newSet.has(id)) { + newSet.delete(id); + } else { + newSet.add(id); + } + return newSet; + }); + }, []); - const renderedMessages = useMemo(() => - messages.map((msg, index) => { - const messageId = msg._id || `msg-${index}`; - const isExpanded = expandedMessages.has(messageId); - const messageContent = msg.message || ''; - const isLongMessage = messageContent.length > 150; + const renderedMessages = useMemo( + () => + messages.map((msg, index) => { + const messageId = msg._id || `msg-${index}`; + const isExpanded = expandedMessages.has(messageId); + const messageContent = msg.message || ""; + const isLongMessage = messageContent.length > 150; - return ( - -
    -
    - {!msg.isBotMessage -
    -
    - - {isLongMessage && !isExpanded ? `${messageContent.slice(0, 150)}...` : messageContent} - - {isLongMessage && ( - - )} -
    -
    -
    - ); - }) - , [messages, expandedMessages, toggleMessageExpansion]); - - return ( - <> - - - - {isLoading ? ( -
    -
    -
    - ) : ( - <> - {renderedMessages} - - {isTyping && ( - +
    -
    -
    - - - -
    -
    - - )} - - - )} -
    - - - - ); +
    + {!msg.isBotMessage +
    +
    + + {isLongMessage && !isExpanded ? `${messageContent.slice(0, 150)}...` : messageContent} + + {isLongMessage && ( + + )} +
    +
    +
    + ); + }), + [messages, expandedMessages, toggleMessageExpansion] + ); + + return ( + <> + + + + {isLoading ? ( +
    +
    +
    + ) : ( + <> + {renderedMessages} + + {isTyping && ( + +
    +
    + + + +
    +
    +
    + )} +
    + + )} +
    +
    +
    + + ); }; export default MessageDisplay; diff --git a/client/components/page-components/chatbot/NotAuthenticated.tsx b/client/components/page-components/chatbot/NotAuthenticated.tsx index eb0e4dae..16b756ed 100644 --- a/client/components/page-components/chatbot/NotAuthenticated.tsx +++ b/client/components/page-components/chatbot/NotAuthenticated.tsx @@ -1,50 +1,48 @@ -import { ButtonV2 } from "@/components/button/ButtonV2" -import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card" -import { LogIn } from "lucide-react" -import Link from "next/link" -import Image from "next/image" +import { ButtonV2 } from "@/components/button/ButtonV2"; +import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; +import { LogIn } from "lucide-react"; +import Link from "next/link"; +import Image from "next/image"; import { memo } from "react"; interface NotAuthenticatedProps { - onClose: () => void; + onClose: () => void; } const NotAuthenticated: React.FC = ({ onClose }) => { - return ( - - - - Close - - Authentication Required - Please log in to access your messages - - -
    - -
    -
    - - - - Sign in to Continue - - - -
    - ) -} + return ( + + + + Close + + Authentication Required + Please log in to access your messages + + +
    + +
    +
    + + + Sign in to Continue + + +
    + ); +}; -export default memo(NotAuthenticated) \ No newline at end of file +export default memo(NotAuthenticated); diff --git a/client/components/page-components/doctor/slots/MultiSlots.tsx b/client/components/page-components/doctor/slots/MultiSlots.tsx index ce615ac7..0c99a3ae 100644 --- a/client/components/page-components/doctor/slots/MultiSlots.tsx +++ b/client/components/page-components/doctor/slots/MultiSlots.tsx @@ -47,11 +47,11 @@ const SlotManager = () => { variant: "success", }); setTimeout(() => { - Object.values(Days).forEach(el => { + Object.values(Days).forEach((el) => { query.invalidateQueries({ - queryKey: ["slotsByDay",el], + queryKey: ["slotsByDay", el], }); - }) + }); }); }, onError: (error) => { @@ -81,11 +81,11 @@ const SlotManager = () => { }); setDeleteModelOpen(false); setTimeout(() => { - Object.values(Days).forEach(el => { + Object.values(Days).forEach((el) => { query.invalidateQueries({ - queryKey: ["slotsByDay",el], + queryKey: ["slotsByDay", el], }); - }) + }); }); }, onError: (error) => { diff --git a/client/components/page-components/landing/about/BookingSection.tsx b/client/components/page-components/landing/about/BookingSection.tsx index 93e0d8cb..8b02eb2a 100644 --- a/client/components/page-components/landing/about/BookingSection.tsx +++ b/client/components/page-components/landing/about/BookingSection.tsx @@ -1,22 +1,24 @@ -'use client' +"use client"; import { Card, CardContent } from "@/components/ui/card"; import { ButtonV2 } from "@/components/button/ButtonV2"; import { useRouter } from "next/navigation"; import { memo } from "react"; const BookingSection = () => { - const router = useRouter(); - return ( - - -

    Ready to Start Your Wellness Journey?

    -

    Book a consultation with our Ayurvedic experts and take the first step towards holistic health.

    - router.push("/new-appointment")} variant={"shine"} size="default"> - Book an Appointment - -
    -
    - ); + const router = useRouter(); + return ( + + +

    Ready to Start Your Wellness Journey?

    +

    + Book a consultation with our Ayurvedic experts and take the first step towards holistic health. +

    + router.push("/new-appointment")} variant={"shine"} size="default"> + Book an Appointment + +
    +
    + ); }; export default memo(BookingSection); diff --git a/client/components/page-components/landing/about/HeroSection.tsx b/client/components/page-components/landing/about/HeroSection.tsx index e692f4bb..3914cb86 100644 --- a/client/components/page-components/landing/about/HeroSection.tsx +++ b/client/components/page-components/landing/about/HeroSection.tsx @@ -4,37 +4,37 @@ import { SliderImages } from "@/constants"; import { memo } from "react"; const HeroSection = () => { - const randomIndex = Math.floor(Math.random() * SliderImages.length); - const randomImage = SliderImages[randomIndex]; + const randomIndex = Math.floor(Math.random() * SliderImages.length); + const randomImage = SliderImages[randomIndex]; - return ( - - -
    -
    -
    - AVM Ayurveda + return ( + + +
    +
    +
    + AVM Ayurveda +
    +
    +
    +

    Embracing Holistic Wellness

    +

    + At Avm Ayurveda, we're dedicated to reviving the ancient wisdom of Ayurveda and integrating it + with modern healthcare practices. Our goal is to guide you on a journey of holistic healing and + self-discovery. +

    +
    -
    -
    -

    Embracing Holistic Wellness

    -

    - At Avm Ayurveda, we're dedicated to reviving the ancient wisdom of Ayurveda - and integrating it with modern healthcare practices. Our goal is to guide you on a - journey of holistic healing and self-discovery. -

    -
    -
    - - - ); + + + ); }; export default memo(HeroSection); diff --git a/client/components/page-components/landing/about/LocationMap.tsx b/client/components/page-components/landing/about/LocationMap.tsx index 90ce9c74..08e36f6c 100644 --- a/client/components/page-components/landing/about/LocationMap.tsx +++ b/client/components/page-components/landing/about/LocationMap.tsx @@ -3,91 +3,85 @@ import Image from "next/image"; import { memo } from "react"; const LocationMap = () => { - return ( - - - - Location - Our Location - - - -
    -
    -
    - + return ( + + + + Location + Our Location + + + +
    +
    +
    + +
    +
    +

    How to reach us:

    +
      +
    • โ€ข 15 minutes drive from Calicut International Airport
    • +
    • โ€ข 30 minutes from Kozhikode Railway Station
    • +
    • โ€ข Bus stop: Chelannur Bus Stand (2 min walk)
    • +
    +
    +
    +
    +
    +

    Contact Information:

    +
      +
    • + Location + Chelannur, Kozhikode, Kerala 673616 +
    • +
    • + Location + 04952262655 +
    • +
    • + Location + avmayrveda@gmail.com +
    • +
    +
    +
    +

    Nearby Landmarks:

    +
      +
    • โ€ข Chelannur Shiva Temple (0.5 km)
    • +
    • โ€ข Peruvayal Bhagavathi Temple (2 km)
    • +
    • โ€ข Kunnamangalam Town (5 km)
    • +
    +
    +
    -
    -

    How to reach us:

    -
      -
    • โ€ข 15 minutes drive from Calicut International Airport
    • -
    • โ€ข 30 minutes from Kozhikode Railway Station
    • -
    • โ€ข Bus stop: Chelannur Bus Stand (2 min walk)
    • -
    -
    -
    -
    -
    -

    Contact Information:

    -
      -
    • - Location - Chelannur, Kozhikode, Kerala 673616 -
    • -
    • - Location - 04952262655 -
    • -
    • - Location - avmayrveda@gmail.com -
    • -
    -
    -
    -

    Nearby Landmarks:

    -
      -
    • โ€ข Chelannur Shiva Temple (0.5 km)
    • -
    • โ€ข Peruvayal Bhagavathi Temple (2 km)
    • -
    • โ€ข Kunnamangalam Town (5 km)
    • -
    -
    -
    -
    - - - ); + + + ); }; export default memo(LocationMap); diff --git a/client/components/page-components/landing/about/MissionAndValues.tsx b/client/components/page-components/landing/about/MissionAndValues.tsx index 07ce15cf..f093b908 100644 --- a/client/components/page-components/landing/about/MissionAndValues.tsx +++ b/client/components/page-components/landing/about/MissionAndValues.tsx @@ -3,43 +3,50 @@ import Image from "next/image"; import { memo, useMemo } from "react"; const values = [ - { title: "Holistic Approach", description: "We treat the whole person, not just symptoms." }, - { title: "Personalized Care", description: "Every treatment plan is tailored to the individual." }, - { title: "Ancient Wisdom, Modern Science", description: "We combine traditional Ayurveda with contemporary research." }, - { title: "Continuous Learning", description: "Our team stays updated with the latest in Ayurvedic medicine." }, + { title: "Holistic Approach", description: "We treat the whole person, not just symptoms." }, + { title: "Personalized Care", description: "Every treatment plan is tailored to the individual." }, + { + title: "Ancient Wisdom, Modern Science", + description: "We combine traditional Ayurveda with contemporary research.", + }, + { title: "Continuous Learning", description: "Our team stays updated with the latest in Ayurvedic medicine." }, ]; const MissionAndValues = () => { - const cards = useMemo( - () => - values.map((value, index) => ( -
    - Check -
    -

    {value.title}

    -

    {value.description}

    -
    -
    - )), - [] - ); + const cards = useMemo( + () => + values.map((value, index) => ( +
    + Check +
    +

    {value.title}

    +

    {value.description}

    +
    +
    + )), + [] + ); - return ( - - - Our Mission and Values - - -

    - Our mission is to empower individuals to achieve optimal health and harmony through - the timeless wisdom of Ayurveda, delivered with compassion and expertise. -

    -
    - {cards} -
    -
    -
    - ); + return ( + + + Our Mission and Values + + +

    + Our mission is to empower individuals to achieve optimal health and harmony through the timeless wisdom + of Ayurveda, delivered with compassion and expertise. +

    +
    {cards}
    +
    +
    + ); }; export default memo(MissionAndValues); diff --git a/client/components/page-components/landing/about/OurStory.tsx b/client/components/page-components/landing/about/OurStory.tsx index 75760c81..a6891713 100644 --- a/client/components/page-components/landing/about/OurStory.tsx +++ b/client/components/page-components/landing/about/OurStory.tsx @@ -2,30 +2,34 @@ import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; import { memo } from "react"; const OurStory = () => { - return ( - - - Our Story - - -

    - Founded in 2000 by Moyudu Gurikkal, AVM Ayurveda began with a vision to harness the power of nature and ancient wisdom. Our journey has been one of growth, learning, and unwavering commitment to holistic health. -

    -

    - At AVM Ayurveda, we blend time-honored Ayurvedic practices with modern wellness approaches. Our comprehensive care includes: -

    -
      -
    • Customized Ayurvedic therapies
    • -
    • Natural herbal remedies
    • -
    • Mindfulness practices
    • -
    • Traditional Kalari classes
    • -
    -

    - With over two decades of expertise, we invite you to experience the transformative power of Ayurveda and embark on a journey towards balanced, vibrant living. -

    -
    -
    - ); + return ( + + + Our Story + + +

    + Founded in 2000 by Moyudu Gurikkal, AVM Ayurveda began with a vision to harness the power of nature and + ancient wisdom. Our journey has been one of growth, learning, and unwavering commitment to holistic + health. +

    +

    + At AVM Ayurveda, we blend time-honored Ayurvedic practices with modern wellness approaches. Our + comprehensive care includes: +

    +
      +
    • Customized Ayurvedic therapies
    • +
    • Natural herbal remedies
    • +
    • Mindfulness practices
    • +
    • Traditional Kalari classes
    • +
    +

    + With over two decades of expertise, we invite you to experience the transformative power of Ayurveda and + embark on a journey towards balanced, vibrant living. +

    +
    +
    + ); }; export default memo(OurStory); diff --git a/client/components/page-components/landing/about/WhyChooseUs.tsx b/client/components/page-components/landing/about/WhyChooseUs.tsx index 61498df0..4f0f29fa 100644 --- a/client/components/page-components/landing/about/WhyChooseUs.tsx +++ b/client/components/page-components/landing/about/WhyChooseUs.tsx @@ -3,33 +3,39 @@ import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; import { memo } from "react"; const WhyChooseUs = () => { - return ( - - - - Stethoscope - Why Choose Ayurveda Health Center? - - - -
      - {[ - "Expert Ayurvedic Physicians", - "Personalized Treatment Plans", - "State-of-the-art Facilities", - "Authentic Herbal Medicines", - "Holistic Wellness Programs", - "Ongoing Support and Education", - ].map((benefit, index) => ( -
    • - Check - {benefit} -
    • - ))} -
    -
    -
    - ); + return ( + + + + Stethoscope + Why Choose Ayurveda Health Center? + + + +
      + {[ + "Expert Ayurvedic Physicians", + "Personalized Treatment Plans", + "State-of-the-art Facilities", + "Authentic Herbal Medicines", + "Holistic Wellness Programs", + "Ongoing Support and Education", + ].map((benefit, index) => ( +
    • + Check + {benefit} +
    • + ))} +
    +
    +
    + ); }; export default memo(WhyChooseUs); diff --git a/client/components/page-components/landing/clinicians/AyurvedaSection.tsx b/client/components/page-components/landing/clinicians/AyurvedaSection.tsx index 128e5f84..25c7cac7 100644 --- a/client/components/page-components/landing/clinicians/AyurvedaSection.tsx +++ b/client/components/page-components/landing/clinicians/AyurvedaSection.tsx @@ -32,4 +32,4 @@ const AyurvedaSection = () => (
    ); -export default memo(AyurvedaSection); \ No newline at end of file +export default memo(AyurvedaSection); diff --git a/client/components/page-components/landing/clinicians/CTASection.tsx b/client/components/page-components/landing/clinicians/CTASection.tsx index ebbb6ac9..11b1aaf5 100644 --- a/client/components/page-components/landing/clinicians/CTASection.tsx +++ b/client/components/page-components/landing/clinicians/CTASection.tsx @@ -13,4 +13,4 @@ const CTASection = () => (
    ); -export default memo(CTASection) \ No newline at end of file +export default memo(CTASection); diff --git a/client/components/page-components/landing/clinicians/DoctorCard.tsx b/client/components/page-components/landing/clinicians/DoctorCard.tsx index e74f23df..ff482d87 100644 --- a/client/components/page-components/landing/clinicians/DoctorCard.tsx +++ b/client/components/page-components/landing/clinicians/DoctorCard.tsx @@ -1,4 +1,4 @@ -'use client'; +"use client"; import { memo } from "react"; import Image from "next/image"; @@ -54,22 +54,30 @@ const DoctorCard: React.FC = ({ doctor }) => {
    {doctor.phone && (
    - Phone + Phone {doctor.phone}
    )} {doctor.email && (
    - Email + Email {doctor.email}
    )}
    - redirect()} - className="w-full text-sm sm:text-base" - > + redirect()} className="w-full text-sm sm:text-base"> Book Appointment
    @@ -77,4 +85,4 @@ const DoctorCard: React.FC = ({ doctor }) => { ); }; -export default memo(DoctorCard); \ No newline at end of file +export default memo(DoctorCard); diff --git a/client/components/page-components/landing/clinicians/DoctorsList.tsx b/client/components/page-components/landing/clinicians/DoctorsList.tsx index 2f310870..57651bf5 100644 --- a/client/components/page-components/landing/clinicians/DoctorsList.tsx +++ b/client/components/page-components/landing/clinicians/DoctorsList.tsx @@ -6,69 +6,69 @@ import DoctorCard from "@/components/page-components/landing/clinicians/DoctorCa import Pagination from "@/components/navigation/Pagination"; interface DoctorsListProps { - initialData: IDoctor[]; + initialData: IDoctor[]; } const DoctorsList = ({ initialData }: DoctorsListProps) => { - const [currentPage, setCurrentPage] = useState(1); - const [pageSize, setPageSize] = useState(3); + const [currentPage, setCurrentPage] = useState(1); + const [pageSize, setPageSize] = useState(3); - useEffect(() => { - const handleResize = () => { - setPageSize(window.innerWidth < 640 ? 2 : 3); - }; + useEffect(() => { + const handleResize = () => { + setPageSize(window.innerWidth < 640 ? 2 : 3); + }; - handleResize(); // Set initial page size - window.addEventListener('resize', handleResize); + handleResize(); // Set initial page size + window.addEventListener("resize", handleResize); - return () => { - window.removeEventListener('resize', handleResize); - }; - }, []); + return () => { + window.removeEventListener("resize", handleResize); + }; + }, []); - const totalPages = useMemo(() => Math.ceil(initialData.length / pageSize), [initialData.length, pageSize]); + const totalPages = useMemo(() => Math.ceil(initialData.length / pageSize), [initialData.length, pageSize]); - const paginatedItems = useMemo( - () => initialData.slice((currentPage - 1) * pageSize, currentPage * pageSize), - [initialData, currentPage, pageSize] - ); + const paginatedItems = useMemo( + () => initialData.slice((currentPage - 1) * pageSize, currentPage * pageSize), + [initialData, currentPage, pageSize] + ); - const handlePageChange = useCallback( - (newPage: number) => { - if (newPage > 0 && newPage <= totalPages) { - setCurrentPage(newPage); - } - }, - [totalPages] - ); + const handlePageChange = useCallback( + (newPage: number) => { + if (newPage > 0 && newPage <= totalPages) { + setCurrentPage(newPage); + } + }, + [totalPages] + ); - useEffect(() => { - if (currentPage > totalPages) { - setCurrentPage(totalPages); - } - }, [currentPage, totalPages]); + useEffect(() => { + if (currentPage > totalPages) { + setCurrentPage(totalPages); + } + }, [currentPage, totalPages]); - if (initialData.length === 0) { - return

    No doctors available at the moment. Please check back later.

    ; - } + if (initialData.length === 0) { + return

    No doctors available at the moment. Please check back later.

    ; + } - return ( -
    -
    - {paginatedItems.map((doctor) => ( - - ))} + return ( +
    +
    + {paginatedItems.map((doctor) => ( + + ))} +
    + 1} + className="mb-16" + />
    - 1} - className="mb-16" - /> -
    - ); -} + ); +}; -export default memo(DoctorsList); \ No newline at end of file +export default memo(DoctorsList); diff --git a/client/components/page-components/landing/clinicians/FAQSection.tsx b/client/components/page-components/landing/clinicians/FAQSection.tsx index 5f3d4d4e..fe73cbac 100644 --- a/client/components/page-components/landing/clinicians/FAQSection.tsx +++ b/client/components/page-components/landing/clinicians/FAQSection.tsx @@ -1,4 +1,4 @@ -import { memo } from "react"; +import { memo } from "react"; import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion"; const FAQSection = () => ( @@ -48,4 +48,4 @@ const FAQSection = () => (
    ); -export default memo(FAQSection); \ No newline at end of file +export default memo(FAQSection); diff --git a/client/components/page-components/landing/clinicians/TestimonialsSection.tsx b/client/components/page-components/landing/clinicians/TestimonialsSection.tsx index c8c7129e..c611cb9e 100644 --- a/client/components/page-components/landing/clinicians/TestimonialsSection.tsx +++ b/client/components/page-components/landing/clinicians/TestimonialsSection.tsx @@ -26,4 +26,4 @@ const TestimonialsSection = () => (
    ); -export default memo(TestimonialsSection); \ No newline at end of file +export default memo(TestimonialsSection); diff --git a/client/components/page-components/landing/home/AboutAyurveda.tsx b/client/components/page-components/landing/home/AboutAyurveda.tsx index 144f266b..f900927a 100644 --- a/client/components/page-components/landing/home/AboutAyurveda.tsx +++ b/client/components/page-components/landing/home/AboutAyurveda.tsx @@ -1,64 +1,59 @@ -"use client" +"use client"; import Image from "next/image"; import { memo, useEffect, useRef } from "react"; import { motion, useAnimation, useInView } from "framer-motion"; const AboutAyurveda = () => { - const controls = useAnimation(); - const ref = useRef(null); - const isInView = useInView(ref, { once: true }); + const controls = useAnimation(); + const ref = useRef(null); + const isInView = useInView(ref, { once: true }); - useEffect(() => { - if (isInView) { - controls.start("visible"); - } - }, [controls, isInView]); + useEffect(() => { + if (isInView) { + controls.start("visible"); + } + }, [controls, isInView]); - return ( -
    - -

    Discover the Power of Ayurveda

    -

    - Ayurveda, the timeless science of life, offers a comprehensive and natural approach to health and - well-being. Grounded in nature, it harmonizes the body, mind, and soul through customized therapies, - herbal remedies, and mindful practices. We prioritize natural healing, avoiding allopathic medicines with - potential side effects. -

    -

    - With over a century of rich heritage and expertise, we provide exceptional service rooted in tradition - and excellence. Our facility also offers Kalari classes, preserving this ancient martial art as part of a - holistic lifestyle. Embrace Ayurveda and Kalari with us for a balanced, vibrant life free from the - drawbacks of modern medicine. -

    -
    - - Ayurvedic Doctor - -
    - ); + return ( +
    + +

    Discover the Power of Ayurveda

    +

    + Ayurveda, the timeless science of life, offers a comprehensive and natural approach to health and + well-being. Grounded in nature, it harmonizes the body, mind, and soul through customized therapies, + herbal remedies, and mindful practices. We prioritize natural healing, avoiding allopathic medicines with + potential side effects. +

    +

    + With over a century of rich heritage and expertise, we provide exceptional service rooted in tradition + and excellence. Our facility also offers Kalari classes, preserving this ancient martial art as part of a + holistic lifestyle. Embrace Ayurveda and Kalari with us for a balanced, vibrant life free from the + drawbacks of modern medicine. +

    +
    + + Ayurvedic Doctor + +
    + ); }; -export default memo(AboutAyurveda); \ No newline at end of file +export default memo(AboutAyurveda); diff --git a/client/components/page-components/landing/home/FeaturedTreatment.tsx b/client/components/page-components/landing/home/FeaturedTreatment.tsx index e2c768f8..037d938f 100644 --- a/client/components/page-components/landing/home/FeaturedTreatment.tsx +++ b/client/components/page-components/landing/home/FeaturedTreatment.tsx @@ -1,35 +1,30 @@ -import React, { memo } from 'react'; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; -import { Button } from '@/components/ui/button'; -import Image from 'next/image'; -import { Treatments } from '@/constants'; +import React, { memo } from "react"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import Image from "next/image"; +import { Treatments } from "@/constants"; const FeaturedTreatments = () => { - return ( -
    -

    Our Featured Treatments

    -
    - {Treatments.map((treatment, index) => ( - -
    - {treatment.title} -
    - - {treatment.title} - - - {treatment.description} - - -
    - ))} -
    -
    - ); + return ( +
    +

    Our Featured Treatments

    +
    + {Treatments.map((treatment, index) => ( + +
    + {treatment.title} +
    + + {treatment.title} + + + {treatment.description} + + +
    + ))} +
    +
    + ); }; -export default memo(FeaturedTreatments); \ No newline at end of file +export default memo(FeaturedTreatments); diff --git a/client/components/page-components/landing/home/Herbs.tsx b/client/components/page-components/landing/home/Herbs.tsx index a5c0dbdb..beb764f6 100644 --- a/client/components/page-components/landing/home/Herbs.tsx +++ b/client/components/page-components/landing/home/Herbs.tsx @@ -1,33 +1,28 @@ -import React, { memo } from 'react' -import Image from 'next/image' -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' -import { Herbs } from '@/constants'; +import React, { memo } from "react"; +import Image from "next/image"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Herbs } from "@/constants"; -const AyurvedicHerbs = () => { - return ( -
    -

    Powerful Ayurvedic Herbs

    -
    - {Herbs.map((herb, index) => ( - -
    - {herb.name} -
    - - {herb.name} - - - {herb.description} - -
    - ))} -
    -
    - ) -} -export default memo(AyurvedicHerbs) \ No newline at end of file +const AyurvedicHerbs = () => { + return ( +
    +

    Powerful Ayurvedic Herbs

    +
    + {Herbs.map((herb, index) => ( + +
    + {herb.name} +
    + + {herb.name} + + + {herb.description} + +
    + ))} +
    +
    + ); +}; +export default memo(AyurvedicHerbs); diff --git a/client/components/page-components/landing/home/ImageSlider.tsx b/client/components/page-components/landing/home/ImageSlider.tsx index cc5b4143..bed0bcc7 100644 --- a/client/components/page-components/landing/home/ImageSlider.tsx +++ b/client/components/page-components/landing/home/ImageSlider.tsx @@ -1,66 +1,66 @@ -"use client" +"use client"; -import { memo, useEffect, useState } from "react" -import { motion } from "framer-motion" -import Link from "next/link" -import ImagesSlider from "@/components/ui/images-slider" -import { SliderImages, SliderTexts } from "@/constants" -import { useAuth } from "@/lib/hooks/useAuth" -import { ButtonV2 } from "@/components/button/ButtonV2" -import FlipWords from "@/components/ui/flip-words" -import useRedirect from "@/lib/hooks/useRedirect" +import { memo, useEffect, useState } from "react"; +import { motion } from "framer-motion"; +import Link from "next/link"; +import ImagesSlider from "@/components/ui/images-slider"; +import { SliderImages, SliderTexts } from "@/constants"; +import { useAuth } from "@/lib/hooks/useAuth"; +import { ButtonV2 } from "@/components/button/ButtonV2"; +import FlipWords from "@/components/ui/flip-words"; +import useRedirect from "@/lib/hooks/useRedirect"; const ImageSlider = () => { - const { patientToken } = useAuth() - const redirect = useRedirect() - const [isClient, setIsClient] = useState(false) + const { patientToken } = useAuth(); + const redirect = useRedirect(); + const [isClient, setIsClient] = useState(false); - useEffect(() => { - setIsClient(true) - }, []) + useEffect(() => { + setIsClient(true); + }, []); - return ( - - -

    - -

    -
    - {isClient && ( - <> - {!patientToken && ( - - redirect('/signin')} - > - Join now โ†’ -
    - - - )} - - redirect()} - > - Book an Appointment now -
    - - - - )} -
    - - - ) -} + return ( + + +

    + +

    +
    + {isClient && ( + <> + {!patientToken && ( + + redirect("/signin")} + > + Join now โ†’ +
    + + + )} + + redirect()} + > + Book an Appointment now +
    + + + + )} +
    + + + ); +}; -export default memo(ImageSlider) \ No newline at end of file +export default memo(ImageSlider); diff --git a/client/components/page-components/landing/home/LifeStyleTips.tsx b/client/components/page-components/landing/home/LifeStyleTips.tsx index 4e3e455e..8293f9ad 100644 --- a/client/components/page-components/landing/home/LifeStyleTips.tsx +++ b/client/components/page-components/landing/home/LifeStyleTips.tsx @@ -1,51 +1,51 @@ -import React, { memo } from 'react' -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' -import { Clock, Coffee, Moon, Sun } from 'lucide-react' +import React, { memo } from "react"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Clock, Coffee, Moon, Sun } from "lucide-react"; const tips = [ - { - title: 'Rise with the Sun', - description: 'Wake up early to align with nature`s rhythms and boost productivity.', - icon: Sun, - }, - { - title: 'Practice Oil Pulling', - description: 'Swish oil in your mouth for 10-15 minutes daily to improve oral health.', - icon: Coffee, - }, - { - title: 'Follow a Consistent Routine', - description: 'Maintain regular times for meals, work, and sleep to balance your doshas.', - icon: Clock, - }, - { - title: 'Get Adequate Sleep', - description: 'Aim for 7-9 hours of sleep per night to support overall health and well-being.', - icon: Moon, - }, -] + { + title: "Rise with the Sun", + description: "Wake up early to align with nature`s rhythms and boost productivity.", + icon: Sun, + }, + { + title: "Practice Oil Pulling", + description: "Swish oil in your mouth for 10-15 minutes daily to improve oral health.", + icon: Coffee, + }, + { + title: "Follow a Consistent Routine", + description: "Maintain regular times for meals, work, and sleep to balance your doshas.", + icon: Clock, + }, + { + title: "Get Adequate Sleep", + description: "Aim for 7-9 hours of sleep per night to support overall health and well-being.", + icon: Moon, + }, +]; -const LifestyleTips = ()=> { - return ( -
    -

    Ayurvedic Lifestyle Tips

    -
    - {tips.map((tip, index) => ( - - -
    - - {tip.title} -
    -
    - -

    {tip.description}

    -
    -
    - ))} -
    -
    - ) -} +const LifestyleTips = () => { + return ( +
    +

    Ayurvedic Lifestyle Tips

    +
    + {tips.map((tip, index) => ( + + +
    + + {tip.title} +
    +
    + +

    {tip.description}

    +
    +
    + ))} +
    +
    + ); +}; -export default memo(LifestyleTips); \ No newline at end of file +export default memo(LifestyleTips); diff --git a/client/components/page-components/landing/home/OurGoals.tsx b/client/components/page-components/landing/home/OurGoals.tsx index 6612163c..4eccff54 100644 --- a/client/components/page-components/landing/home/OurGoals.tsx +++ b/client/components/page-components/landing/home/OurGoals.tsx @@ -1,4 +1,4 @@ -"use client" +"use client"; import Image from "next/image"; import { memo } from "react"; @@ -6,71 +6,73 @@ import { motion } from "framer-motion"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; const goals = [ - "Promote holistic healing through Ayurveda", - "Provide personalized treatment plans", - "Educate about natural lifestyle choices", - "Integrate modern science with traditional wisdom", - "Offer accessible Ayurvedic consultations", + "Promote holistic healing through Ayurveda", + "Provide personalized treatment plans", + "Educate about natural lifestyle choices", + "Integrate modern science with traditional wisdom", + "Offer accessible Ayurvedic consultations", ]; const OurGoals = () => { - return ( -
    -
    -

    Our Goals

    -
    - - Our Goals - - - - - Striving for Excellence in Ayurvedic Care - - -
      - {goals.map((goal, index) => ( - - โœ… - {goal} - - ))} -
    -
    -
    -
    -
    -
    -
    - ); + return ( +
    +
    +

    Our Goals

    +
    + + Our Goals + + + + + + Striving for Excellence in Ayurvedic Care + + + +
      + {goals.map((goal, index) => ( + + โœ… + {goal} + + ))} +
    +
    +
    +
    +
    +
    +
    + ); }; -export default memo(OurGoals); \ No newline at end of file +export default memo(OurGoals); diff --git a/client/components/page-components/landing/services/FeatureList.tsx b/client/components/page-components/landing/services/FeatureList.tsx index 42960353..52eec21e 100644 --- a/client/components/page-components/landing/services/FeatureList.tsx +++ b/client/components/page-components/landing/services/FeatureList.tsx @@ -24,4 +24,4 @@ const FeaturesList = () => { ); }; -export default memo(FeaturesList); \ No newline at end of file +export default memo(FeaturesList); diff --git a/client/components/page-components/landing/services/Featured.tsx b/client/components/page-components/landing/services/Featured.tsx index cd4842d3..17142b8b 100644 --- a/client/components/page-components/landing/services/Featured.tsx +++ b/client/components/page-components/landing/services/Featured.tsx @@ -1,4 +1,4 @@ -'use client'; +"use client"; import Image from "next/image"; import { memo } from "react"; @@ -6,96 +6,100 @@ import { motion } from "framer-motion"; const services = [ { - title: "Hospital Services", - description: "Our hospital services provide comprehensive care for various medical needs. From routine check-ups to emergency care, our facilities are equipped with state-of-the-art technology and staffed by experienced professionals.", - image: "/assets/images/hospital.png", + title: "Hospital Services", + description: + "Our hospital services provide comprehensive care for various medical needs. From routine check-ups to emergency care, our facilities are equipped with state-of-the-art technology and staffed by experienced professionals.", + image: "/assets/images/hospital.png", }, { - title: "Ambulance Services", - description: "Our ambulance services ensure quick and efficient transportation to medical facilities. Equipped with advanced life support systems and staffed by skilled paramedics, we provide reliable emergency medical transport.", - image: "/assets/images/ambulance.png", + title: "Ambulance Services", + description: + "Our ambulance services ensure quick and efficient transportation to medical facilities. Equipped with advanced life support systems and staffed by skilled paramedics, we provide reliable emergency medical transport.", + image: "/assets/images/ambulance.png", }, { - title: "Chat with Doctor", - description: "Our chat services allow you to connect with experienced doctors from the comfort of your home. Get personalized medical advice, answers to your questions, and ongoing support through our secure chat platform.", - image: "/assets/images/chat.png", + title: "Chat with Doctor", + description: + "Our chat services allow you to connect with experienced doctors from the comfort of your home. Get personalized medical advice, answers to your questions, and ongoing support through our secure chat platform.", + image: "/assets/images/chat.png", }, { - title: "Video Call Section", - description: "Experience seamless virtual consultations with our doctors through video calls. Schedule appointments, discuss your health concerns, and receive expert guidance in real-time.", - image: "/assets/images/video.png", + title: "Video Call Section", + description: + "Experience seamless virtual consultations with our doctors through video calls. Schedule appointments, discuss your health concerns, and receive expert guidance in real-time.", + image: "/assets/images/video.png", }, - ]; +]; const Featured = () => { - const containerVariants = { - hidden: { opacity: 0 }, - visible: { - opacity: 1, - transition: { - staggerChildren: 0.1 - } - } - }; + const containerVariants = { + hidden: { opacity: 0 }, + visible: { + opacity: 1, + transition: { + staggerChildren: 0.1, + }, + }, + }; - const itemVariants = { - hidden: { y: 20, opacity: 0 }, - visible: { - y: 0, - opacity: 1, - transition: { - type: "spring", - stiffness: 100 - } - } - }; + const itemVariants = { + hidden: { y: 20, opacity: 0 }, + visible: { + y: 0, + opacity: 1, + transition: { + type: "spring", + stiffness: 100, + }, + }, + }; - return ( -
    -
    - - Our Services - - - {services.map((service, index) => ( - +
    + -
    - - {service.title} - -

    {service.title}

    -

    {service.description}

    -
    + Our Services +
    + + {services.map((service, index) => ( + +
    + + {service.title} + +

    {service.title}

    +

    {service.description}

    +
    +
    + ))}
    - ))} - +
    -
    - ); + ); }; -export default memo(Featured); \ No newline at end of file +export default memo(Featured); diff --git a/client/components/page-components/landing/services/Services.tsx b/client/components/page-components/landing/services/Services.tsx index 3d080d89..3ca75d7f 100644 --- a/client/components/page-components/landing/services/Services.tsx +++ b/client/components/page-components/landing/services/Services.tsx @@ -34,6 +34,6 @@ const Services = () => {
    ); -} +}; -export default memo(Services) \ No newline at end of file +export default memo(Services); diff --git a/client/components/page-components/patient/appointments/PrescriptionPdf.tsx b/client/components/page-components/patient/appointments/PrescriptionPdf.tsx index f71a1f9b..6b12fb10 100644 --- a/client/components/page-components/patient/appointments/PrescriptionPdf.tsx +++ b/client/components/page-components/patient/appointments/PrescriptionPdf.tsx @@ -1,227 +1,247 @@ -import { Document, Page, Text, View, StyleSheet, Font } from '@react-pdf/renderer'; -import { format } from 'date-fns'; -import { IDoctor, IPatient, IPrescription } from '@/types/entities'; +import { Document, Page, Text, View, StyleSheet, Font } from "@react-pdf/renderer"; +import { format } from "date-fns"; +import { IDoctor, IPatient, IPrescription } from "@/types/entities"; Font.register({ - family: 'Roboto', - fonts: [ - { src: 'https://cdnjs.cloudflare.com/ajax/libs/ink/3.1.10/fonts/Roboto/roboto-light-webfont.ttf', fontWeight: 300 }, - { src: 'https://cdnjs.cloudflare.com/ajax/libs/ink/3.1.10/fonts/Roboto/roboto-regular-webfont.ttf', fontWeight: 400 }, - { src: 'https://cdnjs.cloudflare.com/ajax/libs/ink/3.1.10/fonts/Roboto/roboto-medium-webfont.ttf', fontWeight: 500 }, - { src: 'https://cdnjs.cloudflare.com/ajax/libs/ink/3.1.10/fonts/Roboto/roboto-bold-webfont.ttf', fontWeight: 700 }, - ], + family: "Roboto", + fonts: [ + { + src: "https://cdnjs.cloudflare.com/ajax/libs/ink/3.1.10/fonts/Roboto/roboto-light-webfont.ttf", + fontWeight: 300, + }, + { + src: "https://cdnjs.cloudflare.com/ajax/libs/ink/3.1.10/fonts/Roboto/roboto-regular-webfont.ttf", + fontWeight: 400, + }, + { + src: "https://cdnjs.cloudflare.com/ajax/libs/ink/3.1.10/fonts/Roboto/roboto-medium-webfont.ttf", + fontWeight: 500, + }, + { + src: "https://cdnjs.cloudflare.com/ajax/libs/ink/3.1.10/fonts/Roboto/roboto-bold-webfont.ttf", + fontWeight: 700, + }, + ], }); const styles = StyleSheet.create({ - page: { - fontFamily: 'Roboto', - padding: 30, - backgroundColor: '#ffffff', - }, - header: { - flexDirection: 'row', - justifyContent: 'space-between', - alignItems: 'center', - marginBottom: 20, - borderBottom: '2 solid #4a90e2', - paddingBottom: 10, - }, - logo: { - width: 60, - height: 60, - }, - hospitalInfo: { - alignItems: 'center', - }, - hospitalName: { - fontSize: 24, - fontWeight: 700, - color: '#4a90e2', - marginBottom: 5, - }, - title: { - fontSize: 18, - fontWeight: 500, - color: '#4a90e2', - }, - section: { - marginBottom: 15, - }, - sectionTitle: { - fontSize: 14, - fontWeight: 700, - color: '#4a90e2', - marginBottom: 5, - textTransform: 'uppercase', - }, - table: { - width: 'auto', - borderStyle: 'solid', - borderWidth: 1, - borderColor: '#4a90e2', - borderRadius: 3, - }, - tableRow: { - flexDirection: 'row', - borderBottomColor: '#4a90e2', - borderBottomWidth: 1, - alignItems: 'center', - minHeight: 24, - textAlign: 'left', - }, - tableCol: { - width: '25%', - paddingVertical: 5, - paddingHorizontal: 3, - }, - tableCell: { - fontSize: 10, - color: '#333', - }, - tableHeader: { - backgroundColor: '#e6f2ff', - fontWeight: 700, - color: '#4a90e2', - }, - text: { - fontSize: 10, - marginBottom: 3, - color: '#333', - }, - bold: { - fontWeight: 700, - }, - footer: { - position: 'absolute', - bottom: 30, - left: 30, - right: 30, - textAlign: 'center', - fontSize: 8, - color: '#666', - borderTop: '1 solid #4a90e2', - paddingTop: 10, - }, - infoGrid: { - flexDirection: 'row', - justifyContent: 'space-between', - marginBottom: 10, - }, - infoColumn: { - width: '48%', - }, + page: { + fontFamily: "Roboto", + padding: 30, + backgroundColor: "#ffffff", + }, + header: { + flexDirection: "row", + justifyContent: "space-between", + alignItems: "center", + marginBottom: 20, + borderBottom: "2 solid #4a90e2", + paddingBottom: 10, + }, + logo: { + width: 60, + height: 60, + }, + hospitalInfo: { + alignItems: "center", + }, + hospitalName: { + fontSize: 24, + fontWeight: 700, + color: "#4a90e2", + marginBottom: 5, + }, + title: { + fontSize: 18, + fontWeight: 500, + color: "#4a90e2", + }, + section: { + marginBottom: 15, + }, + sectionTitle: { + fontSize: 14, + fontWeight: 700, + color: "#4a90e2", + marginBottom: 5, + textTransform: "uppercase", + }, + table: { + width: "auto", + borderStyle: "solid", + borderWidth: 1, + borderColor: "#4a90e2", + borderRadius: 3, + }, + tableRow: { + flexDirection: "row", + borderBottomColor: "#4a90e2", + borderBottomWidth: 1, + alignItems: "center", + minHeight: 24, + textAlign: "left", + }, + tableCol: { + width: "25%", + paddingVertical: 5, + paddingHorizontal: 3, + }, + tableCell: { + fontSize: 10, + color: "#333", + }, + tableHeader: { + backgroundColor: "#e6f2ff", + fontWeight: 700, + color: "#4a90e2", + }, + text: { + fontSize: 10, + marginBottom: 3, + color: "#333", + }, + bold: { + fontWeight: 700, + }, + footer: { + position: "absolute", + bottom: 30, + left: 30, + right: 30, + textAlign: "center", + fontSize: 8, + color: "#666", + borderTop: "1 solid #4a90e2", + paddingTop: 10, + }, + infoGrid: { + flexDirection: "row", + justifyContent: "space-between", + marginBottom: 10, + }, + infoColumn: { + width: "48%", + }, }); interface PrescriptionPDFProps { - prescription: IPrescription; - doctor: IDoctor; - patient: IPatient; + prescription: IPrescription; + doctor: IDoctor; + patient: IPatient; } const PrescriptionPDF: React.FC = ({ prescription, doctor, patient }) => ( - - - - - AVM Ayurvedic - - - Medical Prescription - - - - - - - Doctor Information - {doctor.name} - Qualifications: {doctor.qualifications?.join(', ')} - Phone: {doctor.phone} - Email: {doctor.email} - - - - - Patient Information - {patient.name} - DOB: {patient.dob ? format(new Date(patient.dob), 'MMMM dd, yyyy') : 'N/A'} - Gender: {patient.gender} - Blood Group: {patient.bloodGroup} - Phone: {patient.phone} - - - - - - Prescription Details - Prescription ID: {prescription._id} - Date: {prescription.createdAt ? format(new Date(prescription.createdAt), 'MMMM dd, yyyy') : 'N/A'} - Status: {prescription.status} - - - - Medications - - - - Medication + + + + + AVM Ayurvedic - - Dosage + + Medical Prescription - - Frequency + + + + + + Doctor Information + {doctor.name} + Qualifications: {doctor.qualifications?.join(", ")} + Phone: {doctor.phone} + Email: {doctor.email} + - - Duration + + + Patient Information + {patient.name} + + DOB: {patient.dob ? format(new Date(patient.dob), "MMMM dd, yyyy") : "N/A"} + + Gender: {patient.gender} + Blood Group: {patient.bloodGroup} + Phone: {patient.phone} + - - {prescription.medications?.map((med, index) => ( - - - {med.name} - - - {med.dosage} - - - {med.frequency} - - - {med.duration} - + + + + Prescription Details + Prescription ID: {prescription._id} + + Date: {prescription.createdAt ? format(new Date(prescription.createdAt), "MMMM dd, yyyy") : "N/A"} + + Status: {prescription.status} + + + + Medications + + + + Medication + + + Dosage + + + Frequency + + + Duration + + + {prescription.medications?.map((med, index) => ( + + + {med.name} + + + {med.dosage} + + + {med.frequency} + + + {med.duration} + + + ))} - ))} - - + - {prescription.medications?.some(med => med.additionalInstructions) && ( - - Additional Instructions - {prescription.medications.map((med, index) => ( - med.additionalInstructions && ( - - {med.name}: - {med.additionalInstructions} - - ) - ))} - - )} + {prescription.medications?.some((med) => med.additionalInstructions) && ( + + Additional Instructions + {prescription.medications.map( + (med, index) => + med.additionalInstructions && ( + + {med.name}: + {med.additionalInstructions} + + ) + )} + + )} - {prescription.notes && ( - - Notes - {prescription.notes} - - )} + {prescription.notes && ( + + Notes + {prescription.notes} + + )} - - This is a digital prescription from AVM Ayurvedic. Please contact your doctor at {doctor.phone} if you have any questions. - Generated on {format(new Date(), 'PPPp')} - - - + + + This is a digital prescription from AVM Ayurvedic. Please contact your doctor at {doctor.phone} if you + have any questions. + + Generated on {format(new Date(), "PPPp")} + + + ); -export default PrescriptionPDF; \ No newline at end of file +export default PrescriptionPDF; diff --git a/client/components/page-components/patient/auth/SignInPageSection.tsx b/client/components/page-components/patient/auth/SignInPageSection.tsx index e99216ca..1b2ad009 100644 --- a/client/components/page-components/patient/auth/SignInPageSection.tsx +++ b/client/components/page-components/patient/auth/SignInPageSection.tsx @@ -65,4 +65,4 @@ const SignFromSection = () => { notFound(); }; -export default SignFromSection; \ No newline at end of file +export default SignFromSection; diff --git a/client/components/page-components/patient/auth/SignUpPageSection.tsx b/client/components/page-components/patient/auth/SignUpPageSection.tsx index caf0ba62..4064afb1 100644 --- a/client/components/page-components/patient/auth/SignUpPageSection.tsx +++ b/client/components/page-components/patient/auth/SignUpPageSection.tsx @@ -56,4 +56,4 @@ const SignUnFormSection = () => { notFound(); }; -export default SignUnFormSection; \ No newline at end of file +export default SignUnFormSection; diff --git a/client/components/page-components/patient/profile/NavSection.tsx b/client/components/page-components/patient/profile/NavSection.tsx index ee5a3a96..ab6152b5 100644 --- a/client/components/page-components/patient/profile/NavSection.tsx +++ b/client/components/page-components/patient/profile/NavSection.tsx @@ -9,61 +9,61 @@ import UploadProfileModel from "@/components/models/patient/UploadProfileModel"; import { ButtonV2 } from "@/components/button/ButtonV2"; interface Props { - setSection: (state: "profile") => void; - patientData: IPatient; - refetch: any; + setSection: (state: "profile") => 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") => { - setSection(path); - }; + const handleClick = (path: "profile") => { + setSection(path); + }; - const handleUploadClick = () => { - setFileModel(!isFileModel); - }; + const handleUploadClick = () => { + setFileModel(!isFileModel); + }; - return ( - -
    - Ayurveda banner -
    -
    -
    - - - {patientData.name!.charAt(0)} - - - Upload - -
    -
    -

    {patientData.name}

    -

    {patientData.phone}

    -
    -
    -
    - -
    - handleClick("profile")} className="flex-1"> - Profile - -
    -
    - - - ); -} \ No newline at end of file + return ( + +
    + Ayurveda banner +
    +
    +
    + + + {patientData.name!.charAt(0)} + + + Upload + +
    +
    +

    {patientData.name}

    +

    {patientData.phone}

    +
    +
    +
    + +
    + handleClick("profile")} className="flex-1"> + Profile + +
    +
    + + + ); +} diff --git a/client/components/page-components/video/JoinVideoCallPage.tsx b/client/components/page-components/video/JoinVideoCallPage.tsx index cb3efb0c..ce8e0807 100644 --- a/client/components/page-components/video/JoinVideoCallPage.tsx +++ b/client/components/page-components/video/JoinVideoCallPage.tsx @@ -1,131 +1,123 @@ -'use client' +"use client"; -import { useState, useEffect, memo } from "react" -import { Card } from "@/components/ui/card" -import { VideoIcon, InfoIcon, ClockIcon, AlertTriangleIcon } from "lucide-react" -import { ButtonV2 } from "@/components/button/ButtonV2" -import { IVideoSection } from "@/types/entities" -import Link from "next/link" -import { notFound } from "next/navigation" -import { format } from "date-fns" +import { useState, useEffect, memo } from "react"; +import { Card } from "@/components/ui/card"; +import { VideoIcon, InfoIcon, ClockIcon, AlertTriangleIcon } from "lucide-react"; +import { ButtonV2 } from "@/components/button/ButtonV2"; +import { IVideoSection } from "@/types/entities"; +import Link from "next/link"; +import { notFound } from "next/navigation"; +import { format } from "date-fns"; -const JoinVideoCallPage = ({ handleStart, section }: { handleStart: () => void, section: IVideoSection }) => { - const [canStartMeeting, setCanStartMeeting] = useState(true) - const [timeRemaining, setTimeRemaining] = useState(null) - const [isEarly, setIsEarly] = useState(false) +const JoinVideoCallPage = ({ handleStart, section }: { handleStart: () => void; section: IVideoSection }) => { + const [canStartMeeting, setCanStartMeeting] = useState(true); + const [timeRemaining, setTimeRemaining] = useState(null); + const [isEarly, setIsEarly] = useState(false); - useEffect(() => { - const now = new Date() - if (section) { - const checkMeetingTime = () => { - const meetingTime = new Date(section.startTime!) - const timeDiff = meetingTime.getTime() - now.getTime() - const minutesDiff = Math.floor(timeDiff / (1000 * 60)) - setCanStartMeeting(minutesDiff <= 10 && minutesDiff >= 0) - setIsEarly(minutesDiff > 10) - - if (minutesDiff > 10) { - const hours = Math.floor(minutesDiff / 60) - const minutes = minutesDiff % 60 - setTimeRemaining(`${hours}h ${minutes}m`) - } else { - setTimeRemaining(null) - } - } + useEffect(() => { + const now = new Date(); + if (section) { + const checkMeetingTime = () => { + const meetingTime = new Date(section.startTime!); + const timeDiff = meetingTime.getTime() - now.getTime(); + const minutesDiff = Math.floor(timeDiff / (1000 * 60)); + setCanStartMeeting(minutesDiff <= 10 && minutesDiff >= 0); + setIsEarly(minutesDiff > 10); - if (section.startTime && section.startTime < new Date(now.getTime() - 1000 * 60 * 60)) { - notFound() - } else { - setCanStartMeeting(true) - } + if (minutesDiff > 10) { + const hours = Math.floor(minutesDiff / 60); + const minutes = minutesDiff % 60; + setTimeRemaining(`${hours}h ${minutes}m`); + } else { + setTimeRemaining(null); + } + }; - checkMeetingTime() - const timer = setInterval(checkMeetingTime, 60000) + if (section.startTime && section.startTime < new Date(now.getTime() - 1000 * 60 * 60)) { + notFound(); + } else { + setCanStartMeeting(true); + } - return () => clearInterval(timer) - } else { - notFound() - } - }, [section]) + checkMeetingTime(); + const timer = setInterval(checkMeetingTime, 60000); + + return () => clearInterval(timer); + } else { + notFound(); + } + }, [section]); - return ( -
    - -
    -
    - -
    -

    {section?.patientName}'s Video Section

    - {canStartMeeting || isEarly ? ( - <> - - {isEarly ? "Join Anyway" : "Start Meeting"} - -

    - {isEarly - ? "The meeting hasn't started yet, but you can join the room early." - : "Click to begin your video consultation with the patient." - } -

    - {isEarly && ( -
    - - - You're joining {timeRemaining} before the scheduled time - -
    - )} - - ) : ( - <> -
    - - - {format(new Date(section.startTime!), "PPPp")} - -
    - {timeRemaining && ( -
    - {timeRemaining} until meeting -
    - )} -
    -
    -
    -

    - The meeting will be available 10 minutes before the scheduled time. -

    - - )} - - - - View Appointment Details - - -
    -
    -
    - ) -} + return ( +
    + +
    +
    + +
    +

    {section?.patientName}'s Video Section

    + {canStartMeeting || isEarly ? ( + <> + + {isEarly ? "Join Anyway" : "Start Meeting"} + +

    + {isEarly + ? "The meeting hasn't started yet, but you can join the room early." + : "Click to begin your video consultation with the patient."} +

    + {isEarly && ( +
    + + + You're joining {timeRemaining} before the scheduled time + +
    + )} + + ) : ( + <> +
    + + {format(new Date(section.startTime!), "PPPp")} +
    + {timeRemaining && ( +
    + {timeRemaining} until meeting +
    + )} +
    +
    +
    +

    + The meeting will be available 10 minutes before the scheduled time. +

    + + )} + + + + View Appointment Details + + +
    +
    +
    + ); +}; -export default memo(JoinVideoCallPage); \ No newline at end of file +export default memo(JoinVideoCallPage); diff --git a/client/components/page-components/video/PatientVideoLayout.tsx b/client/components/page-components/video/PatientVideoLayout.tsx index 7523c9dd..d546333e 100644 --- a/client/components/page-components/video/PatientVideoLayout.tsx +++ b/client/components/page-components/video/PatientVideoLayout.tsx @@ -1,37 +1,33 @@ -'use client' -import { useAuth } from '@/lib/hooks/useAuth'; -import { ReactNode, useEffect, useState } from 'react' -import { notFound } from 'next/navigation'; -import VideoCallSkeleton from '@/components/skeletons/VideoSection'; +"use client"; +import { useAuth } from "@/lib/hooks/useAuth"; +import { ReactNode, useEffect, useState } from "react"; +import { notFound } from "next/navigation"; +import VideoCallSkeleton from "@/components/skeletons/VideoSection"; const PatientVideoLayout = ({ children }: { children: ReactNode }) => { - const [isLoading, setLoading] = useState(true); - const { patientToken } = useAuth(); - const isPatient = !!patientToken; + const [isLoading, setLoading] = useState(true); + const { patientToken } = useAuth(); + const isPatient = !!patientToken; - useEffect(() => { - if (isPatient) { - const timer = setTimeout(() => { - setLoading(false); - }, 0); - return () => clearTimeout(timer); - } else { + useEffect(() => { + if (isPatient) { + const timer = setTimeout(() => { setLoading(false); - } - }, [isPatient]); + }, 0); + return () => clearTimeout(timer); + } else { + setLoading(false); + } + }, [isPatient]); - if (isLoading) { - return - } + if (isLoading) { + return ; + } - if (!isPatient) { - notFound() - } - return ( -
    - {children} -
    - ) -} + if (!isPatient) { + notFound(); + } + return
    {children}
    ; +}; -export default PatientVideoLayout \ No newline at end of file +export default PatientVideoLayout; diff --git a/client/components/page-components/video/VideoChat.tsx b/client/components/page-components/video/VideoChat.tsx index e88842d3..5e9a17ff 100644 --- a/client/components/page-components/video/VideoChat.tsx +++ b/client/components/page-components/video/VideoChat.tsx @@ -1,151 +1,140 @@ -import Image from 'next/image'; -import { useRef, useEffect } from 'react'; +import Image from "next/image"; +import { useRef, useEffect } from "react"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { Button } from "@/components/ui/button"; -import { VideoChatProps } from '@/types'; +import { VideoChatProps } from "@/types"; export default function VideoChat({ - localStream, - remoteStream, - handleEndCall, - toggleMute, - toggleVideo, - isMuted, - isVideoOff, - isDoctor, - selfAvatar, - remoteAvatar, + localStream, + remoteStream, + handleEndCall, + toggleMute, + toggleVideo, + isMuted, + isVideoOff, + isDoctor, + selfAvatar, + remoteAvatar, }: VideoChatProps) { - const localVideoRef = useRef(null); - const remoteVideoRef = useRef(null); + const localVideoRef = useRef(null); + const remoteVideoRef = useRef(null); - useEffect(() => { - if (localVideoRef.current && localStream) { - localVideoRef.current.srcObject = localStream; - } - }, [localStream, isVideoOff]); + useEffect(() => { + if (localVideoRef.current && localStream) { + localVideoRef.current.srcObject = localStream; + } + }, [localStream, isVideoOff]); - useEffect(() => { - if (remoteVideoRef.current && remoteStream) { - remoteVideoRef.current.srcObject = remoteStream; - } - }, [remoteStream]); + useEffect(() => { + if (remoteVideoRef.current && remoteStream) { + remoteVideoRef.current.srcObject = remoteStream; + } + }, [remoteStream]); - return ( -
    - {/* Remote Video */} -
    - {remoteStream ? ( -
    + return ( +
    + {/* Remote Video */} +
    + {remoteStream ? ( +
    -
    - {localStream && !isVideoOff ? ( -
    +
    + {localStream && !isVideoOff ? ( +
    - {/* Control Buttons */} -
    -
    - - - - - - -

    {isMuted ? 'Unmute' : 'Mute'}

    -
    -
    -
    + {/* Control Buttons */} +
    +
    + + + + + + +

    {isMuted ? "Unmute" : "Mute"}

    +
    +
    +
    - - - - - - -

    {isVideoOff ? 'Turn on video' : 'Turn off video'}

    -
    -
    -
    + + + + + + +

    {isVideoOff ? "Turn on video" : "Turn off video"}

    +
    +
    +
    - - - - - - -

    End call

    -
    -
    -
    -
    + + + + + + +

    End call

    +
    +
    +
    +
    +
    -
    - ); + ); } diff --git a/client/components/skeletons/AuthPage.tsx b/client/components/skeletons/AuthPage.tsx index 251ee0dd..884c9f7e 100644 --- a/client/components/skeletons/AuthPage.tsx +++ b/client/components/skeletons/AuthPage.tsx @@ -30,4 +30,4 @@ const AuthSkelton = () => { ); }; -export default memo(AuthSkelton); \ No newline at end of file +export default memo(AuthSkelton); diff --git a/client/components/skeletons/ChatList.tsx b/client/components/skeletons/ChatList.tsx index 8e4f7f39..1bc0ae8f 100644 --- a/client/components/skeletons/ChatList.tsx +++ b/client/components/skeletons/ChatList.tsx @@ -2,29 +2,29 @@ import { Skeleton } from "@/components/ui/skeleton"; import { memo } from "react"; interface ChatListSkeletonProps { - itemCount?: number; + itemCount?: number; } const ChatListSkeletonItem = memo(() => ( -
    - -
    - - -
    -
    +
    + +
    + + +
    +
    )); ChatListSkeletonItem.displayName = "ChatListSkeletonItem"; const ChatListSkeleton = ({ itemCount = 5 }: ChatListSkeletonProps) => { - return ( -
    - {Array.from({ length: itemCount }).map((_, index) => ( - - ))} -
    - ); + return ( +
    + {Array.from({ length: itemCount }).map((_, index) => ( + + ))} +
    + ); }; -export default memo(ChatListSkeleton); \ No newline at end of file +export default memo(ChatListSkeleton); diff --git a/client/components/skeletons/ChatSkelton.tsx b/client/components/skeletons/ChatSkelton.tsx index 881c2edb..0d27f8cc 100644 --- a/client/components/skeletons/ChatSkelton.tsx +++ b/client/components/skeletons/ChatSkelton.tsx @@ -1,61 +1,63 @@ -import { Skeleton } from "@/components/ui/skeleton" +import { Skeleton } from "@/components/ui/skeleton"; import { memo } from "react"; -const ChatLayoutSkeleton= () => { - return ( -
    - -
    -
    -
    -
    - -
    - - -
    +const ChatLayoutSkeleton = () => { + return ( +
    +
    -
    - {[...Array(6)].map((_, i) => ( -
    - {i % 2 === 0 && } -
    - - -
    - {i % 2 !== 0 && } -
    - ))} -
    -
    -
    - - - + +
    +
    +
    +
    + +
    + + +
    +
    +
    +
    + {[...Array(6)].map((_, i) => ( +
    + {i % 2 === 0 && } +
    + + +
    + {i % 2 !== 0 && } +
    + ))} +
    +
    +
    + + + +
    +
    -
    -
    -
    -
    - ) -} + +
    + ); +}; -export default memo(ChatLayoutSkeleton); \ No newline at end of file +export default memo(ChatLayoutSkeleton); diff --git a/client/components/skeletons/Loader.tsx b/client/components/skeletons/Loader.tsx index 463785ce..d0426b09 100644 --- a/client/components/skeletons/Loader.tsx +++ b/client/components/skeletons/Loader.tsx @@ -1,17 +1,12 @@ -import Image from "next/image" +import Image from "next/image"; import { memo } from "react"; const Loading = () => ( -
    -
    - Loading -
    -
    -) +
    +
    + Loading +
    +
    +); -export default memo(Loading); \ No newline at end of file +export default memo(Loading); diff --git a/client/components/skeletons/ProfilePage.tsx b/client/components/skeletons/ProfilePage.tsx index bbc327a2..38ce60b0 100644 --- a/client/components/skeletons/ProfilePage.tsx +++ b/client/components/skeletons/ProfilePage.tsx @@ -2,7 +2,7 @@ import { Skeleton } from "@/components/ui/skeleton"; import { Card, CardContent } from "@/components/ui/card"; import { memo } from "react"; -const ProfileSkeleton =()=> { +const ProfileSkeleton = () => { return (
    @@ -44,5 +44,5 @@ const ProfileSkeleton =()=> {
    ); -} -export default memo(ProfileSkeleton) \ No newline at end of file +}; +export default memo(ProfileSkeleton); diff --git a/client/components/skeletons/Spinner.tsx b/client/components/skeletons/Spinner.tsx index bf3297e9..f91cb176 100644 --- a/client/components/skeletons/Spinner.tsx +++ b/client/components/skeletons/Spinner.tsx @@ -2,54 +2,49 @@ import Image from "next/image"; import { cn } from "@/lib/utils"; import { forwardRef, HTMLAttributes, memo, useMemo } from "react"; -interface SpinnerProps extends Omit, 'color'> { - size?: "sm" | "md" | "lg"; - color?: "primary" | "secondary" | "muted"; +interface SpinnerProps extends Omit, "color"> { + size?: "sm" | "md" | "lg"; + color?: "primary" | "secondary" | "muted"; } -const Spinner = forwardRef(({ - className, - size = "md", - color = "primary", - ...props -}, ref) => { - const colorMap = useMemo(() => ({ - primary: "text-primary", - secondary: "text-secondary", - muted: "text-muted-foreground", - }),[]); - const sizeMap = useMemo(()=>( { - sm: "h-4 w-4", - md: "h-8 w-8", - lg: "h-12 w-12", - }),[]) +const Spinner = forwardRef( + ({ className, size = "md", color = "primary", ...props }, ref) => { + const colorMap = useMemo( + () => ({ + primary: "text-primary", + secondary: "text-secondary", + muted: "text-muted-foreground", + }), + [] + ); + const sizeMap = useMemo( + () => ({ + sm: "h-4 w-4", + md: "h-8 w-8", + lg: "h-12 w-12", + }), + [] + ); - const dimensions = useMemo( - () => parseInt(sizeMap[size].split(' ')[0].replace('h-', '')) * 4, - [size, sizeMap] - ); + const dimensions = useMemo(() => parseInt(sizeMap[size].split(" ")[0].replace("h-", "")) * 4, [size, sizeMap]); - return ( -
    - Loading... -
    - ); -}); + return ( +
    + Loading... +
    + ); + } +); Spinner.displayName = "Spinner"; diff --git a/client/components/skeletons/TableSkelton.tsx b/client/components/skeletons/TableSkelton.tsx index a5a0f6ac..8c87c149 100644 --- a/client/components/skeletons/TableSkelton.tsx +++ b/client/components/skeletons/TableSkelton.tsx @@ -54,4 +54,4 @@ const TableSkeleton = ({ ); }; -export default memo(TableSkeleton); \ No newline at end of file +export default memo(TableSkeleton); diff --git a/client/components/skeletons/Universal.tsx b/client/components/skeletons/Universal.tsx index 4390ca57..afd2d1b7 100644 --- a/client/components/skeletons/Universal.tsx +++ b/client/components/skeletons/Universal.tsx @@ -1,7 +1,7 @@ import { Skeleton } from "@/components/ui/skeleton"; import { memo } from "react"; -const UniversalSkelton = ()=> { +const UniversalSkelton = () => { return (
    @@ -51,6 +51,6 @@ const UniversalSkelton = ()=> {
    ); -} +}; -export default memo(UniversalSkelton) \ No newline at end of file +export default memo(UniversalSkelton); diff --git a/client/components/skeletons/VideoSection.tsx b/client/components/skeletons/VideoSection.tsx index 2b9aa72e..4add4188 100644 --- a/client/components/skeletons/VideoSection.tsx +++ b/client/components/skeletons/VideoSection.tsx @@ -1,17 +1,17 @@ -import React, { memo } from 'react' -import { Card } from "@/components/ui/card" -import { Skeleton } from "@/components/ui/skeleton" +import React, { memo } from "react"; +import { Card } from "@/components/ui/card"; +import { Skeleton } from "@/components/ui/skeleton"; -const VideoCallSkeleton = () =>{ - return ( -
    - - - - - -
    - ) -} +const VideoCallSkeleton = () => { + return ( +
    + + + + + +
    + ); +}; -export default memo(VideoCallSkeleton); \ No newline at end of file +export default memo(VideoCallSkeleton); diff --git a/client/components/ui/alert.tsx b/client/components/ui/alert.tsx index 41fa7e05..ac2c7abf 100644 --- a/client/components/ui/alert.tsx +++ b/client/components/ui/alert.tsx @@ -1,59 +1,43 @@ -import * as React from "react" -import { cva, type VariantProps } from "class-variance-authority" +import * as React from "react"; +import { cva, type VariantProps } from "class-variance-authority"; -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; const alertVariants = cva( - "relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground", - { - variants: { - variant: { - default: "bg-background text-foreground", - destructive: - "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive", + "relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground", + { + variants: { + variant: { + default: "bg-background text-foreground", + destructive: "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive", + }, }, - }, - defaultVariants: { - variant: "default", - }, - } -) + defaultVariants: { + variant: "default", + }, + } +); const Alert = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes & VariantProps + HTMLDivElement, + React.HTMLAttributes & VariantProps >(({ className, variant, ...props }, ref) => ( -
    -)) -Alert.displayName = "Alert" +
    +)); +Alert.displayName = "Alert"; -const AlertTitle = React.forwardRef< - HTMLParagraphElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
    -)) -AlertTitle.displayName = "AlertTitle" +const AlertTitle = React.forwardRef>( + ({ className, ...props }, ref) => ( +
    + ) +); +AlertTitle.displayName = "AlertTitle"; -const AlertDescription = React.forwardRef< - HTMLParagraphElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
    -)) -AlertDescription.displayName = "AlertDescription" +const AlertDescription = React.forwardRef>( + ({ className, ...props }, ref) => ( +
    + ) +); +AlertDescription.displayName = "AlertDescription"; -export { Alert, AlertTitle, AlertDescription } +export { Alert, AlertTitle, AlertDescription }; diff --git a/client/components/ui/avatar.tsx b/client/components/ui/avatar.tsx index 51e507ba..8158e03d 100644 --- a/client/components/ui/avatar.tsx +++ b/client/components/ui/avatar.tsx @@ -1,50 +1,40 @@ -"use client" +"use client"; -import * as React from "react" -import * as AvatarPrimitive from "@radix-ui/react-avatar" +import * as React from "react"; +import * as AvatarPrimitive from "@radix-ui/react-avatar"; -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; const Avatar = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - -)) -Avatar.displayName = AvatarPrimitive.Root.displayName + +)); +Avatar.displayName = AvatarPrimitive.Root.displayName; const AvatarImage = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - -)) -AvatarImage.displayName = AvatarPrimitive.Image.displayName + +)); +AvatarImage.displayName = AvatarPrimitive.Image.displayName; const AvatarFallback = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef + React.ElementRef, + React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( - -)) -AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName + +)); +AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName; -export { Avatar, AvatarImage, AvatarFallback } +export { Avatar, AvatarImage, AvatarFallback }; diff --git a/client/components/ui/breadcrumb.tsx b/client/components/ui/breadcrumb.tsx index 71a5c325..27c0c493 100644 --- a/client/components/ui/breadcrumb.tsx +++ b/client/components/ui/breadcrumb.tsx @@ -1,115 +1,90 @@ -import * as React from "react" -import { Slot } from "@radix-ui/react-slot" -import { ChevronRight, MoreHorizontal } from "lucide-react" +import * as React from "react"; +import { Slot } from "@radix-ui/react-slot"; +import { ChevronRight, MoreHorizontal } from "lucide-react"; -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; const Breadcrumb = React.forwardRef< - HTMLElement, - React.ComponentPropsWithoutRef<"nav"> & { - separator?: React.ReactNode - } ->(({ ...props }, ref) =>