Add medical page with IAP vaccination schedule
This commit is contained in:
parent
fa14a22554
commit
0adc609e4b
2 changed files with 157 additions and 2 deletions
152
src/app/medical/page.tsx
Normal file
152
src/app/medical/page.tsx
Normal file
|
|
@ -0,0 +1,152 @@
|
||||||
|
"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>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
const OFFLINE_QUEUE_KEY = "tia_offline_queue";
|
const OFFLINE_QUEUE_KEY = "tia_offline_queue";
|
||||||
|
|
||||||
|
|
@ -246,8 +247,10 @@ export default function HomePage() {
|
||||||
<div className="font-medium mt-2">Diaper</div>
|
<div className="font-medium mt-2">Diaper</div>
|
||||||
</button>
|
</button>
|
||||||
<button className="p-6 bg-white rounded-2xl shadow-md hover:shadow-lg transition text-center">
|
<button className="p-6 bg-white rounded-2xl shadow-md hover:shadow-lg transition text-center">
|
||||||
|
<Link href="/medical">
|
||||||
<div className="text-3xl">💊</div>
|
<div className="text-3xl">💊</div>
|
||||||
<div className="font-medium mt-2">Medical</div>
|
<div className="font-medium mt-2">Medical</div>
|
||||||
|
</Link>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue