From 90c8d138146da797b3d97e7cc8f5d44ca771b803 Mon Sep 17 00:00:00 2001 From: Mannu Date: Thu, 28 May 2026 00:49:05 +0530 Subject: [PATCH] feat(settings): add Pediatrician Name field alongside phone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - New families.pediatrician_name column (migration 0008) - Settings card: Name input above Phone input, single Save - Emergency page: shows doctor's name above the call button - AI medical redirects: personalised "Call Dr. X: +91…" message Co-Authored-By: Claude Sonnet 4.6 --- drizzle/0008_pediatrician_name.sql | 2 ++ drizzle/meta/_journal.json | 7 +++++++ src/app/(app)/medical/emergency/page.tsx | 23 +++++++++++++++-------- src/app/(app)/settings/page.tsx | 20 ++++++++++++++------ src/app/api/ai/route.ts | 14 +++++++++----- src/app/api/debug-migration/route.ts | 2 ++ src/app/api/family/route.ts | 8 ++++---- src/db/schema/family.ts | 1 + 8 files changed, 54 insertions(+), 23 deletions(-) create mode 100644 drizzle/0008_pediatrician_name.sql diff --git a/drizzle/0008_pediatrician_name.sql b/drizzle/0008_pediatrician_name.sql new file mode 100644 index 0000000..cfe96a8 --- /dev/null +++ b/drizzle/0008_pediatrician_name.sql @@ -0,0 +1,2 @@ +ALTER TABLE families + ADD COLUMN IF NOT EXISTS pediatrician_name text; diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index a53026b..d673271 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -57,6 +57,13 @@ "when": 1748480400000, "tag": "0007_subscription_status", "breakpoints": true + }, + { + "idx": 8, + "version": "7", + "when": 1748566800000, + "tag": "0008_pediatrician_name", + "breakpoints": true } ] } \ No newline at end of file diff --git a/src/app/(app)/medical/emergency/page.tsx b/src/app/(app)/medical/emergency/page.tsx index dea118f..348607e 100644 --- a/src/app/(app)/medical/emergency/page.tsx +++ b/src/app/(app)/medical/emergency/page.tsx @@ -17,10 +17,12 @@ const RULE_META: Record export default function EmergencyPage() { const [phone, setPhone] = useState(null); + const [name, setName] = useState(null); useEffect(() => { fetch("/api/family").then(r => r.json()).then(d => { setPhone(d.family?.pediatrician_phone || null); + setName(d.family?.pediatrician_name || null); }).catch(() => {}); }, []); @@ -38,20 +40,25 @@ export default function EmergencyPage() { {/* Call button */} -
+
{phone ? ( - - 📞 Call Pediatrician Now - + <> + {name && ( +

{name}

+ )} + + 📞 Call Pediatrician Now + + ) : ( - + Add pediatrician phone in Settings + + Add pediatrician info in Settings )}
diff --git a/src/app/(app)/settings/page.tsx b/src/app/(app)/settings/page.tsx index a56c14e..360802a 100644 --- a/src/app/(app)/settings/page.tsx +++ b/src/app/(app)/settings/page.tsx @@ -39,6 +39,7 @@ export default function SettingsPage() { const [inviteRole, setInviteRole] = useState("caregiver"); const [inviteLoading, setInviteLoading] = useState(false); const [pedPhone, setPedPhone] = useState(""); + const [pedName, setPedName] = useState(""); const [pedSaving, setPedSaving] = useState(false); // Check if can invite more members (client-side pre-check; server enforces) @@ -60,6 +61,7 @@ export default function SettingsPage() { fetchInvites(); fetch("/api/family").then(r => r.json()).then(d => { if (d.family?.pediatrician_phone) setPedPhone(d.family.pediatrician_phone); + if (d.family?.pediatrician_name) setPedName(d.family.pediatrician_name); }).catch(() => {}); } }, [familyId]); @@ -92,12 +94,12 @@ export default function SettingsPage() { setExporting(false); }; - const savePedPhone = async () => { + const savePedInfo = async () => { setPedSaving(true); await fetch("/api/family", { method: "PATCH", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ pediatricianPhone: pedPhone }), + body: JSON.stringify({ pediatricianPhone: pedPhone, pediatricianName: pedName }), }).catch(() => {}); setPedSaving(false); }; @@ -356,16 +358,22 @@ export default function SettingsPage() { )}
- {/* Pediatrician Phone */} -
+ {/* Pediatrician */} +
🏥 -
Pediatrician Phone
+
Pediatrician

Shown on the emergency guide and in AI medical redirects.

+ setPedName(e.target.value)} + placeholder="Dr. Priya Sharma" + />
setPedPhone(e.target.value)} placeholder="+91 98765 43210" className="flex-1" /> - +
View Emergency Guide → diff --git a/src/app/api/ai/route.ts b/src/app/api/ai/route.ts index 01ec82e..f9a0542 100644 --- a/src/app/api/ai/route.ts +++ b/src/app/api/ai/route.ts @@ -38,8 +38,10 @@ export async function POST(request: Request) { // ── 1. HARD GUARDRAIL: keyword-based medical detection (most conservative) ── const medicalIntent = detectMedicalIntent(lastUserMsg); if (medicalIntent.isMedical) { - const families = await sql`SELECT pediatrician_phone FROM families WHERE id = ${familyId} LIMIT 1`; + const families = await sql`SELECT pediatrician_phone, pediatrician_name FROM families WHERE id = ${familyId} LIMIT 1`; const phone = families[0]?.pediatrician_phone; + const pedName = families[0]?.pediatrician_name; + const pedLabel = pedName ? `Dr. ${pedName.replace(/^Dr\.?\s*/i, "")}` : "your pediatrician"; const reply = [ `I can't interpret symptoms — that's a pediatrician's job, not mine.`, @@ -47,8 +49,8 @@ export async function POST(request: Request) { ESCALATION_RULES[medicalIntent.category], ``, phone - ? `Call your pediatrician now: ${phone}` - : `Add your pediatrician's phone in Settings so I can show it here.`, + ? `Call ${pedLabel} now: ${phone}` + : `Add your pediatrician's info in Settings so I can show it here.`, ].join("\n"); await logAudit({ @@ -84,13 +86,15 @@ export async function POST(request: Request) { // Medical_redirect from classifier → also redirect if (classification.intent === "medical_redirect") { - const families = await sql`SELECT pediatrician_phone FROM families WHERE id = ${familyId} LIMIT 1`; + const families = await sql`SELECT pediatrician_phone, pediatrician_name FROM families WHERE id = ${familyId} LIMIT 1`; const phone = families[0]?.pediatrician_phone; + const pedName = families[0]?.pediatrician_name; + const pedLabel = pedName ? `Dr. ${pedName.replace(/^Dr\.?\s*/i, "")}` : "your pediatrician"; const reply = [ `That sounds like something your pediatrician should assess.`, ``, ESCALATION_RULES["default"], - phone ? `Call: ${phone}` : `Add your pediatrician's phone in Settings.`, + phone ? `Call ${pedLabel}: ${phone}` : `Add your pediatrician's info in Settings.`, ].join("\n"); await logUsage({ familyId, userId: session.userId, intent: "medical_redirect", durationMs: Date.now() - start }); diff --git a/src/app/api/debug-migration/route.ts b/src/app/api/debug-migration/route.ts index 2fdf5dd..65fa050 100644 --- a/src/app/api/debug-migration/route.ts +++ b/src/app/api/debug-migration/route.ts @@ -35,6 +35,8 @@ export async function POST(req: Request) { `ALTER TABLE family_invites ADD COLUMN IF NOT EXISTS accepted_at timestamp`, // subscription_status on families (0007) — payment-provider abstraction `ALTER TABLE families ADD COLUMN IF NOT EXISTS subscription_status varchar(20) DEFAULT NULL`, + // pediatrician_name on families (0008) + `ALTER TABLE families ADD COLUMN IF NOT EXISTS pediatrician_name text`, // circles tables (0003) `CREATE TABLE IF NOT EXISTS circles (id uuid PRIMARY KEY DEFAULT gen_random_uuid(), name text NOT NULL, created_by uuid NOT NULL REFERENCES families(id), created_at timestamptz NOT NULL DEFAULT now())`, `CREATE TABLE IF NOT EXISTS circle_members (circle_id uuid NOT NULL REFERENCES circles(id) ON DELETE CASCADE, family_id uuid NOT NULL REFERENCES families(id), role text NOT NULL DEFAULT 'member', joined_at timestamptz NOT NULL DEFAULT now(), PRIMARY KEY (circle_id, family_id))`, diff --git a/src/app/api/family/route.ts b/src/app/api/family/route.ts index 3b295ea..471c7a2 100644 --- a/src/app/api/family/route.ts +++ b/src/app/api/family/route.ts @@ -9,7 +9,7 @@ export async function GET(request: Request) { try { const family = await sql.unsafe( - `SELECT id, name, tier, max_children, max_members FROM families WHERE id = $1`, + `SELECT id, name, tier, max_children, max_members, pediatrician_phone, pediatrician_name FROM families WHERE id = $1`, [auth.session!.familyId] ); @@ -31,11 +31,11 @@ export async function PATCH(request: Request) { try { const body = await request.json(); - const { name, pediatricianPhone, tier } = body; + const { name, pediatricianPhone, pediatricianName, tier } = body; await sql.unsafe( - `UPDATE families SET name = COALESCE($1, name), pediatrician_phone = COALESCE($2, pediatrician_phone), tier = COALESCE($3, tier), updated_at = NOW() WHERE id = $4`, - [name, pediatricianPhone, tier, auth.session!.familyId] + `UPDATE families SET name = COALESCE($1, name), pediatrician_phone = COALESCE($2, pediatrician_phone), pediatrician_name = COALESCE($3, pediatrician_name), tier = COALESCE($4, tier), updated_at = NOW() WHERE id = $5`, + [name, pediatricianPhone, pediatricianName, tier, auth.session!.familyId] ); return NextResponse.json({ success: true }); diff --git a/src/db/schema/family.ts b/src/db/schema/family.ts index ebebe12..9c117e8 100644 --- a/src/db/schema/family.ts +++ b/src/db/schema/family.ts @@ -49,6 +49,7 @@ export const families = pgTable("families", { maxChildren: integer("max_children").default(1), maxMembers: integer("max_members").default(2), pediatricianPhone: text("pediatrician_phone"), + pediatricianName: text("pediatrician_name"), createdAt: timestamp("created_at").defaultNow().notNull(), updatedAt: timestamp("updated_at").defaultNow().notNull(), });