diff --git a/src/app/api/growth/route.ts b/src/app/api/growth/route.ts new file mode 100644 index 0000000..bf1496b --- /dev/null +++ b/src/app/api/growth/route.ts @@ -0,0 +1,54 @@ +import { NextResponse } from "next/server"; +import { sql } from "@/db"; + +interface GrowthEntry { + childId: string; + measuredAt: string; + weightKg?: number; + heightCm?: number; + headCircumferenceCm?: number; + notes?: string; +} + +export async function POST(request: Request) { + try { + const body: GrowthEntry = await request.json(); + const { childId, measuredAt, weightKg, heightCm, headCircumferenceCm, notes } = body; + + if (!childId || !measuredAt) { + return NextResponse.json({ error: "Missing required fields" }, { status: 400 }); + } + + await sql.unsafe( + `INSERT INTO growth (child_id, measured_at, weight_kg, height_cm, head_circumference_cm, notes) + VALUES ($1, $2, $3, $4, $5, $6)`, + [childId, new Date(measuredAt), weightKg || null, heightCm || null, headCircumferenceCm || null, notes || null] + ); + + return NextResponse.json({ success: true }); + } catch (error) { + console.error(error); + return NextResponse.json({ error: String(error) }, { status: 500 }); + } +} + +export async function GET(request: Request) { + const { searchParams } = new URL(request.url); + const childId = searchParams.get("childId"); + + if (!childId) { + return NextResponse.json({ error: "childId required" }, { status: 400 }); + } + + try { + const growth = await sql.unsafe( + `SELECT * FROM growth WHERE child_id = $1 ORDER BY measured_at DESC`, + [childId] + ); + + return NextResponse.json({ growth }); + } catch (error) { + console.error(error); + return NextResponse.json({ error: String(error) }, { status: 500 }); + } +} \ No newline at end of file diff --git a/src/app/api/logs/route.ts b/src/app/api/logs/route.ts new file mode 100644 index 0000000..0b1b61e --- /dev/null +++ b/src/app/api/logs/route.ts @@ -0,0 +1,89 @@ +import { NextResponse } from "next/server"; +import { sql } from "@/db"; + +interface LogEntry { + type: "feed" | "diaper" | "sleep"; + childId: string; + subType: string; + amountMl?: number; + notes?: string; + startedAt?: string; + endedAt?: string; +} + +export async function POST(request: Request) { + try { + const body: LogEntry = await request.json(); + const { type, childId, subType, amountMl, notes, startedAt, endedAt } = body; + + if (!type || !childId || !subType) { + return NextResponse.json({ error: "Missing required fields" }, { status: 400 }); + } + + const now = new Date(); + + if (type === "feed") { + await sql.unsafe( + `INSERT INTO feeds (child_id, type, method, amount_ml, notes, logged_at) VALUES ($1, $2, $3, $4, $5, $6)`, + [childId, subType, subType.includes("breast") ? subType : "bottle", amountMl || null, notes || null, now] + ); + } else if (type === "diaper") { + await sql.unsafe( + `INSERT INTO diapers_logs (child_id, type, notes, logged_at) VALUES ($1, $2, $3, $4)`, + [childId, subType, notes || null, now] + ); + } else if (type === "sleep") { + const startTime = startedAt ? new Date(startedAt) : now; + const endTime = endedAt ? new Date(endedAt) : null; + const durationMinutes = endTime + ? Math.round((endTime.getTime() - startTime.getTime()) / 60000) + : null; + + await sql.unsafe( + `INSERT INTO sleeps (child_id, type, started_at, ended_at, duration_minutes, notes, logged_at) VALUES ($1, $2, $3, $4, $5, $6, $7)`, + [childId, subType, startTime, endTime, durationMinutes, notes || null, now] + ); + } + + return NextResponse.json({ success: true }); + } catch (error) { + console.error(error); + return NextResponse.json({ error: String(error) }, { status: 500 }); + } +} + +export async function GET(request: Request) { + const { searchParams } = new URL(request.url); + const childId = searchParams.get("childId"); + const type = searchParams.get("type"); + const limit = parseInt(searchParams.get("limit") || "20"); + + if (!childId || !type) { + return NextResponse.json({ error: "childId and type required" }, { status: 400 }); + } + + try { + let results: any[] = []; + if (type === "feed") { + results = await sql.unsafe( + `SELECT * FROM feeds WHERE child_id = $1 ORDER BY logged_at DESC LIMIT $2`, + [childId, limit] + ); + } else if (type === "diaper") { + results = await sql.unsafe( + `SELECT * FROM diapers_logs WHERE child_id = $1 ORDER BY logged_at DESC LIMIT $2`, + [childId, limit] + ); + } else if (type === "sleep") { + results = await sql.unsafe( + `SELECT * FROM sleeps WHERE child_id = $1 ORDER BY logged_at DESC LIMIT $2`, + [childId, limit] + ); + } + + return NextResponse.json({ entries: results || [] }); + } catch (error) { + console.error(error); + return NextResponse.json({ error: String(error) }, { status: 500 }); + } +} \ No newline at end of file diff --git a/src/app/api/vaccinations/route.ts b/src/app/api/vaccinations/route.ts new file mode 100644 index 0000000..095f2ec --- /dev/null +++ b/src/app/api/vaccinations/route.ts @@ -0,0 +1,56 @@ +import { NextResponse } from "next/server"; +import { sql } from "@/db"; + +interface VaccinationEntry { + childId: string; + vaccineName: string; + scheduledDate: string; + givenDate?: string; + status?: "pending" | "given" | "skipped" | "delayed"; + provider?: string; + lotNumber?: string; + notes?: string; +} + +export async function POST(request: Request) { + try { + const body: VaccinationEntry = await request.json(); + const { childId, vaccineName, scheduledDate, givenDate, status, provider, lotNumber, notes } = body; + + if (!childId || !vaccineName || !scheduledDate) { + return NextResponse.json({ error: "Missing required fields" }, { status: 400 }); + } + + await sql.unsafe( + `INSERT INTO vaccinations (child_id, vaccine_name, scheduled_date, given_date, status, provider, lot_number, notes) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`, + [childId, vaccineName, scheduledDate, givenDate || null, status || "pending", provider || null, lotNumber || null, notes || null] + ); + + return NextResponse.json({ success: true }); + } catch (error) { + console.error(error); + return NextResponse.json({ error: String(error) }, { status: 500 }); + } +} + +export async function GET(request: Request) { + const { searchParams } = new URL(request.url); + const childId = searchParams.get("childId"); + + if (!childId) { + return NextResponse.json({ error: "childId required" }, { status: 400 }); + } + + try { + const vaccinations = await sql.unsafe( + `SELECT * FROM vaccinations WHERE child_id = $1 ORDER BY scheduled_date ASC`, + [childId] + ); + + return NextResponse.json({ vaccinations }); + } catch (error) { + console.error(error); + return NextResponse.json({ error: String(error) }, { status: 500 }); + } +} \ No newline at end of file