G1 — Design System: 14 UI primitives (Button, Card, Modal, Sheet, Input, Textarea, Select, EmptyState, LoadingShimmer, ConfirmDialog, WashiTape, Badge, Avatar, Tabs), PageTransition with Framer Motion, sun/moon CSS vars, Caveat font, /dev/components visual showcase. G2 — Memories Pipeline: R2 presigned uploads, Sharp thumbnail generation, LiteLLM vision captions + pgvector embeddings, CSS masonry gallery with infinite scroll, private toggle, semantic search fallback to ILIKE. G3 — Medical: dose log + correction audit trail, IAP vaccine bulk import, emergency escalation page, pediatrician phone in settings. G4 — AI Brain: keyword guardrail → LLM classifier → structured DB tool-use (7 tools) → memory search → general parenting handler; ai_usage table; 22-case medical bypass safety test suite. DB migrations: 0011_memories, 0012_medical_doses, 0013_ai_usage. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
83 lines
4.1 KiB
TypeScript
83 lines
4.1 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useEffect } from "react";
|
|
import Link from "next/link";
|
|
import { ESCALATION_RULES } from "@/lib/ai/medical-triggers";
|
|
|
|
const RULE_META: Record<string, { icon: string; title: string; color: string }> = {
|
|
fever: { icon: "🌡️", title: "Fever", color: "bg-orange-50 dark:bg-orange-900/20 border-orange-200 dark:border-orange-800" },
|
|
breathing: { icon: "💨", title: "Breathing Issues", color: "bg-blue-50 dark:bg-blue-900/20 border-blue-200 dark:border-blue-800" },
|
|
feeding: { icon: "🍼", title: "Feeding / Diapers", color: "bg-yellow-50 dark:bg-yellow-900/20 border-yellow-200 dark:border-yellow-800" },
|
|
lethargy: { icon: "😴", title: "Lethargy / Unresponsive", color: "bg-purple-50 dark:bg-purple-900/20 border-purple-200 dark:border-purple-800" },
|
|
vomiting: { icon: "🤢", title: "Vomiting", color: "bg-green-50 dark:bg-green-900/20 border-green-200 dark:border-green-800" },
|
|
rash: { icon: "🔴", title: "Rash", color: "bg-rose-50 dark:bg-rose-900/20 border-rose-200 dark:border-rose-800" },
|
|
injury: { icon: "🩹", title: "Injury / Fall", color: "bg-red-50 dark:bg-red-900/20 border-red-200 dark:border-red-800" },
|
|
default: { icon: "⚠️", title: "General Concern", color: "bg-gray-50 dark:bg-gray-800 border-gray-200 dark:border-gray-700" },
|
|
};
|
|
|
|
export default function EmergencyPage() {
|
|
const [phone, setPhone] = useState<string | null>(null);
|
|
|
|
useEffect(() => {
|
|
fetch("/api/family").then(r => r.json()).then(d => {
|
|
setPhone(d.family?.pediatrician_phone || null);
|
|
}).catch(() => {});
|
|
}, []);
|
|
|
|
return (
|
|
<div className="min-h-screen bg-gradient-to-br from-rose-50 to-red-50 dark:from-gray-900 dark:to-gray-800">
|
|
{/* Header */}
|
|
<div className="sticky top-0 bg-red-500 text-white z-10">
|
|
<div className="flex items-center gap-3 p-4">
|
|
<Link href="/medical" className="text-white/80 hover:text-white text-xl">←</Link>
|
|
<div>
|
|
<h1 className="font-bold text-lg">Emergency Guide</h1>
|
|
<p className="text-red-100 text-xs">When to call the doctor immediately</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Call button */}
|
|
<div className="p-4">
|
|
{phone ? (
|
|
<a
|
|
href={`tel:${phone}`}
|
|
className="w-full flex items-center justify-center gap-3 bg-red-500 hover:bg-red-600 text-white rounded-2xl p-4 text-lg font-bold shadow-md shadow-red-200 dark:shadow-red-900/30 transition-colors"
|
|
>
|
|
📞 Call Pediatrician Now
|
|
</a>
|
|
) : (
|
|
<Link
|
|
href="/settings"
|
|
className="w-full flex items-center justify-center gap-2 bg-gray-200 dark:bg-gray-700 text-gray-600 dark:text-gray-300 rounded-2xl p-4 font-medium"
|
|
>
|
|
+ Add pediatrician phone in Settings
|
|
</Link>
|
|
)}
|
|
</div>
|
|
|
|
{/* Emergency rules */}
|
|
<div className="px-4 pb-8 space-y-3">
|
|
<p className="text-xs font-semibold uppercase tracking-widest text-gray-400 dark:text-gray-500 mb-1">Seek care if you see any of these</p>
|
|
|
|
{(Object.entries(ESCALATION_RULES) as [string, string][]).map(([key, text]) => {
|
|
const meta = RULE_META[key] || RULE_META.default;
|
|
return (
|
|
<div key={key} className={`p-4 rounded-2xl border ${meta.color}`}>
|
|
<div className="flex items-center gap-2 mb-1">
|
|
<span className="text-xl">{meta.icon}</span>
|
|
<span className="font-semibold text-gray-900 dark:text-white">{meta.title}</span>
|
|
</div>
|
|
<p className="text-sm text-gray-600 dark:text-gray-300 leading-relaxed">{text}</p>
|
|
</div>
|
|
);
|
|
})}
|
|
|
|
<div className="mt-4 p-4 bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800 rounded-2xl">
|
|
<p className="text-sm text-amber-700 dark:text-amber-300 font-medium">When in doubt, call your pediatrician.</p>
|
|
<p className="text-xs text-amber-600 dark:text-amber-400 mt-1">It's always better to check than to wait.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|