import { useState, useEffect, useCallback } from "react"; import { AxiosError } from "axios"; import { BytescaleUploader } from "@/components/BytescaleUploader/BytescaleUploader"; import { getDoctorsApi, createDoctorApi, updateDoctorApi, deleteDoctorApi, getDoctorTimingApi, } from "@/api/doctor"; import { getDepartmentsApi } from "@/api/department"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { Badge } from "@/components/ui/badge"; import { Loader2, RefreshCw, Plus, Pencil, Trash, ChevronLeft, ChevronRight, User, } from "lucide-react"; interface Department { departmentId: string; name: string; } const DAYS = [ "monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday", "additional", ]; export default function DoctorPage() { const [doctors, setDoctors] = useState([]); const [departments, setDepartments] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(""); const [openModal, setOpenModal] = useState(false); const [editing, setEditing] = useState(null); const [searchText, setSearchText] = useState(""); const [filterDepartment, setFilterDepartment] = useState(""); const [currentPage, setCurrentPage] = useState(1); const itemsPerPage = 10; const [form, setForm] = useState({ doctorId: "", name: "", image: "", designation: "", workingStatus: "", qualification: "", departments: [], }); const fetchAll = useCallback(async () => { setLoading(true); setError(""); try { const [docRes, depRes] = await Promise.all([ getDoctorsApi(), getDepartmentsApi(), ]); setDoctors(docRes?.data || []); setDepartments(depRes?.data || []); } catch (err) { if (err instanceof AxiosError) { setError(err.response?.data?.message || "Failed to load data"); } else { setError("Something went wrong"); } } finally { setLoading(false); } }, []); useEffect(() => { fetchAll(); }, [fetchAll]); const filteredDoctors = doctors.filter((doc) => { const matchesSearch = doc.name.toLowerCase().includes(searchText.toLowerCase()) || doc.doctorId.toLowerCase().includes(searchText.toLowerCase()); const matchesDepartment = filterDepartment ? doc.departments?.some((d: any) => d.departmentId === filterDepartment) : true; return matchesSearch && matchesDepartment; }); useEffect(() => { setCurrentPage(1); }, [searchText, filterDepartment]); const totalPages = Math.ceil(filteredDoctors.length / itemsPerPage); const indexOfLastItem = currentPage * itemsPerPage; const indexOfFirstItem = indexOfLastItem - itemsPerPage; const currentItems = filteredDoctors.slice(indexOfFirstItem, indexOfLastItem); function handleChange(e: any) { setForm({ ...form, [e.target.name]: e.target.value }); } function handleDepartmentToggle(depId: string) { const exists = form.departments.find((d: any) => d.departmentId === depId); if (exists) { setForm({ ...form, departments: form.departments.filter( (d: any) => d.departmentId !== depId, ), }); } else { setForm({ ...form, departments: [...form.departments, { departmentId: depId, timing: {} }], }); } } function handleTimingChange(depId: string, day: string, value: string) { setForm({ ...form, departments: form.departments.map((d: any) => d.departmentId === depId ? { ...d, timing: { ...d.timing, [day]: value } } : d, ), }); } function openAdd() { setEditing(null); setForm({ doctorId: "", name: "", image: "", designation: "", workingStatus: "", qualification: "", departments: [], }); setOpenModal(true); } async function openEdit(doc: any) { setEditing(doc); try { const timingRes = await getDoctorTimingApi(doc.doctorId); const timingData = timingRes?.data?.departments || []; setForm({ doctorId: doc.doctorId, name: doc.name, image: doc.image || "", designation: doc.designation, workingStatus: doc.workingStatus, qualification: doc.qualification, departments: timingData.map((d: any) => ({ departmentId: d.departmentId, timing: d.timing || {}, })), }); setOpenModal(true); } catch (err) { console.error(err); } } async function handleSubmit() { try { if (editing) { await updateDoctorApi(editing.doctorId, form); } else { await createDoctorApi(form); } setOpenModal(false); fetchAll(); } catch (error) { console.error(error); } } async function handleDelete(id: string) { if (!confirm("Delete this doctor?")) return; try { await deleteDoctorApi(id); fetchAll(); } catch (error) { console.error(error); } } return (

Doctors

setSearchText(e.target.value)} className="w-[250px] text-base" />
{error && (
{error}
)} Doctor List
ID Name Designation Qualification Departments Actions {loading ? ( ) : currentItems.length === 0 ? ( No doctors found ) : ( currentItems.map((doc) => ( {doc.doctorId}
{doc.name}
{doc.workingStatus}
{doc.designation || "-"}
{doc.qualification || "-"}
{doc.departments?.map((d: any) => ( {d.departmentName} ))} {doc.departments?.length === 0 && ( - )}
)) )}
{!loading && filteredDoctors.length > 0 && (
Showing{" "} {indexOfFirstItem + 1} to{" "} {Math.min(indexOfLastItem, filteredDoctors.length)} {" "} of{" "} {filteredDoctors.length}{" "} doctors
Page {currentPage} of {totalPages}
)}
{editing ? "Edit Doctor" : "Add Doctor"}

Basic Information

setForm({ ...form, image: url })} />

Assign Departments

{departments.map((dep) => { const isSelected = form.departments.some( (d: any) => d.departmentId === dep.departmentId, ); return ( ); })}

Working Hours / Timing

{form.departments.length === 0 ? (
Select a department to configure timing slots
) : (
{form.departments.map((dep: any) => { const depName = departments.find( (d) => d.departmentId === dep.departmentId, )?.name; return (

{depName}

Timing Slot
{DAYS.map((day) => (
handleTimingChange( dep.departmentId, day, e.target.value, ) } />
))}
); })}
)}
); }