Add notifications API for vaccine reminders

- API endpoint /api/notifications returns due/overdue vaccines
- Checks child's birthDate to calculate due dates
- Returns notifications with type, status, days overdue

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Manohar Gupta 2026-05-16 16:30:14 +05:30
parent 3e54efaf66
commit b93f1f5dcf

View file

@ -0,0 +1,97 @@
import { NextResponse } from "next/server";
import { sql } from "@/db";
// IAP Vaccination Schedule (weeks from birth)
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 },
{ name: "JE-1", weeks: 48 },
{ name: "Vitamin A-1", weeks: 48 },
{ name: "OPV-4", weeks: 48 },
{ name: "MR-2", weeks: 96 },
{ 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 },
{ name: "Tetanus and adult diphtheria (Td)", weeks: 208 },
];
export async function GET(request: Request) {
try {
const { searchParams } = new URL(request.url);
const childId = searchParams.get("childId");
if (!childId) {
return NextResponse.json({ error: "childId required" }, { status: 400 });
}
// Get child's birth date
const children = await sql`
SELECT id, name, birth_date FROM children WHERE id = ${childId}
`;
if (!children || children.length === 0) {
return NextResponse.json({ notifications: [] });
}
const child = children[0];
const birthDate = new Date(child.birth_date);
const today = new Date();
today.setHours(0, 0, 0, 0);
// Get already given vaccines
const given = await sql`
SELECT vaccine_name, given_date FROM vaccinations
WHERE child_id = ${childId} AND status = 'given'
`;
const givenMap = new Set(given.map((v: any) => v.vaccine_name));
// Calculate upcoming vaccine notifications
const notifications = [];
for (const vaccine of IAP_SCHEDULE) {
if (givenMap.has(vaccine.name)) continue;
// Calculate due date
const dueDate = new Date(birthDate);
dueDate.setDate(dueDate.getDate() + vaccine.weeks * 7);
dueDate.setHours(0, 0, 0, 0);
const diffDays = Math.floor((dueDate.getTime() - today.getTime()) / (1000 * 60 * 60 * 24));
// Notify if due today or overdue
if (diffDays <= 0) {
notifications.push({
id: `vaccine-${vaccine.name}`,
type: "vaccine",
title: diffDays === 0 ? "Vaccine Due Today" : "Vaccine Overdue",
message: `${vaccine.name} is ${diffDays === 0 ? "due today" : `${Math.abs(diffDays)} days overdue`}`,
vaccineName: vaccine.name,
dueDate: dueDate.toISOString().split("T")[0],
status: diffDays === 0 ? "due_today" : "overdue",
childId,
childName: child.name,
});
}
}
return NextResponse.json({ notifications });
} catch (error) {
console.error("Notifications error:", error);
return NextResponse.json({ error: String(error) }, { status: 500 });
}
}