tia/src/app/medical/page.tsx

152 lines
No EOL
5.3 KiB
TypeScript

"use client";
import { useState, useEffect } from "react";
// IAP Vaccination Schedule (India)
const IAP_SCHEDULE = [
{ name: "BCG", weeks: 0 },
{ name: "OPV-0", weeks: 0 },
{ name: "HepB-1", weeks: 0 },
{ name: "OPV-1", weeks: 6 },
{ name: "Pentavalent-1", weeks: 6 },
{ name: "PCV-1", weeks: 6 },
{ name: "Rota-1", weeks: 6 },
{ name: "OPV-2", weeks: 10 },
{ name: "Pentavalent-2", weeks: 10 },
{ name: "PCV-2", weeks: 10 },
{ name: "Rota-2", weeks: 10 },
{ name: "OPV-3", weeks: 14 },
{ name: "Pentavalent-3", weeks: 14 },
{ name: "PCV-3", weeks: 14 },
{ name: "Rota-3", weeks: 14 },
{ name: "MR-1", weeks: 48 }, // 9 months
{ name: "JE-1", weeks: 48 },
{ name: "Vitamin A-1", weeks: 48 },
{ name: "OPV-4", weeks: 48 },
{ name: "MR-2", weeks: 96 }, // 18 months
{ name: "JE-2", weeks: 96 },
{ name: "DPT-Booster-1", weeks: 96 },
{ name: "Vitamin A-2", weeks: 96 },
{ name: "OPV-5", weeks: 96 },
{ name: "DPT-Booster-2", weeks: 208 }, // 4 years
{ name: "TT/Td", weeks: 208 },
];
function calculateDueDate(birthDate: string, weeks: number): string {
const birth = new Date(birthDate);
birth.setDate(birth.getDate() + weeks * 7);
return birth.toISOString().split("T")[0];
}
export default function MedicalPage() {
const [childId] = useState("5ad3b16a-1e0d-45ab-bc91-038397d75d0a");
const [vaccinations, setVaccinations] = useState<any[]>([]);
const [loading, setLoading] = useState(true);
const [tab, setTab] = useState<"vaccinations" | "growth">("vaccinations");
const birthDate = "2024-01-15";
useEffect(() => {
fetch(`/api/vaccinations?childId=${childId}`)
.then((res) => res.json())
.then((data) => {
setVaccinations(data.vaccinations || []);
setLoading(false);
})
.catch(() => setLoading(false));
}, [childId]);
const handleMarkGiven = async (vaccineName: string) => {
const dueDate = calculateDueDate(birthDate, IAP_SCHEDULE.find((v) => v.name === vaccineName)?.weeks || 0);
await fetch("/api/vaccinations", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
childId,
vaccineName,
scheduledDate: dueDate,
givenDate: new Date().toISOString().split("T")[0],
status: "given",
}),
});
setVaccinations((prev) => [...prev, { vaccine_name: vaccineName, status: "given" }]);
};
const isGiven = (name: string) => vaccinations.some((v) => v.vaccine_name === name && v.status === "given");
const isPending = (name: string) => !isGiven(name);
return (
<div className="min-h-screen bg-gradient-to-br from-rose-50 to-amber-50">
<div className="container mx-auto px-4 py-8">
<div className="flex justify-between items-center mb-6">
<h1 className="text-2xl font-bold">Medical 💊</h1>
<a href="/" className="text-rose-500"> Home</a>
</div>
<div className="flex gap-2 mb-6">
<button
onClick={() => setTab("vaccinations")}
className={`flex-1 p-3 rounded-xl ${tab === "vaccinations" ? "bg-rose-400 text-white" : "bg-white"}`}
>
Vaccinations
</button>
<button
onClick={() => setTab("growth")}
className={`flex-1 p-3 rounded-xl ${tab === "growth" ? "bg-rose-400 text-white" : "bg-white"}`}
>
Growth
</button>
</div>
{tab === "vaccinations" && (
<div className="space-y-2">
<h2 className="font-semibold mb-3">IAP Schedule</h2>
{loading ? (
<p className="text-gray-500">Loading...</p>
) : (
IAP_SCHEDULE.filter((v) => isPending(v.name) || isGiven(v.name))
.sort((a, b) => a.weeks - b.weeks)
.map((vaccine) => {
const given = isGiven(vaccine.name);
const dueDate = calculateDueDate(birthDate, vaccine.weeks);
return (
<div
key={vaccine.name}
className={`flex items-center justify-between p-4 bg-white rounded-xl ${given ? "opacity-60" : ""}`}
>
<div>
<div className="font-medium">{vaccine.name}</div>
<div className="text-sm text-gray-500">
Due: {new Date(dueDate).toLocaleDateString()}
</div>
</div>
{given ? (
<span className="text-green-500"> Given</span>
) : (
<button
onClick={() => handleMarkGiven(vaccine.name)}
className="px-4 py-2 bg-rose-400 text-white rounded-lg text-sm"
>
Mark Given
</button>
)}
</div>
);
})
)}
</div>
)}
{tab === "growth" && (
<div className="text-center py-8">
<p className="text-gray-500 mb-4">Growth tracking coming soon</p>
<p className="text-sm text-gray-400">Track weight, height, head circumference</p>
</div>
)}
</div>
</div>
);
}