fix(settings): pediatrician save + edit mode
- API: dynamic SET clause (only updates fields present in body) fixes undefined param bug and allows clearing fields; replaces blanket COALESCE - Settings UI: display/edit toggle — saved details shown with Edit button, inputs open on first visit or when editing; Save shows inline error on failure and brief "Saved!" on success Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
0a9def36bf
commit
bdb5199d5f
2 changed files with 90 additions and 23 deletions
|
|
@ -41,6 +41,9 @@ export default function SettingsPage() {
|
|||
const [pedPhone, setPedPhone] = useState("");
|
||||
const [pedName, setPedName] = useState("");
|
||||
const [pedSaving, setPedSaving] = useState(false);
|
||||
const [pedEditing, setPedEditing] = useState(false);
|
||||
const [pedSaved, setPedSaved] = useState(false);
|
||||
const [pedError, setPedError] = useState("");
|
||||
|
||||
// Check if can invite more members (client-side pre-check; server enforces)
|
||||
const canInvite = tier === "pro" || memberCount < 2;
|
||||
|
|
@ -60,8 +63,10 @@ export default function SettingsPage() {
|
|||
fetchMembers();
|
||||
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);
|
||||
setPedPhone(d.family?.pediatrician_phone || "");
|
||||
setPedName(d.family?.pediatrician_name || "");
|
||||
// If no data yet, open in edit mode so user can fill it in
|
||||
if (!d.family?.pediatrician_phone && !d.family?.pediatrician_name) setPedEditing(true);
|
||||
}).catch(() => {});
|
||||
}
|
||||
}, [familyId]);
|
||||
|
|
@ -96,11 +101,24 @@ export default function SettingsPage() {
|
|||
|
||||
const savePedInfo = async () => {
|
||||
setPedSaving(true);
|
||||
await fetch("/api/family", {
|
||||
setPedError("");
|
||||
try {
|
||||
const res = await fetch("/api/family", {
|
||||
method: "PATCH",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ pediatricianPhone: pedPhone, pediatricianName: pedName }),
|
||||
}).catch(() => {});
|
||||
});
|
||||
const data = await res.json();
|
||||
if (!res.ok) {
|
||||
setPedError(data.error || "Failed to save. Please try again.");
|
||||
} else {
|
||||
setPedEditing(false);
|
||||
setPedSaved(true);
|
||||
setTimeout(() => setPedSaved(false), 3000);
|
||||
}
|
||||
} catch {
|
||||
setPedError("Network error. Please try again.");
|
||||
}
|
||||
setPedSaving(false);
|
||||
};
|
||||
|
||||
|
|
@ -360,10 +378,31 @@ export default function SettingsPage() {
|
|||
|
||||
{/* Pediatrician */}
|
||||
<div className="bg-white dark:bg-gray-800 rounded-xl p-4 space-y-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xl">🏥</span>
|
||||
<div className="font-medium dark:text-white">Pediatrician</div>
|
||||
</div>
|
||||
{!pedEditing && (pedName || pedPhone) && (
|
||||
<button
|
||||
onClick={() => { setPedEditing(true); setPedSaved(false); setPedError(""); }}
|
||||
className="text-sm text-rose-500 dark:text-rose-400 font-medium"
|
||||
>
|
||||
Edit
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Display mode */}
|
||||
{!pedEditing && (pedName || pedPhone) ? (
|
||||
<div className="space-y-0.5">
|
||||
{pedName && <div className="text-sm font-medium text-gray-800 dark:text-gray-100">{pedName}</div>}
|
||||
{pedPhone && <div className="text-sm text-gray-500 dark:text-gray-400">{pedPhone}</div>}
|
||||
{pedSaved && <div className="text-xs text-green-600 dark:text-green-400">Saved!</div>}
|
||||
</div>
|
||||
) : (
|
||||
/* Edit / first-fill mode */
|
||||
<div className="space-y-2">
|
||||
<p className="text-xs text-gray-400 dark:text-gray-500">Shown on the emergency guide and in AI medical redirects.</p>
|
||||
<Input
|
||||
type="text"
|
||||
|
|
@ -375,6 +414,18 @@ export default function SettingsPage() {
|
|||
<Input type="tel" value={pedPhone} onChange={e => setPedPhone(e.target.value)} placeholder="+91 98765 43210" className="flex-1" />
|
||||
<Button size="sm" loading={pedSaving} onClick={savePedInfo}>Save</Button>
|
||||
</div>
|
||||
{pedEditing && (pedName || pedPhone) && (
|
||||
<button
|
||||
onClick={() => { setPedEditing(false); setPedError(""); }}
|
||||
className="text-xs text-gray-400 dark:text-gray-500"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
)}
|
||||
{pedError && <p className="text-xs text-red-500">{pedError}</p>}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Link href="/medical/emergency" className="text-xs text-rose-500 dark:text-rose-400">
|
||||
View Emergency Guide →
|
||||
</Link>
|
||||
|
|
|
|||
|
|
@ -33,9 +33,25 @@ export async function PATCH(request: Request) {
|
|||
const body = await request.json();
|
||||
const { name, pediatricianPhone, pediatricianName, tier } = body;
|
||||
|
||||
// Only update fields that are explicitly present in the request body.
|
||||
// This avoids COALESCE masking clears and undefined params causing errors.
|
||||
const setClauses: string[] = [];
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const params: any[] = [];
|
||||
|
||||
if (name !== undefined) { setClauses.push(`name = $${params.push(name)}`); }
|
||||
if (pediatricianPhone !== undefined) { setClauses.push(`pediatrician_phone = $${params.push(pediatricianPhone || null)}`); }
|
||||
if (pediatricianName !== undefined) { setClauses.push(`pediatrician_name = $${params.push(pediatricianName || null)}`); }
|
||||
if (tier !== undefined) { setClauses.push(`tier = $${params.push(tier)}`); }
|
||||
|
||||
if (setClauses.length === 0) return NextResponse.json({ success: true });
|
||||
|
||||
setClauses.push("updated_at = NOW()");
|
||||
params.push(auth.session!.familyId);
|
||||
|
||||
await sql.unsafe(
|
||||
`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]
|
||||
`UPDATE families SET ${setClauses.join(", ")} WHERE id = $${params.length}`,
|
||||
params
|
||||
);
|
||||
|
||||
return NextResponse.json({ success: true });
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue