diff --git a/src/app/admin-login/page.tsx b/src/app/admin-login/page.tsx
index 524c673..f142c08 100644
--- a/src/app/admin-login/page.tsx
+++ b/src/app/admin-login/page.tsx
@@ -2,6 +2,7 @@
import { useState, useEffect } from "react";
import { useRouter } from "next/navigation";
+import { Button, Input } from "@/components/ui";
export default function AdminLoginPage() {
const router = useRouter();
@@ -34,16 +35,13 @@ export default function AdminLoginPage() {
const data = await res.json();
if (res.ok && data.success) {
- // Verify session server-side before redirect
const sessionRes = await fetch("/api/admin/auth");
const sessionData = await sessionRes.json();
- if (sessionData.authenticated) {
- router.push("/admin");
- }
+ if (sessionData.authenticated) router.push("/admin");
} else {
setError(data.error || "Invalid credentials");
}
- } catch (err) {
+ } catch {
setError("Login failed");
} finally {
setLoading(false);
@@ -56,39 +54,30 @@ export default function AdminLoginPage() {
Admin Login
);
-}
\ No newline at end of file
+}
diff --git a/src/app/admin/children/page.tsx b/src/app/admin/children/page.tsx
index b403c3f..e727eb9 100644
--- a/src/app/admin/children/page.tsx
+++ b/src/app/admin/children/page.tsx
@@ -1,6 +1,7 @@
"use client";
import { useEffect, useState } from "react";
+import { Button, Input } from "@/components/ui";
interface Child {
id: string;
@@ -59,17 +60,14 @@ export default function AdminChildren() {
Children
{children.length} total children
-
- Export CSV
-
+ Export CSV
- setSearch(e.target.value)}
- className="w-full bg-gray-800 border border-gray-700 rounded-lg px-4 py-2 text-white"
/>
diff --git a/src/app/admin/families/page.tsx b/src/app/admin/families/page.tsx
index f03146c..2eeca15 100644
--- a/src/app/admin/families/page.tsx
+++ b/src/app/admin/families/page.tsx
@@ -1,6 +1,7 @@
"use client";
import { useEffect, useState } from "react";
+import { Button, Input, Select, Badge } from "@/components/ui";
interface Member {
id: string;
@@ -135,39 +136,28 @@ export default function AdminFamilies() {
{families.length} total families
-
- + New Family
-
-
- Export CSV
-
+ + New Family
+ Export CSV
{/* Filters */}
- setSearch(e.target.value)}
- className="flex-1 bg-gray-800 border border-gray-700 rounded-lg px-4 py-2 text-white"
+ className="flex-1"
/>
- setTierFilter(e.target.value)}
- className="bg-gray-800 border border-gray-700 rounded-lg px-4 py-2 text-white"
>
All Tiers
Free
Pro
-
+
{/* Table */}
@@ -192,19 +182,12 @@ export default function AdminFamilies() {
{family.id}
-
- {family.tier}
-
+ {family.tier}
- setShowMembers(showMembers === family.id ? null : family.id)}
- className="text-rose-400 underline"
- >
+ setShowMembers(showMembers === family.id ? null : family.id)}>
{family.userCount} users
-
+
{family.childCount}
@@ -219,25 +202,24 @@ export default function AdminFamilies() {
- setAddMember({familyId: family.id, email: e.target.value, role: "caregiver", name: ""})}
- className="flex-1 bg-gray-700 border border-gray-600 rounded px-3 py-2 text-white"
+ className="flex-1"
/>
- setAddMember(addMember ? {...addMember, role: e.target.value} : null)}
- className="bg-gray-700 border border-gray-600 rounded px-3 py-2 text-white"
>
Caregiver
Owner
-
- Add
+
+ Add
{(family.members || []).map((m) => (
{m.email} ({m.role})
- handleRemoveMember(m.id)} className="text-red-400 text-sm">Remove
+ handleRemoveMember(m.id)}>Remove
))}
@@ -254,4 +236,4 @@ export default function AdminFamilies() {
);
-}
\ No newline at end of file
+}
diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx
index c07827b..4912345 100644
--- a/src/app/admin/page.tsx
+++ b/src/app/admin/page.tsx
@@ -1,6 +1,7 @@
"use client";
import { useEffect, useState } from "react";
+import { Select } from "@/components/ui";
interface Stats {
overview: {
@@ -59,15 +60,11 @@ export default function AdminDashboard() {
Dashboard
Platform overview and analytics
- setPeriod(e.target.value)}
- className="bg-gray-800 border border-gray-700 rounded-lg px-3 py-2 text-white"
- >
+ setPeriod(e.target.value)}>
Last 7 days
Last 30 days
Last 90 days
-
+
{/* Overview Cards */}
diff --git a/src/app/admin/settings/page.tsx b/src/app/admin/settings/page.tsx
index 7109b19..5e1c042 100644
--- a/src/app/admin/settings/page.tsx
+++ b/src/app/admin/settings/page.tsx
@@ -1,6 +1,7 @@
"use client";
import { useState } from "react";
+import { Button, Input } from "@/components/ui";
interface Settings {
proPrice: number;
@@ -40,12 +41,12 @@ export default function AdminSettings() {
Pro Monthly Price
$
- setSettings({ ...settings, proPrice: Number(e.target.value) })}
- className="flex-1 bg-gray-700 border border-gray-600 rounded-lg px-3 py-2"
+ className="flex-1"
/>
@@ -58,20 +59,18 @@ export default function AdminSettings() {
@@ -83,32 +82,27 @@ export default function AdminSettings() {
{/* Save */}
-
+
{saved ? "Saved!" : "Save Settings"}
-
+
);
-}
\ No newline at end of file
+}
diff --git a/src/app/admin/support/page.tsx b/src/app/admin/support/page.tsx
index 5f49522..19b9cac 100644
--- a/src/app/admin/support/page.tsx
+++ b/src/app/admin/support/page.tsx
@@ -1,6 +1,7 @@
"use client";
import { useEffect, useState } from "react";
+import { Button, Badge } from "@/components/ui";
interface Ticket {
id: string;
@@ -18,7 +19,6 @@ export default function AdminSupport() {
const [loading, setLoading] = useState(true);
const [statusFilter, setStatusFilter] = useState("all");
const [selectedTicket, setSelectedTicket] = useState(null);
- const [replyMessage, setReplyMessage] = useState("");
useEffect(() => {
fetchTickets();
@@ -49,6 +49,12 @@ export default function AdminSupport() {
}
};
+ const priorityVariant = (p: string): "rose" | "warning" | "default" =>
+ p === "urgent" ? "rose" : p === "high" ? "warning" : "default";
+
+ const statusVariant = (s: string): "rose" | "warning" | "default" =>
+ s === "open" ? "rose" : s === "in_progress" ? "warning" : "default";
+
if (loading) {
return Loading...
;
}
@@ -65,15 +71,14 @@ export default function AdminSupport() {
{/* Filters */}
{["all", "open", "in_progress", "resolved", "closed"].map((status) => (
- setStatusFilter(status)}
- className={`px-3 py-1.5 rounded-lg text-sm ${
- statusFilter === status ? "bg-rose-500" : "bg-gray-800"
- }`}
>
{status.replace("_", " ")}
-
+
))}
@@ -89,20 +94,8 @@ export default function AdminSupport() {
}`}
>
-
- {ticket.priority}
-
-
- {ticket.status.replace("_", " ")}
-
+ {ticket.priority}
+ {ticket.status.replace("_", " ")}
{ticket.subject}
{ticket.email}
@@ -132,28 +125,19 @@ export default function AdminSupport() {
{selectedTicket.status === "open" && (
- updateStatus(selectedTicket.id, "in_progress")}
- className="px-3 py-1.5 bg-amber-600 rounded-lg text-sm"
- >
+ updateStatus(selectedTicket.id, "in_progress")}>
Start
-
+
)}
{selectedTicket.status === "in_progress" && (
- updateStatus(selectedTicket.id, "resolved")}
- className="px-3 py-1.5 bg-emerald-600 rounded-lg text-sm"
- >
+ updateStatus(selectedTicket.id, "resolved")}>
Resolve
-
+
)}
{selectedTicket.status === "resolved" && (
- updateStatus(selectedTicket.id, "closed")}
- className="px-3 py-1.5 bg-gray-600 rounded-lg text-sm"
- >
+ updateStatus(selectedTicket.id, "closed")}>
Close
-
+
)}
@@ -166,4 +150,4 @@ export default function AdminSupport() {
);
-}
\ No newline at end of file
+}
diff --git a/src/app/admin/users/page.tsx b/src/app/admin/users/page.tsx
index aadf24c..237c6f9 100644
--- a/src/app/admin/users/page.tsx
+++ b/src/app/admin/users/page.tsx
@@ -1,6 +1,7 @@
"use client";
import { useEffect, useState } from "react";
+import { Button, Input, Select, Modal } from "@/components/ui";
interface User {
id: string;
@@ -25,6 +26,7 @@ export default function AdminUsers() {
const [search, setSearch] = useState("");
const [showAdd, setShowAdd] = useState(false);
const [showPassword, setShowPassword] = useState(null);
+ const [passwordValue, setPasswordValue] = useState("");
const [newUser, setNewUser] = useState({ email: "", name: "", familyId: "", role: "caregiver" });
useEffect(() => {
@@ -98,6 +100,7 @@ export default function AdminUsers() {
if (res.ok) {
fetchUsers();
setShowPassword(null);
+ setPasswordValue("");
}
} catch (err) {
console.error("Failed to set password:", err);
@@ -132,47 +135,45 @@ export default function AdminUsers() {
Users
{users.length} total users
- setShowAdd(!showAdd)} className="px-4 py-2 bg-rose-500 hover:bg-rose-600 rounded-lg">
- + Add User
-
+
+ Export CSV
+ setShowAdd(!showAdd)}>+ Add User
+
{showAdd && (
- setNewUser({ ...newUser, email: e.target.value })}
- className="flex-1 bg-gray-700 border border-gray-600 rounded px-3 py-2 text-white min-w-[200px]"
+ className="flex-1 min-w-[200px]"
/>
- setNewUser({ ...newUser, name: e.target.value })}
- className="bg-gray-700 border border-gray-600 rounded px-3 py-2 text-white"
/>
- setNewUser({ ...newUser, familyId: e.target.value })}
- className="bg-gray-700 border border-gray-600 rounded px-3 py-2 text-white"
>
Select Family
{families.map((f) => (
{f.name}
))}
-
- Create
+
+ Create
)}
- setSearch(e.target.value)}
- className="w-full bg-gray-800 border border-gray-700 rounded-lg px-4 py-2 text-white"
/>
@@ -195,32 +196,20 @@ export default function AdminUsers() {
{user.familyName || "-"}
- {user.hasPassword ? (
- setShowPassword(user.id)}
- className="text-emerald-400 text-sm hover:underline"
- >
- β Set
-
- ) : (
- setShowPassword(user.id)}
- className="text-amber-400 text-sm hover:underline"
- >
- Not set
-
- )}
+ setShowPassword(user.id)}
+ className={`text-sm hover:underline ${user.hasPassword ? "text-emerald-400" : "text-amber-400"}`}
+ >
+ {user.hasPassword ? "β Set" : "Not set"}
+
{user.createdAt?.slice(0, 10)}
- handleRemoveUser(user.id, user.memberId)}
- className="text-red-400 text-sm hover:underline"
- >
+ handleRemoveUser(user.id, user.memberId)}>
Delete
-
+
))}
@@ -231,37 +220,35 @@ export default function AdminUsers() {
)}
- {/* Password Modal */}
- {showPassword && (
-
-
-
Set Password
-
-
- {
- const pwd = (document.getElementById("passwordInput") as HTMLInputElement).value;
- handleSetPassword(showPassword, pwd);
- }}
- className="flex-1 px-4 py-2 bg-rose-500 rounded text-white"
- >
- Set
-
- setShowPassword(null)}
- className="px-4 py-2 bg-gray-600 rounded text-white"
- >
- Cancel
-
-
+
{ setShowPassword(null); setPasswordValue(""); }}
+ title="Set Password"
+ >
+
+
setPasswordValue(e.target.value)}
+ />
+
+ showPassword && handleSetPassword(showPassword, passwordValue)}
+ >
+ Set
+
+ { setShowPassword(null); setPasswordValue(""); }}
+ >
+ Cancel
+
- )}
+
);
-}
\ No newline at end of file
+}
diff --git a/src/app/ai/page.tsx b/src/app/ai/page.tsx
index cfb3239..788809a 100644
--- a/src/app/ai/page.tsx
+++ b/src/app/ai/page.tsx
@@ -2,6 +2,7 @@
import { useState, useEffect } from "react";
import { useFamily } from "../FamilyProvider";
+import { Button, Input, ConfirmDialog } from "@/components/ui";
interface AIChat {
id: string;
@@ -182,7 +183,7 @@ export default function AIChatPage() {
β
Chats
- +
+ +
{sessions.length === 0 ? (
@@ -237,9 +238,7 @@ export default function AIChatPage() {
π€±
Ask anything about your baby
Tap β° to see past chats, or just type below to start
-
- New Chat
-
+
New Chat
) : currentSession.messages.length === 0 ? (
@@ -278,38 +277,30 @@ export default function AIChatPage() {
{/* Input */}
- {/* Delete confirm modal */}
- {deleteConfirm && (
-
-
-
Delete this conversation?
-
This can't be undone.
-
- deleteSession(deleteConfirm)} className="flex-1 py-2 bg-red-500 text-white rounded-xl text-sm">Delete
- setDeleteConfirm(null)} className="flex-1 py-2 bg-gray-100 dark:bg-gray-700 dark:text-white rounded-xl text-sm">Cancel
-
-
-
- )}
+ setDeleteConfirm(null)}
+ onConfirm={() => deleteConfirm && deleteSession(deleteConfirm)}
+ title="Delete this conversation?"
+ description="This can't be undone."
+ confirmLabel="Delete"
+ variant="danger"
+ />
);
}
diff --git a/src/app/growth/page.tsx b/src/app/growth/page.tsx
index 1e6df3b..bbf2c60 100644
--- a/src/app/growth/page.tsx
+++ b/src/app/growth/page.tsx
@@ -2,6 +2,7 @@
import { useState, useEffect, useRef } from "react";
import { useFamily } from "../FamilyProvider";
+import { Button, Card, Input, ConfirmDialog } from "@/components/ui";
import { WHO_BOY_WEIGHT, WHO_GIRL_WEIGHT, getAgeInMonthsFromBirth, getPercentile, type GrowthStandard } from "@/lib/growth-standards";
import {
Chart as ChartJS,
@@ -83,6 +84,7 @@ export default function GrowthPage() {
const [chartMetric, setChartMetric] = useState<"weight" | "height" | "head">("weight");
const [saving, setSaving] = useState(false);
const [saveError, setSaveError] = useState(null);
+ const [confirmDeleteId, setConfirmDeleteId] = useState(null);
const [showWhoStandards, setShowWhoStandards] = useState(true);
const [showChart, setShowChart] = useState(true);
const [showHistory, setShowHistory] = useState(true);
@@ -186,8 +188,8 @@ export default function GrowthPage() {
};
const handleDelete = async (id: string) => {
- if (!confirm("Delete this record?")) return;
await fetch(`/api/growth?id=${id}`, { method: "DELETE" });
+ setConfirmDeleteId(null);
fetchGrowthData();
};
@@ -375,55 +377,33 @@ export default function GrowthPage() {
Growth π
-
- π₯
-
- setShowGoals(!showGoals)} className="p-2 text-sm bg-gray-200 dark:bg-gray-700 rounded-lg" title="Set goals">
- π―
-
- { setShowAdd(!showAdd); setEditingId(null); setWeight(""); setHeight(""); setHeadCircumference(""); setMeasuredAt(new Date().toISOString().split("T")[0]); }} className="p-2 bg-rose-400 text-white rounded-lg">
+ π₯
+ setShowGoals(!showGoals)} title="Set goals">π―
+ { setShowAdd(!showAdd); setEditingId(null); setWeight(""); setHeight(""); setHeadCircumference(""); setMeasuredAt(new Date().toISOString().split("T")[0]); }}>
+ Add
-
+
{/* Goals Card */}
{showGoals && (
-
+
)}
{/* Latest Reading Card */}
@@ -621,54 +601,20 @@ export default function GrowthPage() {
{saveError && (
{saveError}
)}
- setMeasuredAt(e.target.value)}
- className="w-full p-3 border rounded-xl dark:bg-gray-700"
- />
- setWeight(e.target.value)}
- className="w-full p-3 border rounded-xl dark:bg-gray-700"
- />
- setHeight(e.target.value)}
- className="w-full p-3 border rounded-xl dark:bg-gray-700"
- />
- setHeadCircumference(e.target.value)}
- className="w-full p-3 border rounded-xl dark:bg-gray-700"
- />
+ setMeasuredAt(e.target.value)} />
+ setWeight(e.target.value)} />
+ setHeight(e.target.value)} />
+ setHeadCircumference(e.target.value)} />
{editingId ? (
<>
- handleEdit(editingId)} disabled={saving} className="flex-1 p-3 bg-rose-400 text-white rounded-xl disabled:opacity-50">
- {saving ? "Saving..." : "Update"}
-
-
- Cancel
-
+ handleEdit(editingId)}>Update
+ Cancel
>
) : (
<>
- handleAdd()} disabled={saving} className="flex-1 p-3 bg-rose-400 text-white rounded-xl disabled:opacity-50">
- {saving ? "Saving..." : "Save"}
-
- { setShowAdd(false); setWeight(""); setHeight(""); setHeadCircumference(""); }} className="flex-1 p-3 bg-gray-200 dark:bg-gray-700 rounded-xl">
- Cancel
-
+ handleAdd()}>Save
+ { setShowAdd(false); setWeight(""); setHeight(""); setHeadCircumference(""); }}>Cancel
>
)}
@@ -681,16 +627,16 @@ export default function GrowthPage() {
Loading...
) : growthData.length === 0 ? (
-
-
π
-
Track {child?.name}'s Growth
-
- Start logging weight, height, and head measurements to see how {child?.name} is growing compared to WHO standards.
-
-
setShowAdd(true)} className="p-3 bg-rose-400 text-white rounded-xl">
- Add First Measurement
-
-
+
+
+
π
+
Track {child?.name}'s Growth
+
+ Start logging weight, height, and head measurements to see how {child?.name} is growing compared to WHO standards.
+
+
setShowAdd(true)}>Add First Measurement
+
+
) : (
/* History List - Collapsible */
@@ -730,7 +676,7 @@ export default function GrowthPage() {
βοΈ
handleDelete(record.id)}
+ onClick={() => setConfirmDeleteId(record.id)}
className="p-2 text-sm text-gray-400 hover:text-red-500 hover:bg-red-50 dark:hover:bg-red-900 rounded-lg transition-colors"
title="Delete"
>
@@ -743,6 +689,16 @@ export default function GrowthPage() {
)}
)}
+
+ setConfirmDeleteId(null)}
+ onConfirm={() => confirmDeleteId && handleDelete(confirmDeleteId)}
+ title="Delete this record?"
+ description="This measurement will be permanently removed."
+ confirmLabel="Delete"
+ variant="danger"
+ />
);
}
\ No newline at end of file
diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx
index e0f7550..59ae5b7 100644
--- a/src/app/login/page.tsx
+++ b/src/app/login/page.tsx
@@ -2,6 +2,7 @@
import { useState } from "react";
import { useRouter } from "next/navigation";
+import { Button, Input, Card } from "@/components/ui";
export default function LoginPage() {
const router = useRouter();
@@ -32,7 +33,6 @@ export default function LoginPage() {
return;
}
- // Redirect based on response
if (data.isNewUser) {
router.push("/onboarding");
} else if (data.familyId) {
@@ -40,7 +40,7 @@ export default function LoginPage() {
} else {
router.push("/onboarding");
}
- } catch (err) {
+ } catch {
setError("Something went wrong");
} finally {
setLoading(false);
@@ -49,46 +49,33 @@ export default function LoginPage() {
return (
-
+
{mode === "login" ? "Welcome Back" : "Create Account"}
@@ -101,7 +88,7 @@ export default function LoginPage() {
{mode === "login" ? "Sign Up" : "Sign In"}
-
+
);
-}
\ No newline at end of file
+}
diff --git a/src/app/medical/page.tsx b/src/app/medical/page.tsx
index d069923..e759496 100644
--- a/src/app/medical/page.tsx
+++ b/src/app/medical/page.tsx
@@ -2,6 +2,7 @@
import { useState, useEffect } from "react";
import { useFamily } from "../FamilyProvider";
+import { Button, Card, Modal, Input, Select, Textarea, Badge } from "@/components/ui";
interface Medicine {
id: string;
@@ -992,83 +993,38 @@ const SUPPLEMENTS = [
{/* Log Dose Modal */}
- {logDoseMedId && (
-
-
-
Log Dose
-
setDoseAmount(e.target.value)}
- placeholder="Amount given (e.g. 5ml)"
- className="w-full p-2 border dark:border-gray-600 rounded-lg text-sm dark:bg-gray-700 dark:text-white"
- />
-
setDoseTime(e.target.value)}
- className="w-full p-2 border dark:border-gray-600 rounded-lg text-sm dark:bg-gray-700 dark:text-white"
- />
-
setDoseNotes(e.target.value)}
- placeholder="Notes (optional)"
- className="w-full p-2 border dark:border-gray-600 rounded-lg text-sm dark:bg-gray-700 dark:text-white"
- />
-
-
- {doseLoading ? "Savingβ¦" : "Save Dose"}
-
- setLogDoseMedId(null)} className="flex-1 py-2 bg-gray-100 dark:bg-gray-700 dark:text-white rounded-xl text-sm">
- Cancel
-
-
+
setLogDoseMedId(null)} title="Log Dose" maxWidth="sm">
+
- )}
+
{/* Correction Modal */}
- {correctDose && (
-
-
-
Edit Dose (Correction)
-
Original is kept. A correction record is added.
+
setCorrectDose(null)} title="Edit Dose (Correction)" maxWidth="sm">
+
- )}
+
);
}
\ No newline at end of file
diff --git a/src/app/onboarding/page.tsx b/src/app/onboarding/page.tsx
index 0c22ad1..cfe43ca 100644
--- a/src/app/onboarding/page.tsx
+++ b/src/app/onboarding/page.tsx
@@ -2,6 +2,7 @@
import { useState, useEffect } from "react";
import { useRouter } from "next/navigation";
+import { Button, Card, Input, Select } from "@/components/ui";
const IAP_SCHEDULE = [
{ name: "BCG", weeks: 0, milestone: "At Birth" },
@@ -155,38 +156,20 @@ export default function OnboardingPage() {
)}
-
+
{/* Step 1 β Family info */}
{step === 1 && (
<>
Your family
-
- Family Name
- setForm({ ...form, familyName: e.target.value })}
- placeholder="The Gupta Family"
- className="w-full p-3 border rounded-xl mt-1"
- />
-
-
- Your Name
- setForm({ ...form, memberName: e.target.value })}
- placeholder="Mama"
- className="w-full p-3 border rounded-xl mt-1"
- />
-
- setStep(2)}
- disabled={!form.familyName || !form.memberName}
- className="w-full p-3 bg-rose-400 text-white rounded-xl font-medium disabled:opacity-50"
- >
+ setForm({ ...form, familyName: e.target.value })}
+ placeholder="The Gupta Family" />
+ setForm({ ...form, memberName: e.target.value })}
+ placeholder="Mama" />
+ setStep(2)} disabled={!form.familyName || !form.memberName}>
Next β
-
+
>
)}
@@ -194,49 +177,35 @@ export default function OnboardingPage() {
{step === 2 && (
<>
Your baby
-
- Baby's Name
- setForm({ ...form, childName: e.target.value })}
- placeholder="Tia"
- className="w-full p-3 border rounded-xl mt-1"
- />
-
-
- Birth Date
- setForm({ ...form, birthDate: e.target.value })}
- className="w-full p-3 border rounded-xl mt-1"
- />
-
-
- Sex
+ setForm({ ...form, childName: e.target.value })}
+ placeholder="Tia" />
+ setForm({ ...form, birthDate: e.target.value })} />
+
+
Sex
{(["male", "female", "other"] as const).map((s) => (
- setForm({ ...form, sex: s })}
- className={`flex-1 p-3 rounded-xl border capitalize ${form.sex === s ? "bg-rose-400 text-white border-rose-400" : "bg-white"}`}
+ className="capitalize"
>
{s}
-
+
))}
-
+
- setStep(1)} className="flex-1 p-3 border rounded-xl font-medium">Back
-
- {loading ? "Creating..." : "Next β"}
-
+ setStep(1)}>Back
+
+ Next β
+
>
)}
@@ -285,11 +254,8 @@ export default function OnboardingPage() {
{s.given && (
-
setVaccStates(prev => ({ ...prev, [v.name]: { ...s, date: e.target.value } }))}
- className="mt-2 w-full p-1.5 border rounded-lg text-sm"
/>
)}
@@ -302,23 +268,12 @@ export default function OnboardingPage() {
)}
- router.push("/")}
- className="flex-1 p-3 border rounded-xl text-sm text-gray-500"
- >
- Skip for now
-
-
- {saving ? "Saving..." : "Save & Go Home"}
-
+ router.push("/")}>Skip for now
+ Save & Go Home
>
)}
-
+
);
diff --git a/src/app/page.tsx b/src/app/page.tsx
index a3705a5..9fee7b1 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -5,6 +5,7 @@ import Link from "next/link";
import { useTheme } from "./ThemeProvider";
import { useFamily } from "./FamilyProvider";
import { useStageCheck, type BabyStage } from "@/hooks/useStageCheck";
+import { Button, Modal, Select, Input } from "@/components/ui";
const OFFLINE_QUEUE_KEY = "tia_offline_queue";
@@ -109,17 +110,41 @@ function LogModal({ type, childId, onClose }: { type: "feed" | "diaper" | "sleep
setLoading(false);
};
+ const title = type === "feed" ? "Log Feed" : type === "diaper" ? "Log Diaper" : "Log Sleep";
return (
-
-
-
{type === "feed" && "Log Feed"}{type === "diaper" && "Log Diaper"}{type === "sleep" && "Log Sleep"}
- {type === "feed" && (<>
setSubType(e.target.value)} className="w-full p-3 border dark:border-gray-600 rounded-xl mb-3 bg-white dark:bg-gray-700 dark:text-white">Breast Milk Formula Solid Food Water setAmountMl(e.target.value)} className="w-full p-3 border dark:border-gray-600 rounded-xl mb-3 bg-white dark:bg-gray-700 dark:text-white dark:placeholder-gray-400" />>)}
- {type === "diaper" && (
setSubType(e.target.value)} className="w-full p-3 border dark:border-gray-600 rounded-xl mb-3 bg-white dark:bg-gray-700 dark:text-white">Wet Dirty Both )}
- {type === "sleep" && (
setSubType(e.target.value)} className="w-full p-3 border dark:border-gray-600 rounded-xl mb-3 bg-white dark:bg-gray-700 dark:text-white">Nap Night Sleep )}
-
setNotes(e.target.value)} className="w-full p-3 border dark:border-gray-600 rounded-xl mb-4 bg-white dark:bg-gray-700 dark:text-white dark:placeholder-gray-400" />
-
Cancel {loading ? "Saving..." : "Save"}
+
+
+ {type === "feed" && (
+ <>
+
setSubType(e.target.value)}>
+ Breast Milk
+ Formula
+ Solid Food
+ Water
+
+
setAmountMl(e.target.value)} />
+ >
+ )}
+ {type === "diaper" && (
+
setSubType(e.target.value)}>
+ Wet
+ Dirty
+ Both
+
+ )}
+ {type === "sleep" && (
+
setSubType(e.target.value)}>
+ Nap
+ Night Sleep
+
+ )}
+
setNotes(e.target.value)} />
+
+ Cancel
+ Save
+
-
+
);
}
diff --git a/src/app/settings/page.tsx b/src/app/settings/page.tsx
index 283ae7d..bacd771 100644
--- a/src/app/settings/page.tsx
+++ b/src/app/settings/page.tsx
@@ -5,6 +5,7 @@ import Link from "next/link";
import { useRouter } from "next/navigation";
import { useTheme } from "../ThemeProvider";
import { useFamily } from "../FamilyProvider";
+import { Button, Card, Input, Select, Badge } from "@/components/ui";
interface Member {
id: string;
@@ -180,7 +181,7 @@ export default function SettingsPage() {
{tier === "free" && (
- Upgrade
+ Upgrade
)}
@@ -195,9 +196,7 @@ export default function SettingsPage() {
{member.name || member.email}
{member.email}
-
- {member.role}
-
+ {member.role}
))}
@@ -256,28 +255,14 @@ export default function SettingsPage() {
{/* Add invite form */}
{canInvite && (
- setInviteEmail(e.target.value)}
- placeholder="Email address"
- className="w-full p-2 border rounded-lg text-sm"
- />
- setInviteRole(e.target.value)}
- className="w-full p-2 border rounded-lg text-sm"
- >
+ setInviteEmail(e.target.value)} placeholder="Email address" />
+ setInviteRole(e.target.value)}>
Caregiver
Viewer (read-only)
-
-
- {inviteLoading ? "Sending..." : "Send Invite"}
-
+
+
+ Send Invite
+
)}
@@ -301,15 +286,13 @@ export default function SettingsPage() {
{themeOptions.map((opt) => (
- setMode(opt.value)}
- className={`p-3 rounded-lg text-sm ${
- mode === opt.value ? "bg-rose-400 text-white" : "bg-gray-100 dark:bg-gray-700"
- }`}
+ variant={mode === opt.value ? "primary" : "secondary"}
>
{opt.label}
-
+
))}
@@ -324,20 +307,8 @@ export default function SettingsPage() {
Shown on the emergency guide and in AI medical redirects.
- setPedPhone(e.target.value)}
- placeholder="+91 98765 43210"
- className="flex-1 p-2 border dark:border-gray-600 rounded-lg text-sm dark:bg-gray-700 dark:text-white"
- />
-
- {pedSaving ? "..." : "Save"}
-
+ setPedPhone(e.target.value)} placeholder="+91 98765 43210" className="flex-1" />
+ Save
View Emergency Guide β