Update new unified dose management, style/other improvements
This commit is contained in:
154
src/components/day-schedule.tsx
Normal file
154
src/components/day-schedule.tsx
Normal 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;
|
||||
Reference in New Issue
Block a user