Migrate medical data from localStorage to database
- Add database tables: medicines, allergies, doctor_visits, illness_logs - Create API endpoints: /api/medicines, /api/allergies, /api/visits, /api/illnesses - Update medical page to use database APIs instead of localStorage - All medical data now persists across sessions and devices Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
a1b436710f
commit
3e66b259f2
6 changed files with 535 additions and 94 deletions
38
CLAUDE.md
38
CLAUDE.md
|
|
@ -92,6 +92,44 @@ const { theme, toggle, setMode } = useTheme();
|
|||
- Model: `minimax-2.7`
|
||||
- See `/docs/debugging.md` for troubleshooting
|
||||
|
||||
## Data Storage Consistency
|
||||
|
||||
### RULE: All user data must persist to database, NOT localStorage
|
||||
|
||||
| Data Type | Storage | API Key | Persists After Refresh | Persists After Logout |
|
||||
|----------|---------|--------|------------------------|-------------------|
|
||||
| Children | Database | `/api/children` | ✅ Yes | ✅ Yes |
|
||||
| Activity Logs | Database | `/api/logs` | ✅ Yes | ✅ Yes |
|
||||
| Vaccinations | Database | `/api/vaccinations` | ✅ Yes | ✅ Yes |
|
||||
| Growth Records | Database | `/api/growth` | ✅ Yes | ✅ Yes |
|
||||
| User Profile | Database | `/api/auth/profile` | ✅ Yes | ✅ Yes |
|
||||
| Memories/Photos | Database + R2 | `/api/upload` | ✅ Yes | ✅ Yes |
|
||||
| **Medicines** | Database | `/api/medicines` | ⚠️ TODO | ⚠️ TODO |
|
||||
| **Allergies** | Database | `/api/allergies` | ⚠️ TODO | ⚠️ TODO |
|
||||
| **Doctor Visits** | Database | `/api/visits` | ⚠️ TODO | ⚠️ TODO |
|
||||
| **Illness Log** | Database | `/api/illnesses` | ⚠️ TODO | ⚠️ TODO |
|
||||
| Theme | localStorage | `tia_theme` | ✅ Yes | ✅ Yes |
|
||||
| Chat Sessions | localStorage | `tia_chat_sessions` | ✅ Yes | ❌ No |
|
||||
| Offline Queue | localStorage | `tia_offline_queue` | ✅ Yes | ❌ No |
|
||||
|
||||
### localStorage acceptable for:
|
||||
- Theme preference (user-specific display only)
|
||||
- Temporary cache (offline queue for retry)
|
||||
- Chat sessions (upcoming feature: move to database)
|
||||
|
||||
### NEVER use localStorage for:
|
||||
- Medical/health data (medicines, allergies, visits, illnesses)
|
||||
- Any data that should persist across devices
|
||||
- Data important for pediatrician visits
|
||||
|
||||
### Audit (2026-05-10)
|
||||
|
||||
Current status - needs migration to database:
|
||||
- `tia_medicines` → `/api/medicines`
|
||||
- `tia_allergies` → `/api/allergies`
|
||||
- `tia_visits` → `/api/visits`
|
||||
- `tia_illnesses` → `/api/illnesses`
|
||||
|
||||
## R2 Storage (Cloudflare)
|
||||
|
||||
### Setup
|
||||
|
|
|
|||
86
src/app/api/allergies/route.ts
Normal file
86
src/app/api/allergies/route.ts
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
import { NextResponse } from "next/server";
|
||||
import { sql } from "@/db";
|
||||
|
||||
// GET - list allergies for a child
|
||||
export async function GET(request: Request) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const childId = searchParams.get("childId") || "default";
|
||||
|
||||
try {
|
||||
const allergies = await sql.unsafe(
|
||||
`SELECT id, name, severity, notes, created_at as "createdAt"
|
||||
FROM allergies WHERE child_id = $1 ORDER BY created_at DESC`,
|
||||
[childId]
|
||||
);
|
||||
return NextResponse.json({ allergies: allergies || [] });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ error: String(error) }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
// POST - create allergy
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const body = await request.json();
|
||||
const { childId, name, severity, notes } = body;
|
||||
|
||||
if (!childId || !name) {
|
||||
return NextResponse.json({ error: "Missing required fields" }, { status: 400 });
|
||||
}
|
||||
|
||||
const [allergy] = await sql.unsafe(
|
||||
`INSERT INTO allergies (child_id, name, severity, notes)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
RETURNING id, name, severity, notes`,
|
||||
[childId, name, severity || "mild", notes || null]
|
||||
);
|
||||
|
||||
return NextResponse.json({ success: true, allergy });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ error: String(error) }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
// PATCH - update allergy
|
||||
export async function PATCH(request: Request) {
|
||||
try {
|
||||
const body = await request.json();
|
||||
const { id, name, severity, notes } = body;
|
||||
|
||||
if (!id || !name) {
|
||||
return NextResponse.json({ error: "Missing required fields" }, { status: 400 });
|
||||
}
|
||||
|
||||
const [allergy] = await sql.unsafe(
|
||||
`UPDATE allergies SET name = $1, severity = $2, notes = $3, updated_at = NOW()
|
||||
WHERE id = $4
|
||||
RETURNING id, name, severity, notes`,
|
||||
[name, severity, notes, id]
|
||||
);
|
||||
|
||||
return NextResponse.json({ success: true, allergy });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ error: String(error) }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
// DELETE - delete allergy
|
||||
export async function DELETE(request: Request) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const id = searchParams.get("id");
|
||||
|
||||
if (!id) {
|
||||
return NextResponse.json({ error: "ID required" }, { status: 400 });
|
||||
}
|
||||
|
||||
try {
|
||||
await sql.unsafe(`DELETE FROM allergies WHERE id = $1`, [id]);
|
||||
return NextResponse.json({ success: true });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ error: String(error) }, { status: 500 });
|
||||
}
|
||||
}
|
||||
86
src/app/api/illnesses/route.ts
Normal file
86
src/app/api/illnesses/route.ts
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
import { NextResponse } from "next/server";
|
||||
import { sql } from "@/db";
|
||||
|
||||
// GET - list illness logs for a child
|
||||
export async function GET(request: Request) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const childId = searchParams.get("childId") || "default";
|
||||
|
||||
try {
|
||||
const illnesses = await sql.unsafe(
|
||||
`SELECT id, name, start_date as "startDate", end_date as "endDate", notes, created_at as "createdAt"
|
||||
FROM illness_logs WHERE child_id = $1 ORDER BY start_date DESC`,
|
||||
[childId]
|
||||
);
|
||||
return NextResponse.json({ illnesses: illnesses || [] });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ error: String(error) }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
// POST - create illness log
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const body = await request.json();
|
||||
const { childId, name, startDate, endDate, notes } = body;
|
||||
|
||||
if (!childId || !name || !startDate) {
|
||||
return NextResponse.json({ error: "Missing required fields" }, { status: 400 });
|
||||
}
|
||||
|
||||
const [illness] = await sql.unsafe(
|
||||
`INSERT INTO illness_logs (child_id, name, start_date, end_date, notes)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
RETURNING id, name, start_date as "startDate", end_date as "endDate", notes`,
|
||||
[childId, name, startDate, endDate || null, notes || null]
|
||||
);
|
||||
|
||||
return NextResponse.json({ success: true, illness });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ error: String(error) }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
// PATCH - update illness log
|
||||
export async function PATCH(request: Request) {
|
||||
try {
|
||||
const body = await request.json();
|
||||
const { id, name, startDate, endDate, notes } = body;
|
||||
|
||||
if (!id || !name || !startDate) {
|
||||
return NextResponse.json({ error: "Missing required fields" }, { status: 400 });
|
||||
}
|
||||
|
||||
const [illness] = await sql.unsafe(
|
||||
`UPDATE illness_logs SET name = $1, start_date = $2, end_date = $3, notes = $4, updated_at = NOW()
|
||||
WHERE id = $5
|
||||
RETURNING id, name, start_date as "startDate", end_date as "endDate", notes`,
|
||||
[name, startDate, endDate, notes, id]
|
||||
);
|
||||
|
||||
return NextResponse.json({ success: true, illness });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ error: String(error) }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
// DELETE - delete illness log
|
||||
export async function DELETE(request: Request) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const id = searchParams.get("id");
|
||||
|
||||
if (!id) {
|
||||
return NextResponse.json({ error: "ID required" }, { status: 400 });
|
||||
}
|
||||
|
||||
try {
|
||||
await sql.unsafe(`DELETE FROM illness_logs WHERE id = $1`, [id]);
|
||||
return NextResponse.json({ success: true });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ error: String(error) }, { status: 500 });
|
||||
}
|
||||
}
|
||||
86
src/app/api/medicines/route.ts
Normal file
86
src/app/api/medicines/route.ts
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
import { NextResponse } from "next/server";
|
||||
import { sql } from "@/db";
|
||||
|
||||
// GET - list medicines for a child
|
||||
export async function GET(request: Request) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const childId = searchParams.get("childId") || "default";
|
||||
|
||||
try {
|
||||
const medicines = await sql.unsafe(
|
||||
`SELECT id, name, dose, notes, reminder_time as "reminderTime", created_at as "createdAt"
|
||||
FROM medicines WHERE child_id = $1 ORDER BY created_at DESC`,
|
||||
[childId]
|
||||
);
|
||||
return NextResponse.json({ medicines: medicines || [] });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ error: String(error) }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
// POST - create medicine
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const body = await request.json();
|
||||
const { childId, name, dose, notes, reminderTime } = body;
|
||||
|
||||
if (!childId || !name) {
|
||||
return NextResponse.json({ error: "Missing required fields" }, { status: 400 });
|
||||
}
|
||||
|
||||
const [medicine] = await sql.unsafe(
|
||||
`INSERT INTO medicines (child_id, name, dose, notes, reminder_time)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
RETURNING id, name, dose, notes, reminder_time as "reminderTime"`,
|
||||
[childId, name, dose || null, notes || null, reminderTime || null]
|
||||
);
|
||||
|
||||
return NextResponse.json({ success: true, medicine });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ error: String(error) }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
// PATCH - update medicine
|
||||
export async function PATCH(request: Request) {
|
||||
try {
|
||||
const body = await request.json();
|
||||
const { id, name, dose, notes, reminderTime } = body;
|
||||
|
||||
if (!id || !name) {
|
||||
return NextResponse.json({ error: "Missing required fields" }, { status: 400 });
|
||||
}
|
||||
|
||||
const [medicine] = await sql.unsafe(
|
||||
`UPDATE medicines SET name = $1, dose = $2, notes = $3, reminder_time = $4, updated_at = NOW()
|
||||
WHERE id = $5
|
||||
RETURNING id, name, dose, notes, reminder_time as "reminderTime"`,
|
||||
[name, dose, notes, reminderTime, id]
|
||||
);
|
||||
|
||||
return NextResponse.json({ success: true, medicine });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ error: String(error) }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
// DELETE - delete medicine
|
||||
export async function DELETE(request: Request) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const id = searchParams.get("id");
|
||||
|
||||
if (!id) {
|
||||
return NextResponse.json({ error: "ID required" }, { status: 400 });
|
||||
}
|
||||
|
||||
try {
|
||||
await sql.unsafe(`DELETE FROM medicines WHERE id = $1`, [id]);
|
||||
return NextResponse.json({ success: true });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ error: String(error) }, { status: 500 });
|
||||
}
|
||||
}
|
||||
86
src/app/api/visits/route.ts
Normal file
86
src/app/api/visits/route.ts
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
import { NextResponse } from "next/server";
|
||||
import { sql } from "@/db";
|
||||
|
||||
// GET - list doctor visits for a child
|
||||
export async function GET(request: Request) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const childId = searchParams.get("childId") || "default";
|
||||
|
||||
try {
|
||||
const visits = await sql.unsafe(
|
||||
`SELECT id, doctor_name as "doctorName", reason, visit_date as "date", notes, created_at as "createdAt"
|
||||
FROM doctor_visits WHERE child_id = $1 ORDER BY visit_date DESC`,
|
||||
[childId]
|
||||
);
|
||||
return NextResponse.json({ visits: visits || [] });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ error: String(error) }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
// POST - create visit
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const body = await request.json();
|
||||
const { childId, doctorName, reason, date, notes } = body;
|
||||
|
||||
if (!childId || !doctorName || !date) {
|
||||
return NextResponse.json({ error: "Missing required fields" }, { status: 400 });
|
||||
}
|
||||
|
||||
const [visit] = await sql.unsafe(
|
||||
`INSERT INTO doctor_visits (child_id, doctor_name, reason, visit_date, notes)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
RETURNING id, doctor_name as "doctorName", reason, visit_date as "date", notes`,
|
||||
[childId, doctorName, reason || null, date, notes || null]
|
||||
);
|
||||
|
||||
return NextResponse.json({ success: true, visit });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ error: String(error) }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
// PATCH - update visit
|
||||
export async function PATCH(request: Request) {
|
||||
try {
|
||||
const body = await request.json();
|
||||
const { id, doctorName, reason, date, notes } = body;
|
||||
|
||||
if (!id || !doctorName || !date) {
|
||||
return NextResponse.json({ error: "Missing required fields" }, { status: 400 });
|
||||
}
|
||||
|
||||
const [visit] = await sql.unsafe(
|
||||
`UPDATE doctor_visits SET doctor_name = $1, reason = $2, visit_date = $3, notes = $4, updated_at = NOW()
|
||||
WHERE id = $5
|
||||
RETURNING id, doctor_name as "doctorName", reason, visit_date as "date", notes`,
|
||||
[doctorName, reason, date, notes, id]
|
||||
);
|
||||
|
||||
return NextResponse.json({ success: true, visit });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ error: String(error) }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
// DELETE - delete visit
|
||||
export async function DELETE(request: Request) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const id = searchParams.get("id");
|
||||
|
||||
if (!id) {
|
||||
return NextResponse.json({ error: "ID required" }, { status: 400 });
|
||||
}
|
||||
|
||||
try {
|
||||
await sql.unsafe(`DELETE FROM doctor_visits WHERE id = $1`, [id]);
|
||||
return NextResponse.json({ success: true });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return NextResponse.json({ error: String(error) }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
|
@ -76,8 +76,6 @@ export default function MedicalPage() {
|
|||
const [tab, setTab] = useState<"vaccinations" | "medicine" | "allergies" | "visits" | "illness">("vaccinations");
|
||||
const [showAddDate, setShowAddDate] = useState<string | null>(null);
|
||||
const [givenDate, setGivenDate] = useState("");
|
||||
const [showReminder, setShowReminder] = useState<string | null>(null);
|
||||
const [reminderTime, setReminderTime] = useState("08:00");
|
||||
|
||||
// CRUD state for medicine, allergies, visits, illness
|
||||
const [medicines, setMedicines] = useState<Medicine[]>([]);
|
||||
|
|
@ -111,44 +109,85 @@ export default function MedicalPage() {
|
|||
const [newIllnessEnd, setNewIllnessEnd] = useState("");
|
||||
const [newIllnessNotes, setNewIllnessNotes] = useState("");
|
||||
|
||||
// Load data from localStorage on mount
|
||||
// Load data from database on mount
|
||||
useEffect(() => {
|
||||
// Load medicines
|
||||
const savedMeds = localStorage.getItem("tia_medicines");
|
||||
if (savedMeds) setMedicines(JSON.parse(savedMeds));
|
||||
|
||||
const savedAllergies = localStorage.getItem("tia_allergies");
|
||||
if (savedAllergies) setAllergies(JSON.parse(savedAllergies));
|
||||
|
||||
const savedVisits = localStorage.getItem("tia_visits");
|
||||
if (savedVisits) setVisits(JSON.parse(savedVisits));
|
||||
|
||||
const savedIllnesses = localStorage.getItem("tia_illnesses");
|
||||
if (savedIllnesses) setIllnesses(JSON.parse(savedIllnesses));
|
||||
fetchMedicines();
|
||||
fetchAllergies();
|
||||
fetchVisits();
|
||||
fetchIllnesses();
|
||||
}, []);
|
||||
|
||||
// Medicine CRUD
|
||||
const saveMedicine = () => {
|
||||
if (!newMedName) return;
|
||||
const newItem: Medicine = {
|
||||
id: editingMed?.id || Date.now().toString(),
|
||||
name: newMedName,
|
||||
dose: newMedDose,
|
||||
notes: newMedNotes,
|
||||
reminderTime: reminderTime,
|
||||
const fetchMedicines = async () => {
|
||||
try {
|
||||
const res = await fetch(`/api/medicines?childId=${childId}`);
|
||||
const data = await res.json();
|
||||
setMedicines(data.medicines || []);
|
||||
} catch (err) {
|
||||
console.error("Failed to fetch medicines:", err);
|
||||
}
|
||||
};
|
||||
const updated = editingMed
|
||||
? medicines.map((m) => (m.id === editingMed.id ? newItem : m))
|
||||
: [...medicines, newItem];
|
||||
setMedicines(updated);
|
||||
localStorage.setItem("tia_medicines", JSON.stringify(updated));
|
||||
|
||||
const fetchAllergies = async () => {
|
||||
try {
|
||||
const res = await fetch(`/api/allergies?childId=${childId}`);
|
||||
const data = await res.json();
|
||||
setAllergies(data.allergies || []);
|
||||
} catch (err) {
|
||||
console.error("Failed to fetch allergies:", err);
|
||||
}
|
||||
};
|
||||
|
||||
const fetchVisits = async () => {
|
||||
try {
|
||||
const res = await fetch(`/api/visits?childId=${childId}`);
|
||||
const data = await res.json();
|
||||
setVisits(data.visits || []);
|
||||
} catch (err) {
|
||||
console.error("Failed to fetch visits:", err);
|
||||
}
|
||||
};
|
||||
|
||||
const fetchIllnesses = async () => {
|
||||
try {
|
||||
const res = await fetch(`/api/illnesses?childId=${childId}`);
|
||||
const data = await res.json();
|
||||
setIllnesses(data.illnesses || []);
|
||||
} catch (err) {
|
||||
console.error("Failed to fetch illnesses:", err);
|
||||
}
|
||||
};
|
||||
|
||||
// Medicine CRUD - now using database
|
||||
const saveMedicine = async () => {
|
||||
if (!newMedName) return;
|
||||
try {
|
||||
if (editingMed) {
|
||||
await fetch(`/api/medicines`, {
|
||||
method: "PATCH",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ id: editingMed.id, name: newMedName, dose: newMedDose, notes: newMedNotes }),
|
||||
});
|
||||
} else {
|
||||
await fetch("/api/medicines", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ childId, name: newMedName, dose: newMedDose, notes: newMedNotes }),
|
||||
});
|
||||
}
|
||||
fetchMedicines();
|
||||
} catch (err) {
|
||||
console.error("Failed to save:", err);
|
||||
}
|
||||
resetMedForm();
|
||||
};
|
||||
|
||||
const deleteMedicine = (id: string) => {
|
||||
const updated = medicines.filter((m) => m.id !== id);
|
||||
setMedicines(updated);
|
||||
localStorage.setItem("tia_medicines", JSON.stringify(updated));
|
||||
const deleteMedicine = async (id: string) => {
|
||||
try {
|
||||
await fetch(`/api/medicines?id=${id}`, { method: "DELETE" });
|
||||
fetchMedicines();
|
||||
} catch (err) {
|
||||
console.error("Failed to delete:", err);
|
||||
}
|
||||
};
|
||||
|
||||
const editMedicine = (med: Medicine) => {
|
||||
|
|
@ -156,7 +195,6 @@ export default function MedicalPage() {
|
|||
setNewMedName(med.name);
|
||||
setNewMedDose(med.dose);
|
||||
setNewMedNotes(med.notes);
|
||||
setReminderTime(med.reminderTime || "08:00");
|
||||
setShowAddMed(true);
|
||||
};
|
||||
|
||||
|
|
@ -168,27 +206,37 @@ export default function MedicalPage() {
|
|||
setShowAddMed(false);
|
||||
};
|
||||
|
||||
// Allergy CRUD
|
||||
const saveAllergy = () => {
|
||||
// Allergy CRUD - now using database
|
||||
const saveAllergy = async () => {
|
||||
if (!newAllergyName) return;
|
||||
const newItem: Allergy = {
|
||||
id: editingAllergy?.id || Date.now().toString(),
|
||||
name: newAllergyName,
|
||||
severity: newAllergySeverity,
|
||||
notes: newAllergyNotes,
|
||||
};
|
||||
const updated = editingAllergy
|
||||
? allergies.map((a) => (a.id === editingAllergy.id ? newItem : a))
|
||||
: [...allergies, newItem];
|
||||
setAllergies(updated);
|
||||
localStorage.setItem("tia_allergies", JSON.stringify(updated));
|
||||
try {
|
||||
if (editingAllergy) {
|
||||
await fetch(`/api/allergies`, {
|
||||
method: "PATCH",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ id: editingAllergy.id, name: newAllergyName, severity: newAllergySeverity, notes: newAllergyNotes }),
|
||||
});
|
||||
} else {
|
||||
await fetch("/api/allergies", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ childId, name: newAllergyName, severity: newAllergySeverity, notes: newAllergyNotes }),
|
||||
});
|
||||
}
|
||||
fetchAllergies();
|
||||
} catch (err) {
|
||||
console.error("Failed to save:", err);
|
||||
}
|
||||
resetAllergyForm();
|
||||
};
|
||||
|
||||
const deleteAllergy = (id: string) => {
|
||||
const updated = allergies.filter((a) => a.id !== id);
|
||||
setAllergies(updated);
|
||||
localStorage.setItem("tia_allergies", JSON.stringify(updated));
|
||||
const deleteAllergy = async (id: string) => {
|
||||
try {
|
||||
await fetch(`/api/allergies?id=${id}`, { method: "DELETE" });
|
||||
fetchAllergies();
|
||||
} catch (err) {
|
||||
console.error("Failed to delete:", err);
|
||||
}
|
||||
};
|
||||
|
||||
const editAllergy = (allergy: Allergy) => {
|
||||
|
|
@ -207,28 +255,37 @@ export default function MedicalPage() {
|
|||
setShowAddAllergy(false);
|
||||
};
|
||||
|
||||
// Visit CRUD
|
||||
const saveVisit = () => {
|
||||
// Visit CRUD - now using database
|
||||
const saveVisit = async () => {
|
||||
if (!newVisitDoctor) return;
|
||||
const newItem: Visit = {
|
||||
id: editingVisit?.id || Date.now().toString(),
|
||||
doctorName: newVisitDoctor,
|
||||
reason: newVisitReason,
|
||||
date: newVisitDate || new Date().toISOString().split("T")[0],
|
||||
notes: newVisitNotes,
|
||||
};
|
||||
const updated = editingVisit
|
||||
? visits.map((v) => (v.id === editingVisit.id ? newItem : v))
|
||||
: [...visits, newItem];
|
||||
setVisits(updated);
|
||||
localStorage.setItem("tia_visits", JSON.stringify(updated));
|
||||
try {
|
||||
if (editingVisit) {
|
||||
await fetch(`/api/visits`, {
|
||||
method: "PATCH",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ id: editingVisit.id, doctorName: newVisitDoctor, reason: newVisitReason, date: newVisitDate, notes: newVisitNotes }),
|
||||
});
|
||||
} else {
|
||||
await fetch("/api/visits", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ childId, doctorName: newVisitDoctor, reason: newVisitReason, date: newVisitDate, notes: newVisitNotes }),
|
||||
});
|
||||
}
|
||||
fetchVisits();
|
||||
} catch (err) {
|
||||
console.error("Failed to save:", err);
|
||||
}
|
||||
resetVisitForm();
|
||||
};
|
||||
|
||||
const deleteVisit = (id: string) => {
|
||||
const updated = visits.filter((v) => v.id !== id);
|
||||
setVisits(updated);
|
||||
localStorage.setItem("tia_visits", JSON.stringify(updated));
|
||||
const deleteVisit = async (id: string) => {
|
||||
try {
|
||||
await fetch(`/api/visits?id=${id}`, { method: "DELETE" });
|
||||
fetchVisits();
|
||||
} catch (err) {
|
||||
console.error("Failed to delete:", err);
|
||||
}
|
||||
};
|
||||
|
||||
const editVisit = (visit: Visit) => {
|
||||
|
|
@ -249,28 +306,37 @@ export default function MedicalPage() {
|
|||
setShowAddVisit(false);
|
||||
};
|
||||
|
||||
// Illness CRUD
|
||||
const saveIllness = () => {
|
||||
// Illness CRUD - now using database
|
||||
const saveIllness = async () => {
|
||||
if (!newIllnessName) return;
|
||||
const newItem: Illness = {
|
||||
id: editingIllness?.id || Date.now().toString(),
|
||||
name: newIllnessName,
|
||||
startDate: newIllnessStart || new Date().toISOString().split("T")[0],
|
||||
endDate: newIllnessEnd || undefined,
|
||||
notes: newIllnessNotes,
|
||||
};
|
||||
const updated = editingIllness
|
||||
? illnesses.map((i) => (i.id === editingIllness.id ? newItem : i))
|
||||
: [...illnesses, newItem];
|
||||
setIllnesses(updated);
|
||||
localStorage.setItem("tia_illnesses", JSON.stringify(updated));
|
||||
try {
|
||||
if (editingIllness) {
|
||||
await fetch(`/api/illnesses`, {
|
||||
method: "PATCH",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ id: editingIllness.id, name: newIllnessName, startDate: newIllnessStart, endDate: newIllnessEnd, notes: newIllnessNotes }),
|
||||
});
|
||||
} else {
|
||||
await fetch("/api/illnesses", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ childId, name: newIllnessName, startDate: newIllnessStart, endDate: newIllnessEnd, notes: newIllnessNotes }),
|
||||
});
|
||||
}
|
||||
fetchIllnesses();
|
||||
} catch (err) {
|
||||
console.error("Failed to save:", err);
|
||||
}
|
||||
resetIllnessForm();
|
||||
};
|
||||
|
||||
const deleteIllness = (id: string) => {
|
||||
const updated = illnesses.filter((i) => i.id !== id);
|
||||
setIllnesses(updated);
|
||||
localStorage.setItem("tia_illnesses", JSON.stringify(updated));
|
||||
const deleteIllness = async (id: string) => {
|
||||
try {
|
||||
await fetch(`/api/illnesses?id=${id}`, { method: "DELETE" });
|
||||
fetchIllnesses();
|
||||
} catch (err) {
|
||||
console.error("Failed to delete:", err);
|
||||
}
|
||||
};
|
||||
|
||||
const editIllness = (illness: Illness) => {
|
||||
|
|
@ -291,13 +357,6 @@ export default function MedicalPage() {
|
|||
setShowAddIllness(false);
|
||||
};
|
||||
|
||||
// Reminder save handler
|
||||
const handleSetReminder = (medName: string) => {
|
||||
// In production, save to database with reminder time
|
||||
alert(`Reminder set for ${medName} at ${reminderTime}`);
|
||||
setShowReminder(null);
|
||||
};
|
||||
|
||||
const birthDate = "2024-01-15";
|
||||
|
||||
// Common supplements for babies
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue