Update new unified dose management, style/other improvements

This commit is contained in:
2025-12-02 21:39:17 +00:00
parent 3fa5bf8360
commit bbdfc5f894
15 changed files with 830 additions and 495 deletions

View File

@@ -0,0 +1,154 @@
/**
* Day Schedule Component
*
* Manages day-based medication schedules with doses.
* Allows adding/removing days, cloning days, and managing doses within each day.
*
* @author Andreas Weyer
* @license MIT
*/
import React from 'react';
import { Button } from './ui/button';
import { Card, CardContent, CardHeader, CardTitle } from './ui/card';
import { Badge } from './ui/badge';
import { FormTimeInput } from './ui/form-time-input';
import { FormNumericInput } from './ui/form-numeric-input';
import { Plus, Copy, Trash2 } from 'lucide-react';
import type { DayGroup } from '../constants/defaults';
interface DayScheduleProps {
days: DayGroup[];
doseIncrement: string;
onAddDay: (cloneFromDayId?: string) => void;
onRemoveDay: (dayId: string) => void;
onAddDose: (dayId: string) => void;
onRemoveDose: (dayId: string, doseId: string) => void;
onUpdateDose: (dayId: string, doseId: string, field: 'time' | 'ldx' | 'damph', value: string) => void;
t: any;
}
const DaySchedule: React.FC<DayScheduleProps> = ({
days,
doseIncrement,
onAddDay,
onRemoveDay,
onAddDose,
onRemoveDose,
onUpdateDose,
t
}) => {
const canAddDay = days.length < 3;
return (
<div className="space-y-4">
{days.map((day, dayIndex) => (
<Card key={day.id}>
<CardHeader className="pb-3">
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<CardTitle className="text-lg">
{day.isTemplate ? t.regularPlan : t.dayNumber.replace('{{number}}', String(dayIndex + 1))}
</CardTitle>
{day.isTemplate && (
<Badge variant="secondary" className="text-xs">
{t.day} 1
</Badge>
)}
</div>
<div className="flex gap-2">
{canAddDay && (
<Button
onClick={() => onAddDay(day.id)}
size="sm"
variant="outline"
title={t.cloneDay}
>
<Copy className="h-4 w-4" />
</Button>
)}
{!day.isTemplate && (
<Button
onClick={() => onRemoveDay(day.id)}
size="sm"
variant="outline"
className="border-destructive text-destructive hover:bg-destructive hover:text-destructive-foreground"
title={t.removeDay}
>
<Trash2 className="h-4 w-4" />
</Button>
)}
</div>
</div>
</CardHeader>
<CardContent className="space-y-3">
{/* Dose table header */}
<div className="grid grid-cols-[120px_1fr_auto] gap-3 text-sm font-medium text-muted-foreground">
<div>{t.time}</div>
<div>{t.ldx} (mg)</div>
<div></div>
</div>
{/* Dose rows */}
{day.doses.map((dose) => (
<div key={dose.id} className="grid grid-cols-[120px_1fr_auto] gap-3 items-center">
<FormTimeInput
value={dose.time}
onChange={(value) => onUpdateDose(day.id, dose.id, 'time', value)}
required={true}
errorMessage={t.errorTimeRequired}
/>
<FormNumericInput
value={dose.ldx}
onChange={(value) => onUpdateDose(day.id, dose.id, 'ldx', value)}
increment={doseIncrement}
min={0}
unit="mg"
required={true}
errorMessage={t.errorNumberRequired}
/>
<Button
onClick={() => onRemoveDose(day.id, dose.id)}
size="sm"
variant="ghost"
disabled={day.isTemplate && day.doses.length === 1}
className="h-9 w-9 p-0"
title={t.removeDose}
>
<Trash2 className="h-4 w-4" />
</Button>
</div>
))}
{/* Add dose button */}
{day.doses.length < 5 && (
<Button
onClick={() => onAddDose(day.id)}
size="sm"
variant="outline"
className="w-full mt-2"
>
<Plus className="h-4 w-4 mr-2" />
{t.addDose}
</Button>
)}
</CardContent>
</Card>
))}
{/* Add day button */}
{canAddDay && (
<Button
onClick={() => onAddDay()}
variant="outline"
className="w-full"
>
<Plus className="h-4 w-4 mr-2" />
{t.addDay}
</Button>
)}
</div>
);
};
export default DaySchedule;