From 3e54efaf66251eecc0b41bfc729e1d1ba3cb6d59 Mon Sep 17 00:00:00 2001 From: Mannu Date: Sat, 16 May 2026 16:29:33 +0530 Subject: [PATCH] Add vaccine tabs: Completed/Upcoming/Overdue with days overdue display - Calculate schedule from child's DOB - Add tab navigation for vaccines - Show days overdue for missed vaccines - Visual indicators (opacity for completed, red border for overdue) Co-Authored-By: Claude Opus 4.7 --- src/app/medical/page.tsx | 60 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 4 deletions(-) diff --git a/src/app/medical/page.tsx b/src/app/medical/page.tsx index ae653ea..fca4728 100644 --- a/src/app/medical/page.tsx +++ b/src/app/medical/page.tsx @@ -75,6 +75,7 @@ export default function MedicalPage() { const [loading, setLoading] = useState(true); const { childId: sessionChildId, child, loading: loadingChild } = useFamily(); const [tab, setTab] = useState<"vaccinations" | "medicine" | "allergies" | "visits" | "illness">("vaccinations"); + const [vaccineTab, setVaccineTab] = useState<"upcoming" | "completed" | "overdue">("upcoming"); const [showAddDate, setShowAddDate] = useState(null); const [givenDate, setGivenDate] = useState(""); @@ -407,6 +408,33 @@ const SUPPLEMENTS = [ const getGivenDate = (name: string) => vaccinations.find((v) => v.vaccine_name === name && v.status === "given")?.given_date; const isPending = (name: string) => !isGiven(name); + // Get vaccines by status + const getVaccinesByStatus = (status: "upcoming" | "completed" | "overdue") => { + const today = new Date(); + const todayStr = today.toISOString().split("T")[0]; + + return IAP_SCHEDULE.filter((v) => { + const dueDate = calculateDueDate(birthDate, v.weeks); + const given = isGiven(v.name); + + if (status === "completed") return given; + if (status === "overdue") return !given && dueDate < todayStr; + if (status === "upcoming") return !given && dueDate >= todayStr; + return false; + }).sort((a, b) => a.weeks - b.weeks); + }; + + const getVaccineStatus = (name: string) => { + const dueDate = calculateDueDate(birthDate, IAP_SCHEDULE.find((v) => v.name === name)?.weeks || 0); + const today = new Date(); + const todayStr = today.toISOString().split("T")[0]; + const given = isGiven(name); + + if (given) return "completed"; + if (dueDate < todayStr) return "overdue"; + return "upcoming"; + }; + return (
@@ -450,21 +478,42 @@ const SUPPLEMENTS = [ {tab === "vaccinations" && (
+
+ + + +
+

IAP Schedule

{loading ? (

Loading...

) : ( - IAP_SCHEDULE.filter((v) => isPending(v.name) || isGiven(v.name)) - .sort((a, b) => a.weeks - b.weeks) - .map((vaccine) => { + getVaccinesByStatus(vaccineTab).map((vaccine) => { const given = isGiven(vaccine.name); const actualDate = getGivenDate(vaccine.name); const dueDate = calculateDueDate(birthDate, vaccine.weeks); + const status = getVaccineStatus(vaccine.name); + const daysOverdue = status === "overdue" ? Math.floor((new Date().getTime() - new Date(dueDate).getTime()) / (1000 * 60 * 60 * 24)) : 0; return (
@@ -473,6 +522,9 @@ const SUPPLEMENTS = [ Due: {new Date(dueDate).toLocaleDateString()} {actualDate && ` · Given: ${new Date(actualDate).toLocaleDateString()}`}
+ {status === "overdue" && ( +
{daysOverdue} days overdue
+ )}
{given ? (