tia/src/app/family/page.tsx

206 lines
No EOL
6.9 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { useState, useEffect } from "react";
import { useRouter } from "next/navigation";
interface Child {
id: string;
name: string;
birthDate: string;
sex: string;
stage?: string;
}
export default function FamilyPage() {
const router = useRouter();
const [children, setChildren] = useState<Child[]>([]);
const [loading, setLoading] = useState(true);
const [editing, setEditing] = useState<string | null>(null);
const [editName, setEditName] = useState("");
const [editDob, setEditDob] = useState("");
const [showAdd, setShowAdd] = useState(false);
const [newName, setNewName] = useState("");
const [newDob, setNewDob] = useState("");
const [newSex, setNewSex] = useState("male");
useEffect(() => {
fetchChildren();
}, []);
const fetchChildren = async () => {
try {
const res = await fetch("/api/children?familyId=default");
const data = await res.json();
setChildren(data.children || []);
} catch (err) {
console.error("Failed to fetch:", err);
}
setLoading(false);
};
const startEdit = (child: Child) => {
setEditing(child.id);
setEditName(child.name);
setEditDob(child.birthDate);
};
const saveEdit = async (childId: string) => {
try {
const res = await fetch("/api/children", {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ id: childId, name: editName, birthDate: editDob }),
});
const data = await res.json();
if (data.success) {
setChildren(children.map((c) => (c.id === childId ? { ...c, name: editName, birthDate: editDob } : c)));
}
} catch (err) {
console.error("Failed to save:", err);
}
setEditing(null);
};
const addChild = async () => {
if (!newName || !newDob) return;
try {
const res = await fetch("/api/children", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: newName, birthDate: newDob, sex: newSex, familyId: "default" }),
});
const data = await res.json();
if (data.success) {
setChildren([data.child, ...children]);
setShowAdd(false);
setNewName("");
setNewDob("");
}
} catch (err) {
console.error("Failed to add:", err);
}
};
return (
<div className="min-h-screen bg-gradient-to-br from-rose-50 to-amber-50 dark:from-gray-900 dark:to-gray-800">
<div className="p-4 flex items-center gap-4">
<button onClick={() => router.back()} className="p-2"></button>
<h1 className="text-xl font-bold">Family</h1>
</div>
<div className="px-4 space-y-4">
{/* Add Child Form */}
{showAdd && (
<div className="p-4 bg-white dark:bg-gray-800 rounded-xl space-y-3">
<input
type="text"
value={newName}
onChange={(e) => setNewName(e.target.value)}
placeholder="Baby's name"
className="w-full p-2 border rounded-lg"
/>
<input
type="date"
value={newDob}
onChange={(e) => setNewDob(e.target.value)}
className="w-full p-2 border rounded-lg"
/>
<select
value={newSex}
onChange={(e) => setNewSex(e.target.value)}
className="w-full p-2 border rounded-lg"
>
<option value="male">Boy</option>
<option value="female">Girl</option>
</select>
<div className="flex gap-2">
<button onClick={addChild} className="flex-1 py-2 bg-rose-400 text-white rounded-lg">
Add Baby
</button>
<button onClick={() => setShowAdd(false)} className="flex-1 py-2 bg-gray-200 dark:bg-gray-600 rounded-lg">
Cancel
</button>
</div>
</div>
)}
{loading ? (
<div className="text-center py-20 text-gray-400">Loading...</div>
) : children.length === 0 && !showAdd ? (
<div className="text-center py-20">
<div className="text-6xl mb-4">👶</div>
<p className="text-gray-500 mb-4">No baby added yet</p>
<button
onClick={() => setShowAdd(true)}
className="px-4 py-2 bg-rose-400 text-white rounded-lg"
>
Add Baby
</button>
</div>
) : (
children.map((child) => (
<div key={child.id} className="p-4 bg-white dark:bg-gray-800 rounded-xl">
{editing === child.id ? (
<div className="space-y-3">
<input
type="text"
value={editName}
onChange={(e) => setEditName(e.target.value)}
className="w-full p-2 border rounded-lg"
/>
<input
type="date"
value={editDob}
onChange={(e) => setEditDob(e.target.value)}
className="w-full p-2 border rounded-lg"
/>
<div className="flex gap-2">
<button
onClick={() => saveEdit(child.id)}
className="flex-1 py-2 bg-rose-400 text-white rounded-lg"
>
Save
</button>
<button
onClick={() => setEditing(null)}
className="flex-1 py-2 bg-gray-200 dark:bg-gray-600 rounded-lg"
>
Cancel
</button>
</div>
</div>
) : (
<div className="flex items-center justify-between">
<div className="flex items-center gap-4">
<div className="text-4xl">{child.sex === "male" ? "👦" : "👧"}</div>
<div>
<div className="font-medium text-lg">{child.name}</div>
<div className="text-sm text-gray-500">
Born: {child.birthDate ? new Date(child.birthDate).toLocaleDateString() : "Not set"}
</div>
</div>
</div>
<div className="flex gap-2">
<button onClick={() => startEdit(child)} className="p-2 text-gray-400">
</button>
</div>
</div>
)}
</div>
))
)}
{/* Add Button */}
{!showAdd && children.length > 0 && (
<button
onClick={() => setShowAdd(true)}
className="w-full p-4 border-2 border-dashed border-gray-300 rounded-xl text-gray-500"
>
+ Add Baby
</button>
)}
</div>
</div>
);
}