Update day-schedule add folding and summary badges with trend indicator

This commit is contained in:
2025-12-04 01:45:11 +00:00
parent abae3d54e6
commit d64b9eabfa
3 changed files with 110 additions and 6 deletions

View File

@@ -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 && (