import { NextRequest, NextResponse } from "next/server"; import { requireFamily } from "@/lib/auth"; import { sql } from "@/db"; import { GARMENT_CATEGORIES } from "@/db/schema/wardrobe"; // GET /api/garments?childId=&status=active&category=&sizeLabel=&season= export async function GET(req: NextRequest) { const auth = await requireFamily(); if (!auth.success) return NextResponse.json({ error: auth.error }, { status: auth.status }); const familyId = auth.session!.familyId!; const { searchParams } = new URL(req.url); const childId = searchParams.get("childId"); const status = searchParams.get("status") || "active"; const category = searchParams.get("category"); const sizeLabel = searchParams.get("sizeLabel"); const season = searchParams.get("season"); if (!childId) return NextResponse.json({ error: "childId required" }, { status: 400 }); // Build filter conditions using raw SQL for array contains let rows; if (category && sizeLabel && season) { rows = await sql` SELECT * FROM garments WHERE family_id = ${familyId} AND child_id = ${childId} AND status = ${status} AND category = ${category} AND size_label = ${sizeLabel} AND ${season} = ANY(seasons) ORDER BY created_at DESC`; } else if (category && sizeLabel) { rows = await sql` SELECT * FROM garments WHERE family_id = ${familyId} AND child_id = ${childId} AND status = ${status} AND category = ${category} AND size_label = ${sizeLabel} ORDER BY created_at DESC`; } else if (category && season) { rows = await sql` SELECT * FROM garments WHERE family_id = ${familyId} AND child_id = ${childId} AND status = ${status} AND category = ${category} AND ${season} = ANY(seasons) ORDER BY created_at DESC`; } else if (sizeLabel && season) { rows = await sql` SELECT * FROM garments WHERE family_id = ${familyId} AND child_id = ${childId} AND status = ${status} AND size_label = ${sizeLabel} AND ${season} = ANY(seasons) ORDER BY created_at DESC`; } else if (category) { rows = await sql` SELECT * FROM garments WHERE family_id = ${familyId} AND child_id = ${childId} AND status = ${status} AND category = ${category} ORDER BY created_at DESC`; } else if (sizeLabel) { rows = await sql` SELECT * FROM garments WHERE family_id = ${familyId} AND child_id = ${childId} AND status = ${status} AND size_label = ${sizeLabel} ORDER BY created_at DESC`; } else if (season) { rows = await sql` SELECT * FROM garments WHERE family_id = ${familyId} AND child_id = ${childId} AND status = ${status} AND ${season} = ANY(seasons) ORDER BY created_at DESC`; } else { rows = await sql` SELECT * FROM garments WHERE family_id = ${familyId} AND child_id = ${childId} AND status = ${status} ORDER BY created_at DESC`; } const baseUrl = process.env.R2_PUBLIC_URL || `https://pub-${process.env.R2_ACCOUNT_ID}.r2.dev`; return NextResponse.json({ success: true, items: rows.map(g => toDto(g, baseUrl)), }); } // POST /api/garments export async function POST(req: NextRequest) { const auth = await requireFamily(); if (!auth.success) return NextResponse.json({ error: auth.error }, { status: auth.status }); const familyId = auth.session!.familyId!; let body: { childId?: string; name?: string; category?: string; sizeLabel?: string; colors?: string[]; seasons?: string[]; occasionTags?: string[]; imageKey?: string; thumbKey?: string; status?: string; acquiredVia?: string; giftFrom?: string; visionMetadata?: unknown; }; try { body = await req.json(); } catch { return NextResponse.json({ error: "Invalid JSON" }, { status: 400 }); } const { childId, name, category, sizeLabel, colors = [], seasons = [], occasionTags = [], imageKey, thumbKey, acquiredVia, giftFrom, visionMetadata } = body; if (!childId || !category || !sizeLabel || !imageKey || !thumbKey) { return NextResponse.json({ error: "childId, category, sizeLabel, imageKey, thumbKey required" }, { status: 400 }); } if (!GARMENT_CATEGORIES.includes(category as never)) { return NextResponse.json({ error: "Invalid category" }, { status: 400 }); } // Verify child belongs to family const childCheck = await sql`SELECT id FROM children WHERE id = ${childId} AND family_id = ${familyId} LIMIT 1`; if (!childCheck[0]) return NextResponse.json({ error: "Child not found" }, { status: 404 }); const rows = await sql` INSERT INTO garments (family_id, child_id, name, category, size_label, colors, seasons, occasion_tags, image_key, thumb_key, status, acquired_via, gift_from, vision_metadata) VALUES (${familyId}, ${childId}, ${name || null}, ${category}, ${sizeLabel}, ${colors}, ${seasons}, ${occasionTags}, ${imageKey}, ${thumbKey}, 'active', ${acquiredVia || null}, ${giftFrom || null}, ${visionMetadata ? JSON.stringify(visionMetadata) : null}) RETURNING *`; const baseUrl = process.env.R2_PUBLIC_URL || `https://pub-${process.env.R2_ACCOUNT_ID}.r2.dev`; return NextResponse.json({ success: true, item: toDto(rows[0], baseUrl) }, { status: 201 }); } function toDto(g: Record, baseUrl: string) { return { id: g.id, familyId: g.family_id, childId: g.child_id, name: g.name, category: g.category, sizeLabel: g.size_label, colors: g.colors || [], seasons: g.seasons || [], occasionTags: g.occasion_tags || [], imageKey: g.image_key, thumbKey: g.thumb_key, imageUrl: `${baseUrl}/${g.image_key}`, thumbUrl: `${baseUrl}/${g.thumb_key}`, status: g.status, acquiredVia: g.acquired_via, giftFrom: g.gift_from, createdAt: g.created_at, updatedAt: g.updated_at, }; }