import React, { useState, useCallback } from 'react'; import { Plus, Trash2, CheckCircle, Trophy, AlertTriangle, Quote, Calendar, Edit2, X, Save, Clock } from 'lucide-react'; import { Medication, PatientProfile } from '../types'; interface MedicationTrackerProps { medications: Medication[]; setMedications: React.Dispatch>; profile: PatientProfile; setProfile: React.Dispatch>; } const MOTIVATIONAL_QUOTES = [ "Success is stumbling from failure to failure with no loss of enthusiasm. – Winston Churchill", "Fall seven times, stand up eight. – Japanese Proverb", "The only real mistake is the one from which we learn nothing. – Henry Ford", "It does not matter how slowly you go as long as you do not stop. – Confucius" ]; // Helper to get local date string YYYY-MM-DD const getLocalTodayString = () => { const now = new Date(); const year = now.getFullYear(); const month = String(now.getMonth() + 1).padStart(2, '0'); const day = String(now.getDate()).padStart(2, '0'); return `${year}-${month}-${day}`; }; // Check if med is active today const isDueToday = (med: Medication) => { const today = getLocalTodayString(); // If start date exists and is in the future, it's not due if (med.startDate && med.startDate > today) return false; // If end date exists and is in the past, it's not due if (med.endDate && med.endDate < today) return false; return true; }; // Memoized item const MedicationItem = React.memo(({ med, editingId, onToggle, onEdit, onDelete }: { med: Medication; editingId: string | null; onToggle: (id: string) => void; onEdit: (med: Medication) => void; onDelete: (id: string) => void; }) => { const isDue = isDueToday(med); return (

{med.name} {!isDue && NOT DUE TODAY}

{med.dosage} • {med.time} {(med.startDate || med.endDate) && ( {med.startDate || 'Now'} → {med.endDate || 'Ongoing'} )}
); }); const MedicationTracker: React.FC = ({ medications, setMedications, profile, setProfile }) => { const [newMedName, setNewMedName] = useState(''); const [newMedDosage, setNewMedDosage] = useState(''); const [newMedTime, setNewMedTime] = useState('09:00'); const [startDate, setStartDate] = useState(''); const [endDate, setEndDate] = useState(''); // Edit Mode State const [editingId, setEditingId] = useState(null); const resetForm = () => { setNewMedName(''); setNewMedDosage(''); setNewMedTime('09:00'); setStartDate(''); setEndDate(''); setEditingId(null); }; const handleEdit = useCallback((med: Medication) => { setNewMedName(med.name); setNewMedDosage(med.dosage); setNewMedTime(med.time); setStartDate(med.startDate || ''); setEndDate(med.endDate || ''); setEditingId(med.id); }, []); const handleUpdate = () => { if (!editingId || !newMedName || !newMedDosage) return; setMedications(prev => prev.map(med => { if (med.id === editingId) { return { ...med, name: newMedName, dosage: newMedDosage, time: newMedTime, startDate: startDate || undefined, endDate: endDate || undefined }; } return med; })); resetForm(); }; const addMedication = () => { if (!newMedName || !newMedDosage) return; const newMed: Medication = { id: Date.now().toString(), name: newMedName, dosage: newMedDosage, time: newMedTime, taken: false, startDate: startDate || undefined, endDate: endDate || undefined }; setMedications(prev => [...prev, newMed]); resetForm(); }; const removeMedication = useCallback((id: string) => { setMedications(prev => prev.filter(m => m.id !== id)); if (editingId === id) resetForm(); }, [editingId, setMedications]); const toggleTaken = useCallback((id: string) => { // 1. Calculate new state immediately const updatedMeds = medications.map(m => { if (m.id === id) { return { ...m, taken: !m.taken }; } return m; }); // 2. Determine Streak Changes (LOGIC FIX: Filter ONLY meds active TODAY) const todayMeds = updatedMeds.filter(isDueToday); // Only check if active meds are taken. If no meds due today, streak logic is neutral (or paused). const allActiveTaken = todayMeds.length > 0 && todayMeds.every(m => m.taken); const today = new Date(); today.setHours(0,0,0,0); const lastUpdate = new Date(profile.lastStreakUpdate); lastUpdate.setHours(0,0,0,0); const isToday = today.getTime() === lastUpdate.getTime(); let newStreak = profile.streak; let newLastUpdate = profile.lastStreakUpdate; if (allActiveTaken) { if (!isToday) { // First time finishing today -> Increment newStreak += 1; newLastUpdate = new Date().toISOString(); } } else { // Not all taken if (isToday) { // previously marked done today, now unchecked -> Revert newStreak = Math.max(0, newStreak - 1); // Reset date to yesterday to allow re-completion const yesterday = new Date(today); yesterday.setDate(yesterday.getDate() - 1); newLastUpdate = yesterday.toISOString(); } } // 3. Batch Updates setMedications(updatedMeds); if (newStreak !== profile.streak || newLastUpdate !== profile.lastStreakUpdate) { setProfile(prev => ({ ...prev, streak: newStreak, lastStreakUpdate: newLastUpdate })); } }, [medications, profile.streak, profile.lastStreakUpdate, setMedications, setProfile]); // LOGIC FIX: Pending count only looks at what is due today const pendingMeds = medications.filter(m => isDueToday(m) && !m.taken).length; const randomQuote = MOTIVATIONAL_QUOTES[Math.floor(Math.random() * MOTIVATIONAL_QUOTES.length)]; return (

{editingId ? : } {editingId ? 'Edit Medication' : 'Add Medication'}

{editingId && ( )}
setNewMedName(e.target.value)} placeholder="Medication Name" className="bg-black/40 border border-white/10 rounded-lg p-3 text-white text-sm focus:border-neon-blue outline-none col-span-2" /> setNewMedDosage(e.target.value)} placeholder="Dosage (e.g. 10mg)" className="bg-black/40 border border-white/10 rounded-lg p-3 text-white text-sm focus:border-neon-blue outline-none" /> setNewMedTime(e.target.value)} className="bg-black/40 border border-white/10 rounded-lg p-3 text-white text-sm focus:border-neon-blue outline-none" />
setStartDate(e.target.value)} className="w-full bg-black/40 border border-white/10 rounded-lg p-3 text-white text-sm focus:border-neon-blue outline-none" />
setEndDate(e.target.value)} className="w-full bg-black/40 border border-white/10 rounded-lg p-3 text-white text-sm focus:border-neon-blue outline-none" />
{editingId ? ( ) : ( )}
{medications.map(med => ( ))} {medications.length === 0 && (

No medications tracked.

)}
0 ? 'via-yellow-500' : 'via-gray-500'} to-transparent`}>
0 ? 'text-yellow-400 drop-shadow-[0_0_10px_rgba(234,179,8,0.5)]' : 'text-gray-700'} mb-4 transition-colors duration-500`} />

0 ? 'text-white' : 'text-gray-500'} mb-2`}>{profile.streak} Days

Current Streak

{profile.streak === 0 && (

"{randomQuote}"

)} {profile.streak > 0 && (

Keep going! You are building a healthier future.

)}
{pendingMeds > 0 ? (

Missed Doses Pending

You have {pendingMeds} medication(s) due today.

) : (

All Caught Up!

You've taken all your medications for today.

)}
); }; export default MedicationTracker;