Update day-schedule add folding and summary badges with trend indicator
This commit is contained in:
@@ -15,7 +15,7 @@ import { Badge } from './ui/badge';
|
||||
import { FormTimeInput } from './ui/form-time-input';
|
||||
import { FormNumericInput } from './ui/form-numeric-input';
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from './ui/tooltip';
|
||||
import { Plus, Copy, Trash2, ArrowDownAZ } from 'lucide-react';
|
||||
import { Plus, Copy, Trash2, ArrowDownAZ, ChevronDown, ChevronUp, TrendingUp, TrendingDown } from 'lucide-react';
|
||||
import type { DayGroup } from '../constants/defaults';
|
||||
|
||||
interface DayScheduleProps {
|
||||
@@ -43,6 +43,21 @@ const DaySchedule: React.FC<DayScheduleProps> = ({
|
||||
}) => {
|
||||
const canAddDay = days.length < 3;
|
||||
|
||||
// Track collapsed state for each day (by day ID)
|
||||
const [collapsedDays, setCollapsedDays] = React.useState<Set<string>>(new Set());
|
||||
|
||||
const toggleDayCollapse = (dayId: string) => {
|
||||
setCollapsedDays(prev => {
|
||||
const newSet = new Set(prev);
|
||||
if (newSet.has(dayId)) {
|
||||
newSet.delete(dayId);
|
||||
} else {
|
||||
newSet.add(dayId);
|
||||
}
|
||||
return newSet;
|
||||
});
|
||||
};
|
||||
|
||||
// Check if doses are sorted chronologically
|
||||
const isDaySorted = (day: DayGroup): boolean => {
|
||||
for (let i = 1; i < day.doses.length; i++) {
|
||||
@@ -57,17 +72,94 @@ const DaySchedule: React.FC<DayScheduleProps> = ({
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
{days.map((day, dayIndex) => (
|
||||
{days.map((day, dayIndex) => {
|
||||
// Get template day for comparison
|
||||
const templateDay = days.find(d => d.isTemplate);
|
||||
|
||||
// Calculate differences for deviation days
|
||||
let doseCountDiff = 0;
|
||||
let totalMgDiff = 0;
|
||||
|
||||
if (!day.isTemplate && templateDay) {
|
||||
doseCountDiff = day.doses.length - templateDay.doses.length;
|
||||
const dayTotal = day.doses.reduce((sum, dose) => sum + (parseFloat(dose.ldx) || 0), 0);
|
||||
const templateTotal = templateDay.doses.reduce((sum, dose) => sum + (parseFloat(dose.ldx) || 0), 0);
|
||||
totalMgDiff = dayTotal - templateTotal;
|
||||
}
|
||||
|
||||
return (
|
||||
<Card key={day.id}>
|
||||
<CardHeader className="pb-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
className="h-6 w-6 p-0"
|
||||
onClick={() => toggleDayCollapse(day.id)}
|
||||
title={collapsedDays.has(day.id) ? t('expandDay') : t('collapseDay')}
|
||||
>
|
||||
{collapsedDays.has(day.id) ? (
|
||||
<ChevronDown className="h-4 w-4" />
|
||||
) : (
|
||||
<ChevronUp className="h-4 w-4" />
|
||||
)}
|
||||
</Button>
|
||||
<CardTitle className="text-lg">
|
||||
{day.isTemplate ? t('regularPlan') : t('deviatingPlan')}
|
||||
</CardTitle>
|
||||
<Badge variant="secondary" className="text-xs">
|
||||
{t('day')} {dayIndex + 1}
|
||||
</Badge>
|
||||
{!day.isTemplate && doseCountDiff !== 0 ? (
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Badge
|
||||
variant="outline"
|
||||
className={`text-xs ${doseCountDiff > 0 ? 'bg-blue-50' : 'bg-orange-50'}`}
|
||||
>
|
||||
{doseCountDiff > 0 ? <TrendingUp className="h-3 w-3 inline mr-1" /> : <TrendingDown className="h-3 w-3 inline mr-1" />}
|
||||
{day.doses.length} {day.doses.length === 1 ? t('dose') : t('doses')}
|
||||
</Badge>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p className="text-xs">
|
||||
{doseCountDiff > 0 ? '+' : ''}{doseCountDiff} {Math.abs(doseCountDiff) === 1 ? t('dose') : t('doses')} {t('comparedToRegularPlan')}
|
||||
</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
) : (
|
||||
<Badge variant="outline" className="text-xs">
|
||||
{day.doses.length} {day.doses.length === 1 ? t('dose') : t('doses')}
|
||||
</Badge>
|
||||
)}
|
||||
{!day.isTemplate && Math.abs(totalMgDiff) > 0.1 ? (
|
||||
<TooltipProvider>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Badge
|
||||
variant="outline"
|
||||
className={`text-xs ${totalMgDiff > 0 ? 'bg-blue-50' : 'bg-orange-50'}`}
|
||||
>
|
||||
{totalMgDiff > 0 ? <TrendingUp className="h-3 w-3 inline mr-1" /> : <TrendingDown className="h-3 w-3 inline mr-1" />}
|
||||
{day.doses.reduce((sum, dose) => sum + (parseFloat(dose.ldx) || 0), 0).toFixed(1)} mg
|
||||
</Badge>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>
|
||||
<p className="text-xs">
|
||||
{totalMgDiff > 0 ? '+' : ''}{totalMgDiff.toFixed(1)} mg {t('comparedToRegularPlan')}
|
||||
</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
) : (
|
||||
<Badge variant="outline" className="text-xs">
|
||||
{day.doses.reduce((sum, dose) => sum + (parseFloat(dose.ldx) || 0), 0).toFixed(1)} mg
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
{canAddDay && (
|
||||
@@ -94,6 +186,7 @@ const DaySchedule: React.FC<DayScheduleProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
{!collapsedDays.has(day.id) && (
|
||||
<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">
|
||||
@@ -186,8 +279,9 @@ const DaySchedule: React.FC<DayScheduleProps> = ({
|
||||
</Button>
|
||||
)}
|
||||
</CardContent>
|
||||
)}
|
||||
</Card>
|
||||
))}
|
||||
)})}
|
||||
|
||||
{/* Add day button */}
|
||||
{canAddDay && (
|
||||
|
||||
@@ -98,13 +98,18 @@ export const de = {
|
||||
// Day-based schedule
|
||||
regularPlan: "Regulärer Plan",
|
||||
deviatingPlan: "Abweichung vom Plan",
|
||||
regularPlanOverlay: "nach Plan",
|
||||
regularPlanOverlay: "Regulär",
|
||||
dayNumber: "Tag {{number}}",
|
||||
cloneDay: "Tag klonen",
|
||||
addDay: "Tag hinzufügen",
|
||||
addDose: "Dosis hinzufügen",
|
||||
removeDose: "Dosis entfernen",
|
||||
removeDay: "Tag entfernen",
|
||||
collapseDay: "Tag einklappen",
|
||||
expandDay: "Tag ausklappen",
|
||||
dose: "Dosis",
|
||||
doses: "Dosen",
|
||||
comparedToRegularPlan: "verglichen mit regulärem Plan",
|
||||
time: "Zeit",
|
||||
ldx: "LDX",
|
||||
damph: "d-amph",
|
||||
|
||||
@@ -107,13 +107,18 @@ export const en = {
|
||||
// Day-based schedule
|
||||
regularPlan: "Regular Plan",
|
||||
deviatingPlan: "Deviation from Plan",
|
||||
regularPlanOverlay: "as planned",
|
||||
regularPlanOverlay: "Regular",
|
||||
dayNumber: "Day {{number}}",
|
||||
cloneDay: "Clone day",
|
||||
addDay: "Add day",
|
||||
addDose: "Add dose",
|
||||
removeDose: "Remove dose",
|
||||
removeDay: "Remove day",
|
||||
collapseDay: "Collapse day",
|
||||
expandDay: "Expand day",
|
||||
dose: "dose",
|
||||
doses: "doses",
|
||||
comparedToRegularPlan: "compared to regular plan",
|
||||
time: "Time",
|
||||
ldx: "LDX",
|
||||
damph: "d-amph",
|
||||
|
||||
Reference in New Issue
Block a user