diff --git a/backend/src/controllers/appointment.controller.js b/backend/src/controllers/appointment.controller.js index 3984c17..f8e50a5 100644 --- a/backend/src/controllers/appointment.controller.js +++ b/backend/src/controllers/appointment.controller.js @@ -1,10 +1,10 @@ import prisma from "../prisma/client.js"; -import {sendEmail} from "../utils/sendEmail.js"; -import {getEmailsByType} from "../utils/getEmailByTypes.js"; +import { sendEmail } from "../utils/sendEmail.js"; +import { getEmailsByType } from "../utils/getEmailByTypes.js"; export const createAppointment = async (req, res) => { try { - const {name, mobileNumber, email, message, date, doctorId, departmentId} = + const { name, mobileNumber, email, message, date, doctorId, departmentId } = req.body; if (!name || !mobileNumber || !doctorId || !departmentId || !date) { @@ -71,26 +71,49 @@ export const createAppointment = async (req, res) => { export const getAppointments = async (req, res) => { try { - const appointments = await prisma.appointment.findMany({ - include: { - doctor: true, - department: true, - }, - orderBy: { - createdAt: "desc", - }, - }); + const page = parseInt(req.query.page) || 1; + const limit = parseInt(req.query.limit) || 10; + const skip = (page - 1) * limit; + const { date, search } = req.query; + + const where = {}; + + if (date) { + const start = new Date(date); + const end = new Date(date); + end.setDate(end.getDate() + 1); + where.date = { gte: start, lt: end }; + } + + if (search) { + where.OR = [ + { name: { contains: search, mode: "insensitive" } }, + { mobileNumber: { contains: search } }, + { email: { contains: search, mode: "insensitive" } }, + ]; + } + + const [appointments, total] = await Promise.all([ + prisma.appointment.findMany({ + where, + include: { doctor: true, department: true }, + orderBy: { createdAt: "desc" }, + skip, + take: limit, + }), + prisma.appointment.count({ where }), + ]); res.status(200).json({ success: true, data: appointments, + pagination: { total, page, limit, totalPages: Math.ceil(total / limit) }, }); } catch (error) { console.error(error); - res.status(500).json({ - success: false, - message: "Failed to fetch appointments", - }); + res + .status(500) + .json({ success: false, message: "Failed to fetch appointments" }); } }; @@ -98,7 +121,7 @@ export const getAppointments = async (req, res) => { export const getAppointment = async (req, res) => { try { - const {id} = req.params; + const { id } = req.params; const appointment = await prisma.appointment.findUnique({ where: { @@ -134,7 +157,7 @@ export const getAppointment = async (req, res) => { export const getAppointmentsByDoctor = async (req, res) => { try { - const {doctorId} = req.params; + const { doctorId } = req.params; const appointments = await prisma.appointment.findMany({ where: { @@ -166,7 +189,7 @@ export const getAppointmentsByDoctor = async (req, res) => { export const getAppointmentsByDepartment = async (req, res) => { try { - const {departmentId} = req.params; + const { departmentId } = req.params; const appointments = await prisma.appointment.findMany({ where: { @@ -195,7 +218,7 @@ export const getAppointmentsByDepartment = async (req, res) => { export const updateAppointment = async (req, res) => { try { - const {id} = req.params; + const { id } = req.params; const appointment = await prisma.appointment.update({ where: { @@ -226,7 +249,7 @@ export const updateAppointment = async (req, res) => { export const deleteAppointment = async (req, res) => { try { - const {id} = req.params; + const { id } = req.params; await prisma.appointment.delete({ where: { diff --git a/frontend/src/api/appointment.ts b/frontend/src/api/appointment.ts index c8ce146..5a7d90e 100644 --- a/frontend/src/api/appointment.ts +++ b/frontend/src/api/appointment.ts @@ -1,7 +1,18 @@ import apiClient from "@/api/client"; -export const getAppointmentsApi = async () => { - const res = await apiClient.get("/appointments/getall"); +export const getAppointmentsApi = async ( + page = 1, + limit = 10, + date = "", + search = "", +) => { + const params = new URLSearchParams({ + page: String(page), + limit: String(limit), + ...(date && { date }), + ...(search && { search }), + }); + const res = await apiClient.get(`/appointments/getall?${params}`); return res.data; }; diff --git a/frontend/src/pages/Appointment.tsx b/frontend/src/pages/Appointment.tsx index 0ed6b7c..5863afd 100644 --- a/frontend/src/pages/Appointment.tsx +++ b/frontend/src/pages/Appointment.tsx @@ -45,52 +45,46 @@ export default function AppointmentPage() { const [viewData, setViewData] = useState(null); const [currentPage, setCurrentPage] = useState(1); - const itemsPerPage = 10; + const [totalPages, setTotalPages] = useState(1); + const [totalItems, setTotalItems] = useState(0); + const [itemsPerPage, setItemsPerPage] = useState(10); const fetchAll = useCallback(async () => { setLoading(true); try { - const res = await getAppointmentsApi(); + const res = await getAppointmentsApi( + currentPage, + itemsPerPage, + filterDate, + searchText, + ); setAppointments(res?.data || []); + setTotalPages(res?.pagination?.totalPages || 1); + setTotalItems(res?.pagination?.total || 0); } catch (err) { console.error(err); } finally { setLoading(false); } - }, []); + }, [currentPage, itemsPerPage, filterDate, searchText]); useEffect(() => { fetchAll(); }, [fetchAll]); const filteredAppointments = appointments.filter((item) => { - const matchesSearch = - item.name?.toLowerCase().includes(searchText.toLowerCase()) || - item.mobileNumber?.includes(searchText) || - item.email?.toLowerCase().includes(searchText.toLowerCase()); - const matchesDoctor = filterDoctor ? item.doctor?.name?.toLowerCase().includes(filterDoctor.toLowerCase()) : true; - const matchesDate = filterDate - ? new Date(item.date).toISOString().split("T")[0] === filterDate - : true; - - return matchesSearch && matchesDoctor && matchesDate; + return matchesDoctor; }); useEffect(() => { setCurrentPage(1); }, [searchText, filterDoctor, filterDate]); - const totalPages = Math.ceil(filteredAppointments.length / itemsPerPage); - const indexOfLastItem = currentPage * itemsPerPage; - const indexOfFirstItem = indexOfLastItem - itemsPerPage; - const currentItems = filteredAppointments.slice( - indexOfFirstItem, - indexOfLastItem, - ); + const indexOfFirstItem = (currentPage - 1) * itemsPerPage; function openView(item: any) { setViewData(item); @@ -126,17 +120,36 @@ export default function AppointmentPage() { setSearchText(e.target.value)} + onChange={(e) => { + setSearchText(e.target.value); + setCurrentPage(1); + }} className="w-[220px] text-base" /> setFilterDate(e.target.value)} + onChange={(e) => { + setFilterDate(e.target.value); + setCurrentPage(1); + }} className="w-[160px] text-base" /> + +