added dark mode
This commit is contained in:
@@ -81,52 +81,52 @@ export default function NewMedicationPage() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50">
|
||||
<header className="bg-white border-b border-gray-200 sticky top-0 z-10">
|
||||
<div className="min-h-screen bg-gray-50 dark:bg-gray-950">
|
||||
<header className="bg-white dark:bg-gray-900 border-b border-gray-200 dark:border-gray-700 sticky top-0 z-10">
|
||||
<div className="flex items-center gap-3 px-4 py-3">
|
||||
<button onClick={() => router.back()} className="p-1">
|
||||
<button onClick={() => router.back()} className="p-1 text-gray-600 dark:text-gray-400">
|
||||
<ArrowLeftIcon size={24} />
|
||||
</button>
|
||||
<h1 className="text-xl font-bold text-gray-900">Add Medication</h1>
|
||||
<h1 className="text-xl font-bold text-gray-900 dark:text-gray-100">Add Medication</h1>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<form onSubmit={handleSubmit} className="p-4 space-y-6">
|
||||
{error && (
|
||||
<div className="bg-red-50 text-red-600 px-4 py-3 rounded-lg text-sm">
|
||||
<div className="bg-red-50 dark:bg-red-900/30 text-red-600 dark:text-red-400 px-4 py-3 rounded-lg text-sm">
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="bg-white rounded-xl p-4 shadow-sm space-y-4">
|
||||
<div className="bg-white dark:bg-gray-800 rounded-xl p-4 shadow-sm space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">Medication Name</label>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Medication Name</label>
|
||||
<input
|
||||
type="text"
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
placeholder="e.g., Vitamin D"
|
||||
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 outline-none"
|
||||
className="w-full px-4 py-3 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 placeholder-gray-400 dark:placeholder-gray-500 focus:ring-2 focus:ring-indigo-500 outline-none"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">Dosage</label>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Dosage</label>
|
||||
<input
|
||||
type="text"
|
||||
value={dosage}
|
||||
onChange={(e) => setDosage(e.target.value)}
|
||||
placeholder="e.g., 1000"
|
||||
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 outline-none"
|
||||
className="w-full px-4 py-3 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 placeholder-gray-400 dark:placeholder-gray-500 focus:ring-2 focus:ring-indigo-500 outline-none"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">Unit</label>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Unit</label>
|
||||
<select
|
||||
value={unit}
|
||||
onChange={(e) => setUnit(e.target.value)}
|
||||
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 outline-none"
|
||||
className="w-full px-4 py-3 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-indigo-500 outline-none"
|
||||
>
|
||||
<option value="mg">mg</option>
|
||||
<option value="mcg">mcg</option>
|
||||
@@ -140,11 +140,11 @@ export default function NewMedicationPage() {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">Frequency</label>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Frequency</label>
|
||||
<select
|
||||
value={frequency}
|
||||
onChange={(e) => setFrequency(e.target.value)}
|
||||
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 outline-none"
|
||||
className="w-full px-4 py-3 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-indigo-500 outline-none"
|
||||
>
|
||||
<option value="daily">Daily</option>
|
||||
<option value="specific_days">Specific Days of Week</option>
|
||||
@@ -156,7 +156,7 @@ export default function NewMedicationPage() {
|
||||
{/* Day-of-week picker for specific_days */}
|
||||
{frequency === 'specific_days' && (
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">Days</label>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Days</label>
|
||||
<div className="flex gap-2 flex-wrap">
|
||||
{DAY_OPTIONS.map(({ value, label }) => (
|
||||
<button
|
||||
@@ -166,7 +166,7 @@ export default function NewMedicationPage() {
|
||||
className={`px-3 py-2 rounded-lg text-sm font-medium border transition-colors ${
|
||||
daysOfWeek.includes(value)
|
||||
? 'bg-indigo-600 text-white border-indigo-600'
|
||||
: 'bg-white text-gray-700 border-gray-300'
|
||||
: 'bg-white dark:bg-gray-700 text-gray-700 dark:text-gray-300 border-gray-300 dark:border-gray-600'
|
||||
}`}
|
||||
>
|
||||
{label}
|
||||
@@ -180,22 +180,22 @@ export default function NewMedicationPage() {
|
||||
{frequency === 'every_n_days' && (
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">Every N Days</label>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Every N Days</label>
|
||||
<input
|
||||
type="number"
|
||||
min={1}
|
||||
value={intervalDays}
|
||||
onChange={(e) => setIntervalDays(parseInt(e.target.value) || 1)}
|
||||
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 outline-none"
|
||||
className="w-full px-4 py-3 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 placeholder-gray-400 dark:placeholder-gray-500 focus:ring-2 focus:ring-indigo-500 outline-none"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">Starting From</label>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Starting From</label>
|
||||
<input
|
||||
type="date"
|
||||
value={startDate}
|
||||
onChange={(e) => setStartDate(e.target.value)}
|
||||
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 outline-none"
|
||||
className="w-full px-4 py-3 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-indigo-500 outline-none"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -205,17 +205,17 @@ export default function NewMedicationPage() {
|
||||
{frequency !== 'as_needed' && (
|
||||
<div>
|
||||
<div className="flex items-center justify-between mb-1">
|
||||
<label className="block text-sm font-medium text-gray-700">Times</label>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300">Times</label>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleAddTime}
|
||||
className="text-indigo-600 text-sm font-medium"
|
||||
className="text-indigo-600 dark:text-indigo-400 text-sm font-medium"
|
||||
>
|
||||
+ Add Time
|
||||
</button>
|
||||
</div>
|
||||
{frequency === 'daily' && (
|
||||
<p className="text-xs text-gray-400 mb-2">Add multiple times for 2x, 3x, or more doses per day</p>
|
||||
<p className="text-xs text-gray-400 dark:text-gray-500 mb-2">Add multiple times for 2x, 3x, or more doses per day</p>
|
||||
)}
|
||||
<div className="space-y-2">
|
||||
{times.map((time, index) => (
|
||||
@@ -224,13 +224,13 @@ export default function NewMedicationPage() {
|
||||
type="time"
|
||||
value={time}
|
||||
onChange={(e) => handleTimeChange(index, e.target.value)}
|
||||
className="flex-1 px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 outline-none"
|
||||
className="flex-1 px-4 py-3 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-indigo-500 outline-none"
|
||||
/>
|
||||
{times.length > 1 && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleRemoveTime(index)}
|
||||
className="text-red-500 px-3"
|
||||
className="text-red-500 dark:text-red-400 px-3"
|
||||
>
|
||||
Remove
|
||||
</button>
|
||||
|
||||
@@ -214,7 +214,7 @@ export default function MedicationsPage() {
|
||||
return (
|
||||
<div className="p-4 space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<h1 className="text-2xl font-bold text-gray-900">Medications</h1>
|
||||
<h1 className="text-2xl font-bold text-gray-900 dark:text-gray-100">Medications</h1>
|
||||
<Link href="/dashboard/medications/new" className="bg-indigo-600 text-white p-2 rounded-full">
|
||||
<PlusIcon size={24} />
|
||||
</Link>
|
||||
@@ -224,7 +224,7 @@ export default function MedicationsPage() {
|
||||
<PushNotificationToggle />
|
||||
|
||||
{error && (
|
||||
<div className="bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded-lg">
|
||||
<div className="bg-red-50 dark:bg-red-900/30 border border-red-200 dark:border-red-800 text-red-700 dark:text-red-400 px-4 py-3 rounded-lg">
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
@@ -232,38 +232,38 @@ export default function MedicationsPage() {
|
||||
{/* Due Now Section */}
|
||||
{dueEntries.length > 0 && (
|
||||
<div>
|
||||
<h2 className="text-lg font-semibold text-gray-900 mb-3">Due</h2>
|
||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-3">Due</h2>
|
||||
<div className="space-y-3">
|
||||
{dueEntries.map((entry) => (
|
||||
<div
|
||||
key={`${entry.item.medication.id}-${entry.time}`}
|
||||
className={`bg-white rounded-xl p-4 shadow-sm ${borderColor(entry.status)}`}
|
||||
className={`bg-white dark:bg-gray-800 rounded-xl p-4 shadow-sm ${borderColor(entry.status)}`}
|
||||
>
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<div>
|
||||
<div className="flex items-center gap-2">
|
||||
<h3 className="font-semibold text-gray-900">{entry.item.medication.name}</h3>
|
||||
<h3 className="font-semibold text-gray-900 dark:text-gray-100">{entry.item.medication.name}</h3>
|
||||
{entry.item.is_previous_day && (
|
||||
<span className="text-xs bg-purple-100 text-purple-700 px-2 py-0.5 rounded">Yesterday</span>
|
||||
<span className="text-xs bg-purple-100 dark:bg-purple-900/30 text-purple-700 dark:text-purple-400 px-2 py-0.5 rounded">Yesterday</span>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-sm text-gray-500">{entry.item.medication.dosage} {entry.item.medication.unit}</p>
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400">{entry.item.medication.dosage} {entry.item.medication.unit}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center justify-between bg-gray-50 rounded-lg p-3">
|
||||
<div className="flex items-center justify-between bg-gray-50 dark:bg-gray-700 rounded-lg p-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<ClockIcon size={16} className="text-gray-500" />
|
||||
<span className="font-medium">{entry.time}</span>
|
||||
<ClockIcon size={16} className="text-gray-500 dark:text-gray-400" />
|
||||
<span className="font-medium text-gray-900 dark:text-gray-100">{entry.time}</span>
|
||||
{entry.status === 'overdue' && (
|
||||
<span className="text-xs text-red-600 font-medium">Overdue</span>
|
||||
<span className="text-xs text-red-600 dark:text-red-400 font-medium">Overdue</span>
|
||||
)}
|
||||
</div>
|
||||
{entry.status === 'taken' ? (
|
||||
<span className="text-green-600 font-medium flex items-center gap-1">
|
||||
<span className="text-green-600 dark:text-green-400 font-medium flex items-center gap-1">
|
||||
<CheckIcon size={16} /> Taken
|
||||
</span>
|
||||
) : entry.status === 'skipped' ? (
|
||||
<span className="text-gray-400 font-medium">Skipped</span>
|
||||
<span className="text-gray-400 dark:text-gray-500 font-medium">Skipped</span>
|
||||
) : (
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
@@ -274,7 +274,7 @@ export default function MedicationsPage() {
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handleSkip(entry.item.medication.id, entry.time)}
|
||||
className="text-gray-500 px-2 py-1"
|
||||
className="text-gray-500 dark:text-gray-400 px-2 py-1"
|
||||
>
|
||||
Skip
|
||||
</button>
|
||||
@@ -290,18 +290,18 @@ export default function MedicationsPage() {
|
||||
{/* PRN Section */}
|
||||
{prnEntries.length > 0 && (
|
||||
<div>
|
||||
<h2 className="text-lg font-semibold text-gray-900 mb-3">As Needed</h2>
|
||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-3">As Needed</h2>
|
||||
<div className="space-y-3">
|
||||
{prnEntries.map((item) => (
|
||||
<div key={item.medication.id} className="bg-white rounded-xl p-4 shadow-sm">
|
||||
<div key={item.medication.id} className="bg-white dark:bg-gray-800 rounded-xl p-4 shadow-sm">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<div>
|
||||
<h3 className="font-semibold text-gray-900">{item.medication.name}</h3>
|
||||
<p className="text-sm text-gray-500">{item.medication.dosage} {item.medication.unit}</p>
|
||||
<h3 className="font-semibold text-gray-900 dark:text-gray-100">{item.medication.name}</h3>
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400">{item.medication.dosage} {item.medication.unit}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center justify-between bg-gray-50 rounded-lg p-3">
|
||||
<span className="text-gray-500 text-sm">As needed</span>
|
||||
<div className="flex items-center justify-between bg-gray-50 dark:bg-gray-700 rounded-lg p-3">
|
||||
<span className="text-gray-500 dark:text-gray-400 text-sm">As needed</span>
|
||||
<button
|
||||
onClick={() => handleTake(item.medication.id)}
|
||||
className="bg-green-600 text-white px-3 py-1 rounded-lg text-sm font-medium"
|
||||
@@ -318,24 +318,24 @@ export default function MedicationsPage() {
|
||||
{/* Upcoming Section */}
|
||||
{upcomingEntries.length > 0 && (
|
||||
<div>
|
||||
<h2 className="text-lg font-semibold text-gray-500 mb-3">Upcoming</h2>
|
||||
<h2 className="text-lg font-semibold text-gray-500 dark:text-gray-400 mb-3">Upcoming</h2>
|
||||
<div className="space-y-3">
|
||||
{upcomingEntries.map((entry) => (
|
||||
<div
|
||||
key={`${entry.item.medication.id}-${entry.time}`}
|
||||
className="bg-gray-50 rounded-xl p-4 shadow-sm opacity-75"
|
||||
className="bg-gray-50 dark:bg-gray-800 rounded-xl p-4 shadow-sm opacity-75"
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<div className="flex items-center gap-2">
|
||||
<h3 className="font-medium text-gray-700">{entry.item.medication.name}</h3>
|
||||
<h3 className="font-medium text-gray-700 dark:text-gray-300">{entry.item.medication.name}</h3>
|
||||
{entry.item.is_next_day && (
|
||||
<span className="text-xs bg-blue-100 text-blue-700 px-2 py-0.5 rounded">Tomorrow</span>
|
||||
<span className="text-xs bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-400 px-2 py-0.5 rounded">Tomorrow</span>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-sm text-gray-400">{entry.item.medication.dosage} {entry.item.medication.unit}</p>
|
||||
<p className="text-sm text-gray-400 dark:text-gray-500">{entry.item.medication.dosage} {entry.item.medication.unit}</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 text-gray-400">
|
||||
<div className="flex items-center gap-2 text-gray-400 dark:text-gray-500">
|
||||
<ClockIcon size={16} />
|
||||
<span className="font-medium">{entry.time}</span>
|
||||
</div>
|
||||
@@ -348,15 +348,15 @@ export default function MedicationsPage() {
|
||||
|
||||
{/* All Medications */}
|
||||
<div>
|
||||
<h2 className="text-lg font-semibold text-gray-900 mb-3">All Medications</h2>
|
||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-3">All Medications</h2>
|
||||
|
||||
{medications.length === 0 ? (
|
||||
<div className="bg-white rounded-xl p-8 shadow-sm text-center">
|
||||
<div className="w-16 h-16 bg-gray-100 rounded-full flex items-center justify-center mx-auto mb-4">
|
||||
<PillIcon className="text-gray-400" size={32} />
|
||||
<div className="bg-white dark:bg-gray-800 rounded-xl p-8 shadow-sm text-center">
|
||||
<div className="w-16 h-16 bg-gray-100 dark:bg-gray-700 rounded-full flex items-center justify-center mx-auto mb-4">
|
||||
<PillIcon className="text-gray-400 dark:text-gray-500" size={32} />
|
||||
</div>
|
||||
<h3 className="font-semibold text-gray-900 mb-1">No medications yet</h3>
|
||||
<p className="text-gray-500 text-sm mb-4">Add your medications to track them</p>
|
||||
<h3 className="font-semibold text-gray-900 dark:text-gray-100 mb-1">No medications yet</h3>
|
||||
<p className="text-gray-500 dark:text-gray-400 text-sm mb-4">Add your medications to track them</p>
|
||||
<Link href="/dashboard/medications/new" className="inline-block bg-indigo-600 text-white px-4 py-2 rounded-lg font-medium">
|
||||
Add Medication
|
||||
</Link>
|
||||
@@ -366,41 +366,41 @@ export default function MedicationsPage() {
|
||||
{medications.map((med) => {
|
||||
const { percent: adherencePercent, isPrn } = getAdherenceForMed(med.id);
|
||||
return (
|
||||
<div key={med.id} className="bg-white rounded-xl p-4 shadow-sm">
|
||||
<div key={med.id} className="bg-white dark:bg-gray-800 rounded-xl p-4 shadow-sm">
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center gap-2">
|
||||
<h3 className="font-semibold text-gray-900">{med.name}</h3>
|
||||
<h3 className="font-semibold text-gray-900 dark:text-gray-100">{med.name}</h3>
|
||||
{!med.active && (
|
||||
<span className="text-xs bg-gray-100 text-gray-500 px-2 py-0.5 rounded">Inactive</span>
|
||||
<span className="text-xs bg-gray-100 dark:bg-gray-700 text-gray-500 dark:text-gray-400 px-2 py-0.5 rounded">Inactive</span>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-gray-500 text-sm">{med.dosage} {med.unit} · {formatSchedule(med)}</p>
|
||||
<p className="text-gray-500 dark:text-gray-400 text-sm">{med.dosage} {med.unit} · {formatSchedule(med)}</p>
|
||||
{med.times.length > 0 && (
|
||||
<p className="text-gray-400 text-sm mt-1">Times: {med.times.join(', ')}</p>
|
||||
<p className="text-gray-400 dark:text-gray-500 text-sm mt-1">Times: {med.times.join(', ')}</p>
|
||||
)}
|
||||
</div>
|
||||
<button
|
||||
onClick={() => handleDelete(med.id)}
|
||||
className="text-red-500 p-2"
|
||||
className="text-red-500 dark:text-red-400 p-2"
|
||||
>
|
||||
<TrashIcon size={18} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Adherence */}
|
||||
<div className="mt-3 pt-3 border-t border-gray-100">
|
||||
<div className="mt-3 pt-3 border-t border-gray-100 dark:border-gray-700">
|
||||
{isPrn || adherencePercent === null ? (
|
||||
<span className="text-sm text-gray-400">PRN — no adherence tracking</span>
|
||||
<span className="text-sm text-gray-400 dark:text-gray-500">PRN — no adherence tracking</span>
|
||||
) : (
|
||||
<>
|
||||
<div className="flex items-center justify-between mb-1">
|
||||
<span className="text-sm text-gray-500">30-day adherence</span>
|
||||
<span className={`font-semibold ${adherencePercent >= 80 ? 'text-green-600' : adherencePercent >= 50 ? 'text-yellow-600' : 'text-red-600'}`}>
|
||||
<span className="text-sm text-gray-500 dark:text-gray-400">30-day adherence</span>
|
||||
<span className={`font-semibold ${adherencePercent >= 80 ? 'text-green-600 dark:text-green-400' : adherencePercent >= 50 ? 'text-yellow-600 dark:text-yellow-400' : 'text-red-600 dark:text-red-400'}`}>
|
||||
{adherencePercent}%
|
||||
</span>
|
||||
</div>
|
||||
<div className="h-2 bg-gray-100 rounded-full overflow-hidden">
|
||||
<div className="h-2 bg-gray-100 dark:bg-gray-700 rounded-full overflow-hidden">
|
||||
<div
|
||||
className={`h-full ${adherencePercent >= 80 ? 'bg-green-500' : adherencePercent >= 50 ? 'bg-yellow-500' : 'bg-red-500'}`}
|
||||
style={{ width: `${adherencePercent}%` }}
|
||||
|
||||
Reference in New Issue
Block a user