tia/src/app/medical/page.tsx
Mannu 70aa35384b fix(medical): dark mode support and tab wrapping fix
Added dark: variants to all cards, inputs, selects, text, and buttons
throughout the medical page. Added whitespace-nowrap + flex-shrink-0 to
all tab buttons to prevent labels like "Doctor Visit" from wrapping.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 13:22:14 +05:30

873 lines
No EOL
35 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 { useFamily } from "../FamilyProvider";
interface Medicine {
id: string;
name: string;
dose: string;
notes: string;
reminderTime?: string;
}
interface Allergy {
id: string;
name: string;
severity: string;
notes: string;
}
interface Visit {
id: string;
doctorName: string;
reason: string;
date: string;
notes: string;
}
interface Illness {
id: string;
name: string;
startDate: string;
endDate?: string;
notes: string;
}
// IAP Vaccination Schedule (India)
const IAP_SCHEDULE = [
{ name: "BCG", weeks: 0 },
{ name: "OPV-0", weeks: 0 },
{ name: "HepB-1", weeks: 0 },
{ name: "OPV-1", weeks: 6 },
{ name: "Pentavalent-1", weeks: 6 },
{ name: "PCV-1", weeks: 6 },
{ name: "Rota-1", weeks: 6 },
{ name: "OPV-2", weeks: 10 },
{ name: "Pentavalent-2", weeks: 10 },
{ name: "PCV-2", weeks: 10 },
{ name: "Rota-2", weeks: 10 },
{ name: "OPV-3", weeks: 14 },
{ name: "Pentavalent-3", weeks: 14 },
{ name: "PCV-3", weeks: 14 },
{ name: "Rota-3", weeks: 14 },
{ name: "MR-1", weeks: 48 }, // 9 months
{ name: "JE-1", weeks: 48 },
{ name: "Vitamin A-1", weeks: 48 },
{ name: "OPV-4", weeks: 48 },
{ name: "MR-2", weeks: 96 }, // 18 months
{ name: "JE-2", weeks: 96 },
{ name: "DPT-Booster-1", weeks: 96 },
{ name: "Vitamin A-2", weeks: 96 },
{ name: "OPV-5", weeks: 96 },
{ name: "DPT-Booster-2", weeks: 208 }, // 4 years
{ name: "Tetanus and adult diphtheria (Td)", weeks: 208 },
];
function calculateDueDate(birthDate: string, weeks: number): string {
const birth = new Date(birthDate);
birth.setDate(birth.getDate() + weeks * 7);
return birth.toISOString().split("T")[0];
}
export default function MedicalPage() {
const [vaccinations, setVaccinations] = useState<any[]>([]);
const [loading, setLoading] = useState(true);
const { childId: sessionChildId, child, loading: loadingChild } = useFamily();
const [tab, setTab] = useState<"vaccinations" | "medicine" | "allergies" | "visits" | "illness">("vaccinations");
const [vaccineTab, setVaccineTab] = useState<"upcoming" | "completed" | "overdue">("upcoming");
const [showAddDate, setShowAddDate] = useState<string | null>(null);
const [givenDate, setGivenDate] = useState("");
// CRUD state for medicine, allergies, visits, illness
const [medicines, setMedicines] = useState<Medicine[]>([]);
const [allergies, setAllergies] = useState<Allergy[]>([]);
const [visits, setVisits] = useState<Visit[]>([]);
const [illnesses, setIllnesses] = useState<Illness[]>([]);
// Add/Edit mode
const [editingMed, setEditingMed] = useState<Medicine | null>(null);
const [editingAllergy, setEditingAllergy] = useState<Allergy | null>(null);
const [editingVisit, setEditingVisit] = useState<Visit | null>(null);
const [editingIllness, setEditingIllness] = useState<Illness | null>(null);
const [showAddMed, setShowAddMed] = useState(false);
const [showAddAllergy, setShowAddAllergy] = useState(false);
const [showAddVisit, setShowAddVisit] = useState(false);
const [showAddIllness, setShowAddIllness] = useState(false);
// Form state for new items
const [newMedName, setNewMedName] = useState("");
const [newMedDose, setNewMedDose] = useState("");
const [newMedNotes, setNewMedNotes] = useState("");
const [newAllergyName, setNewAllergyName] = useState("");
const [newAllergySeverity, setNewAllergySeverity] = useState("mild");
const [newAllergyNotes, setNewAllergyNotes] = useState("");
const [newVisitDoctor, setNewVisitDoctor] = useState("");
const [newVisitReason, setNewVisitReason] = useState("");
const [newVisitDate, setNewVisitDate] = useState("");
const [newVisitNotes, setNewVisitNotes] = useState("");
const [newIllnessName, setNewIllnessName] = useState("");
const [newIllnessStart, setNewIllnessStart] = useState("");
const [newIllnessEnd, setNewIllnessEnd] = useState("");
const [newIllnessNotes, setNewIllnessNotes] = useState("");
// Load data from database on mount
useEffect(() => {
fetchMedicines();
fetchAllergies();
fetchVisits();
fetchIllnesses();
}, []);
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 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 = 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) => {
setEditingMed(med);
setNewMedName(med.name);
setNewMedDose(med.dose);
setNewMedNotes(med.notes);
setShowAddMed(true);
};
const resetMedForm = () => {
setEditingMed(null);
setNewMedName("");
setNewMedDose("");
setNewMedNotes("");
setShowAddMed(false);
};
// Allergy CRUD - now using database
const saveAllergy = async () => {
if (!newAllergyName) return;
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 = 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) => {
setEditingAllergy(allergy);
setNewAllergyName(allergy.name);
setNewAllergySeverity(allergy.severity);
setNewAllergyNotes(allergy.notes);
setShowAddAllergy(true);
};
const resetAllergyForm = () => {
setEditingAllergy(null);
setNewAllergyName("");
setNewAllergySeverity("mild");
setNewAllergyNotes("");
setShowAddAllergy(false);
};
// Visit CRUD - now using database
const saveVisit = async () => {
if (!newVisitDoctor) return;
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 = 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) => {
setEditingVisit(visit);
setNewVisitDoctor(visit.doctorName);
setNewVisitReason(visit.reason);
setNewVisitDate(visit.date);
setNewVisitNotes(visit.notes);
setShowAddVisit(true);
};
const resetVisitForm = () => {
setEditingVisit(null);
setNewVisitDoctor("");
setNewVisitReason("");
setNewVisitDate("");
setNewVisitNotes("");
setShowAddVisit(false);
};
// Illness CRUD - now using database
const saveIllness = async () => {
if (!newIllnessName) return;
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 = 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) => {
setEditingIllness(illness);
setNewIllnessName(illness.name);
setNewIllnessStart(illness.startDate);
setNewIllnessEnd(illness.endDate || "");
setNewIllnessNotes(illness.notes);
setShowAddIllness(true);
};
const resetIllnessForm = () => {
setEditingIllness(null);
setNewIllnessName("");
setNewIllnessStart("");
setNewIllnessEnd("");
setNewIllnessNotes("");
setShowAddIllness(false);
};
const childId = sessionChildId;
const birthDate = child?.birthDate || "2024-01-15";
// Common supplements for babies
const SUPPLEMENTS = [
{ name: "Vitamin D3", dose: "400 IU daily", notes: "For bone health" },
{ name: "Iron", dose: "1 mg/kg daily", notes: "As prescribed" },
{ name: "Calcium", dose: "500 mg daily", notes: "With food" },
{ name: "Zinc", dose: "5 mg daily", notes: "Immune support" },
{ name: "Omega-3", dose: "DHA 100mg", notes: "Brain development" },
{ name: "Probiotics", dose: "1 shot daily", notes: "Gut health" },
{ name: "Multivitamin", dose: "As directed", notes: "Daily vitamin" },
];
useEffect(() => {
fetch(`/api/vaccinations?childId=${childId}`)
.then((res) => res.json())
.then((data) => {
setVaccinations(data.vaccinations || []);
setLoading(false);
})
.catch(() => setLoading(false));
}, [childId]);
const handleMarkGiven = async (vaccineName: string) => {
const dueDate = calculateDueDate(birthDate, IAP_SCHEDULE.find((v) => v.name === vaccineName)?.weeks || 0);
const dateToSave = givenDate || new Date().toISOString().split("T")[0];
await fetch("/api/vaccinations", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
childId,
vaccineName,
scheduledDate: dueDate,
givenDate: dateToSave,
status: "given",
}),
});
setVaccinations((prev) => [...prev, { vaccine_name: vaccineName, given_date: dateToSave, status: "given" }]);
setShowAddDate(null);
setGivenDate("");
};
const isGiven = (name: string) => vaccinations.some((v) => v.vaccine_name === name && v.status === "given");
const getGivenDate = (name: string) => vaccinations.find((v) => v.vaccine_name === name && v.status === "given")?.given_date;
const isPending = (name: string) => !isGiven(name);
// Get vaccines by status
const getVaccinesByStatus = (status: "upcoming" | "completed" | "overdue") => {
const today = new Date();
const todayStr = today.toISOString().split("T")[0];
return IAP_SCHEDULE.filter((v) => {
const dueDate = calculateDueDate(birthDate, v.weeks);
const given = isGiven(v.name);
if (status === "completed") return given;
if (status === "overdue") return !given && dueDate < todayStr;
if (status === "upcoming") return !given && dueDate >= todayStr;
return false;
}).sort((a, b) => a.weeks - b.weeks);
};
const getVaccineStatus = (name: string) => {
const dueDate = calculateDueDate(birthDate, IAP_SCHEDULE.find((v) => v.name === name)?.weeks || 0);
const today = new Date();
const todayStr = today.toISOString().split("T")[0];
const given = isGiven(name);
if (given) return "completed";
if (dueDate < todayStr) return "overdue";
return "upcoming";
};
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">
<div className="flex justify-between items-center">
<a href="/menu" className="p-2"></a>
<h1 className="text-xl font-bold">Medical</h1>
</div>
<div className="flex gap-2 mb-6 overflow-x-auto">
<button
onClick={() => setTab("vaccinations")}
className={`px-4 p-3 rounded-xl whitespace-nowrap flex-shrink-0 ${tab === "vaccinations" ? "bg-rose-400 text-white" : "bg-white dark:bg-gray-800 dark:text-white"}`}
>
Vaccines
</button>
<button
onClick={() => setTab("medicine")}
className={`px-4 p-3 rounded-xl whitespace-nowrap flex-shrink-0 ${tab === "medicine" ? "bg-rose-400 text-white" : "bg-white dark:bg-gray-800 dark:text-white"}`}
>
Medicine
</button>
<button
onClick={() => setTab("allergies")}
className={`px-4 p-3 rounded-xl whitespace-nowrap flex-shrink-0 ${tab === "allergies" ? "bg-rose-400 text-white" : "bg-white dark:bg-gray-800 dark:text-white"}`}
>
Allergies
</button>
<button
onClick={() => setTab("visits")}
className={`px-4 p-3 rounded-xl whitespace-nowrap flex-shrink-0 ${tab === "visits" ? "bg-rose-400 text-white" : "bg-white dark:bg-gray-800 dark:text-white"}`}
>
Doctor Visit
</button>
<button
onClick={() => setTab("illness")}
className={`px-4 p-3 rounded-xl whitespace-nowrap flex-shrink-0 ${tab === "illness" ? "bg-rose-400 text-white" : "bg-white dark:bg-gray-800 dark:text-white"}`}
>
Illness
</button>
</div>
{tab === "vaccinations" && (
<div className="space-y-2">
<div className="flex gap-2 mb-4 overflow-x-auto">
<button
onClick={() => setVaccineTab("upcoming")}
className={`px-4 py-2 rounded-xl whitespace-nowrap flex-shrink-0 ${vaccineTab === "upcoming" ? "bg-rose-400 text-white" : "bg-white dark:bg-gray-800 dark:text-white"}`}
>
Upcoming ({getVaccinesByStatus("upcoming").length})
</button>
<button
onClick={() => setVaccineTab("completed")}
className={`px-4 py-2 rounded-xl whitespace-nowrap flex-shrink-0 ${vaccineTab === "completed" ? "bg-rose-400 text-white" : "bg-white dark:bg-gray-800 dark:text-white"}`}
>
Completed ({getVaccinesByStatus("completed").length})
</button>
<button
onClick={() => setVaccineTab("overdue")}
className={`px-4 py-2 rounded-xl whitespace-nowrap flex-shrink-0 ${vaccineTab === "overdue" ? "bg-red-500 text-white" : "bg-white dark:bg-gray-800 dark:text-white"}`}
>
Overdue ({getVaccinesByStatus("overdue").length})
</button>
</div>
<h2 className="font-semibold mb-3">IAP Schedule</h2>
{loading ? (
<p className="text-gray-500">Loading...</p>
) : (
getVaccinesByStatus(vaccineTab).map((vaccine) => {
const given = isGiven(vaccine.name);
const actualDate = getGivenDate(vaccine.name);
const dueDate = calculateDueDate(birthDate, vaccine.weeks);
const status = getVaccineStatus(vaccine.name);
const daysOverdue = status === "overdue" ? Math.floor((new Date().getTime() - new Date(dueDate).getTime()) / (1000 * 60 * 60 * 24)) : 0;
return (
<div
key={vaccine.name}
className={`p-4 bg-white dark:bg-gray-800 rounded-xl ${status === "completed" ? "opacity-60" : ""} ${status === "overdue" ? "border-l-4 border-red-500" : ""}`}
>
<div className="flex items-center justify-between">
<div className="flex-1">
<div className="font-medium">{vaccine.name}</div>
<div className="text-sm text-gray-500 dark:text-gray-400">
Due: {new Date(dueDate).toLocaleDateString()}
{actualDate && ` · Given: ${new Date(actualDate).toLocaleDateString()}`}
</div>
{status === "overdue" && (
<div className="text-red-500 text-sm font-medium">{daysOverdue} days overdue</div>
)}
</div>
{given ? (
<span className="text-green-500"></span>
) : showAddDate === vaccine.name ? (
<div className="flex gap-2">
<input
type="date"
value={givenDate}
onChange={(e) => setGivenDate(e.target.value)}
className="p-1 text-sm border dark:border-gray-600 rounded dark:bg-gray-700 dark:text-white"
placeholder="Date given"
/>
<button
onClick={() => handleMarkGiven(vaccine.name)}
className="px-3 py-1 bg-rose-400 text-white rounded-lg text-sm"
>
</button>
<button
onClick={() => { setShowAddDate(null); setGivenDate(""); }}
className="px-2 py-1 text-gray-400"
>
</button>
</div>
) : (
<button
onClick={() => setShowAddDate(vaccine.name)}
className="px-4 py-2 bg-rose-400 text-white rounded-lg text-sm"
>
Mark Given
</button>
)}
</div>
</div>
);
})
)}
</div>
)}
{tab === "medicine" && (
<div className="space-y-2">
<h2 className="font-semibold mb-3">Medicine & Supplements</h2>
{/* Add Form */}
{showAddMed && (
<div className="p-4 bg-white dark:bg-gray-800 rounded-xl space-y-3">
<input
type="text"
value={newMedName}
onChange={(e) => setNewMedName(e.target.value)}
placeholder="Medicine name"
className="w-full p-2 border dark:border-gray-600 rounded-lg dark:bg-gray-700 dark:text-white dark:placeholder-gray-400"
/>
<input
type="text"
value={newMedDose}
onChange={(e) => setNewMedDose(e.target.value)}
placeholder="Dose (e.g., 5ml, 1 tablet)"
className="w-full p-2 border dark:border-gray-600 rounded-lg dark:bg-gray-700 dark:text-white dark:placeholder-gray-400"
/>
<input
type="text"
value={newMedNotes}
onChange={(e) => setNewMedNotes(e.target.value)}
placeholder="Notes"
className="w-full p-2 border dark:border-gray-600 rounded-lg dark:bg-gray-700 dark:text-white dark:placeholder-gray-400"
/>
<div className="flex gap-2">
<button onClick={saveMedicine} className="flex-1 py-2 bg-rose-400 text-white rounded-lg">
{editingMed ? "Update" : "Add"}
</button>
<button onClick={resetMedForm} className="flex-1 py-2 bg-gray-200 dark:bg-gray-600 dark:text-white rounded-lg">
Cancel
</button>
</div>
</div>
)}
{medicines.length === 0 && !showAddMed ? (
<div className="p-4 bg-white dark:bg-gray-800 rounded-xl">
<p className="text-gray-500 dark:text-gray-400">No medicines added</p>
</div>
) : (
medicines.map((med) => (
<div key={med.id} className="p-4 bg-white dark:bg-gray-800 rounded-xl">
<div className="flex items-center justify-between">
<div className="flex-1">
<div className="font-medium">{med.name}</div>
<div className="text-sm text-gray-500 dark:text-gray-400">
{med.dose} {med.notes && `· ${med.notes}`}
{med.reminderTime && ` · ⏰ ${med.reminderTime}`}
</div>
</div>
<div className="flex gap-2">
<button onClick={() => editMedicine(med)} className="p-2 text-gray-400"></button>
<button onClick={() => deleteMedicine(med.id)} className="p-2 text-red-400">🗑</button>
</div>
</div>
</div>
))
)}
{!showAddMed && (
<button onClick={() => setShowAddMed(true)} className="w-full p-4 border-2 border-dashed border-gray-300 dark:border-gray-600 rounded-xl text-gray-500 dark:text-gray-400">
+ Add Medicine
</button>
)}
</div>
)}
{tab === "allergies" && (
<div className="space-y-2">
<h2 className="font-semibold mb-3">Known Allergies</h2>
{showAddAllergy && (
<div className="p-4 bg-white dark:bg-gray-800 rounded-xl space-y-3">
<input
type="text"
value={newAllergyName}
onChange={(e) => setNewAllergyName(e.target.value)}
placeholder="Allergy name (e.g., Peanut, Milk)"
className="w-full p-2 border dark:border-gray-600 rounded-lg dark:bg-gray-700 dark:text-white dark:placeholder-gray-400"
/>
<select
value={newAllergySeverity}
onChange={(e) => setNewAllergySeverity(e.target.value)}
className="w-full p-2 border dark:border-gray-600 rounded-lg dark:bg-gray-700 dark:text-white"
>
<option value="mild">Mild</option>
<option value="moderate">Moderate</option>
<option value="severe">Severe</option>
</select>
<input
type="text"
value={newAllergyNotes}
onChange={(e) => setNewAllergyNotes(e.target.value)}
placeholder="Notes"
className="w-full p-2 border dark:border-gray-600 rounded-lg dark:bg-gray-700 dark:text-white dark:placeholder-gray-400"
/>
<div className="flex gap-2">
<button onClick={saveAllergy} className="flex-1 py-2 bg-rose-400 text-white rounded-lg">
{editingAllergy ? "Update" : "Add"}
</button>
<button onClick={resetAllergyForm} className="flex-1 py-2 bg-gray-200 dark:bg-gray-600 dark:text-white rounded-lg">
Cancel
</button>
</div>
</div>
)}
{allergies.length === 0 && !showAddAllergy ? (
<div className="p-4 bg-white dark:bg-gray-800 rounded-xl">
<p className="text-gray-500 dark:text-gray-400">No allergies recorded</p>
</div>
) : (
allergies.map((allergy) => (
<div key={allergy.id} className="p-4 bg-white dark:bg-gray-800 rounded-xl">
<div className="flex items-center justify-between">
<div className="flex-1">
<div className="font-medium">{allergy.name}</div>
<div className="text-sm text-gray-500 dark:text-gray-400">
<span className={allergy.severity === "severe" ? "text-red-500" : "text-orange-500"}>
{allergy.severity.toUpperCase()}
</span>
{allergy.notes && ` · ${allergy.notes}`}
</div>
</div>
<div className="flex gap-2">
<button onClick={() => editAllergy(allergy)} className="p-2 text-gray-400"></button>
<button onClick={() => deleteAllergy(allergy.id)} className="p-2 text-red-400">🗑</button>
</div>
</div>
</div>
))
)}
{!showAddAllergy && (
<button onClick={() => setShowAddAllergy(true)} className="w-full p-4 border-2 border-dashed border-gray-300 dark:border-gray-600 rounded-xl text-gray-500 dark:text-gray-400">
+ Add Allergy
</button>
)}
</div>
)}
{tab === "visits" && (
<div className="space-y-2">
<h2 className="font-semibold mb-3">Doctor Visits</h2>
{showAddVisit && (
<div className="p-4 bg-white dark:bg-gray-800 rounded-xl space-y-3">
<input
type="text"
value={newVisitDoctor}
onChange={(e) => setNewVisitDoctor(e.target.value)}
placeholder="Doctor name"
className="w-full p-2 border dark:border-gray-600 rounded-lg dark:bg-gray-700 dark:text-white dark:placeholder-gray-400"
/>
<input
type="text"
value={newVisitReason}
onChange={(e) => setNewVisitReason(e.target.value)}
placeholder="Reason (e.g., Checkup, Fever)"
className="w-full p-2 border dark:border-gray-600 rounded-lg dark:bg-gray-700 dark:text-white dark:placeholder-gray-400"
/>
<input
type="date"
value={newVisitDate}
onChange={(e) => setNewVisitDate(e.target.value)}
className="w-full p-2 border dark:border-gray-600 rounded-lg dark:bg-gray-700 dark:text-white"
/>
<input
type="text"
value={newVisitNotes}
onChange={(e) => setNewVisitNotes(e.target.value)}
placeholder="Notes"
className="w-full p-2 border dark:border-gray-600 rounded-lg dark:bg-gray-700 dark:text-white dark:placeholder-gray-400"
/>
<div className="flex gap-2">
<button onClick={saveVisit} className="flex-1 py-2 bg-rose-400 text-white rounded-lg">
{editingVisit ? "Update" : "Add"}
</button>
<button onClick={resetVisitForm} className="flex-1 py-2 bg-gray-200 dark:bg-gray-600 dark:text-white rounded-lg">
Cancel
</button>
</div>
</div>
)}
{visits.length === 0 && !showAddVisit ? (
<div className="p-4 bg-white dark:bg-gray-800 rounded-xl">
<p className="text-gray-500 dark:text-gray-400">No visits recorded</p>
</div>
) : (
visits.map((visit) => (
<div key={visit.id} className="p-4 bg-white dark:bg-gray-800 rounded-xl">
<div className="flex items-center justify-between">
<div className="flex-1">
<div className="font-medium">{visit.doctorName}</div>
<div className="text-sm text-gray-500 dark:text-gray-400">
{new Date(visit.date).toLocaleDateString()}
{visit.reason && ` · ${visit.reason}`}
{visit.notes && ` · ${visit.notes}`}
</div>
</div>
<div className="flex gap-2">
<button onClick={() => editVisit(visit)} className="p-2 text-gray-400"></button>
<button onClick={() => deleteVisit(visit.id)} className="p-2 text-red-400">🗑</button>
</div>
</div>
</div>
))
)}
{!showAddVisit && (
<button onClick={() => setShowAddVisit(true)} className="w-full p-4 border-2 border-dashed border-gray-300 dark:border-gray-600 rounded-xl text-gray-500 dark:text-gray-400">
+ Add Visit
</button>
)}
</div>
)}
{tab === "illness" && (
<div className="space-y-2">
<h2 className="font-semibold mb-3">Illness Log</h2>
{showAddIllness && (
<div className="p-4 bg-white dark:bg-gray-800 rounded-xl space-y-3">
<input
type="text"
value={newIllnessName}
onChange={(e) => setNewIllnessName(e.target.value)}
placeholder="Illness (e.g., Cold, Fever, Flu)"
className="w-full p-2 border dark:border-gray-600 rounded-lg dark:bg-gray-700 dark:text-white dark:placeholder-gray-400"
/>
<div className="grid grid-cols-2 gap-2">
<input
type="date"
value={newIllnessStart}
onChange={(e) => setNewIllnessStart(e.target.value)}
placeholder="Start date"
className="w-full p-2 border dark:border-gray-600 rounded-lg dark:bg-gray-700 dark:text-white"
/>
<input
type="date"
value={newIllnessEnd}
onChange={(e) => setNewIllnessEnd(e.target.value)}
placeholder="End date"
className="w-full p-2 border dark:border-gray-600 rounded-lg dark:bg-gray-700 dark:text-white"
/>
</div>
<input
type="text"
value={newIllnessNotes}
onChange={(e) => setNewIllnessNotes(e.target.value)}
placeholder="Notes"
className="w-full p-2 border dark:border-gray-600 rounded-lg dark:bg-gray-700 dark:text-white dark:placeholder-gray-400"
/>
<div className="flex gap-2">
<button onClick={saveIllness} className="flex-1 py-2 bg-rose-400 text-white rounded-lg">
{editingIllness ? "Update" : "Add"}
</button>
<button onClick={resetIllnessForm} className="flex-1 py-2 bg-gray-200 dark:bg-gray-600 dark:text-white rounded-lg">
Cancel
</button>
</div>
</div>
)}
{illnesses.length === 0 && !showAddIllness ? (
<div className="p-4 bg-white dark:bg-gray-800 rounded-xl">
<p className="text-gray-500 dark:text-gray-400">No illnesses recorded</p>
</div>
) : (
illnesses.map((illness) => (
<div key={illness.id} className="p-4 bg-white dark:bg-gray-800 rounded-xl">
<div className="flex items-center justify-between">
<div className="flex-1">
<div className="font-medium">{illness.name}</div>
<div className="text-sm text-gray-500 dark:text-gray-400">
{new Date(illness.startDate).toLocaleDateString()}
{illness.endDate && ` - ${new Date(illness.endDate).toLocaleDateString()}`}
{illness.notes && ` · ${illness.notes}`}
</div>
</div>
<div className="flex gap-2">
<button onClick={() => editIllness(illness)} className="p-2 text-gray-400"></button>
<button onClick={() => deleteIllness(illness.id)} className="p-2 text-red-400">🗑</button>
</div>
</div>
</div>
))
)}
{!showAddIllness && (
<button onClick={() => setShowAddIllness(true)} className="w-full p-4 border-2 border-dashed border-gray-300 dark:border-gray-600 rounded-xl text-gray-500 dark:text-gray-400">
+ Log Illness
</button>
)}
</div>
)}
</div>
</div>
);
}