Add intake auto sorting, chart intake markers, upped max daily intakes to 6, various style changes

This commit is contained in:
2026-02-09 17:08:53 +00:00
parent c41db99cba
commit 7a2a8b0b47
13 changed files with 558 additions and 293 deletions

View File

@@ -56,6 +56,7 @@ const SimulationChart = ({
chartView,
showDayTimeOnXAxis,
showDayReferenceLines,
showIntakeTimeLines,
showTherapeuticRange,
therapeuticRange,
simulationDays,
@@ -347,6 +348,44 @@ const SimulationChart = ({
}
}, [days, daysWithDeviations, t]);
// Extract all intake times from all days for intake time reference lines
const intakeTimes = React.useMemo(() => {
if (!days || !Array.isArray(days)) return [];
const times: Array<{ hour: number; dayIndex: number; doseIndex: number }> = [];
const simDaysCount = parseInt(simulationDays, 10) || 3;
// Iterate through each simulated day
for (let dayNum = 1; dayNum <= simDaysCount; dayNum++) {
// Determine which schedule to use for this day
let daySchedule;
if (dayNum === 1 || days.length === 1) {
// First day or only one schedule exists: use template/first schedule
daySchedule = days.find(d => d.isTemplate) || days[0];
} else {
// For subsequent days, use the corresponding schedule if it exists, otherwise use template
const scheduleIndex = dayNum - 1;
daySchedule = days[scheduleIndex] || days.find(d => d.isTemplate) || days[0];
}
if (daySchedule && daySchedule.doses) {
daySchedule.doses.forEach((dose: any, doseIdx: number) => {
if (dose.time) {
const [hours, minutes] = dose.time.split(':').map(Number);
const hoursSinceStart = (dayNum - 1) * 24 + hours + minutes / 60;
times.push({
hour: hoursSinceStart,
dayIndex: dayNum,
doseIndex: doseIdx + 1 // 1-based index
});
}
});
}
}
return times;
}, [days, simulationDays]);
// Merge all profiles into a single dataset for proper tooltip synchronization
const mergedData = React.useMemo(() => {
const dataMap = new Map();
@@ -617,6 +656,43 @@ const SimulationChart = ({
/>
)}
{showIntakeTimeLines && intakeTimes.map((intake, idx) => {
// Determine label position offset if day lines are also shown
const labelOffsetY = showDayReferenceLines !== false ? 20 : 5; // More spacing when day lines are shown
return (
<ReferenceLine
key={`intake-${idx}`}
x={intake.hour}
label={(props: any) => {
const { viewBox } = props;
// Position at top-right of the reference line with proper offsets
// x: subtract 5px from right edge to create gap between line and text
// y: add offset + ~12px (font size) since y is the text baseline, not top
const x = viewBox.x + viewBox.width - 5;
const y = viewBox.y + labelOffsetY + 12; // 12px ≈ 0.75rem font size
return (
<text
x={x}
y={y}
textAnchor="end"
fontSize="0.75rem"
fontStyle="italic"
fill="#a0a0a0"
>
{intake.doseIndex}
</text>
);
}}
stroke="#c0c0c0"
strokeDasharray="3 3"
xAxisId="hours"
yAxisId="concentration"
/>
);
})}
{[...Array(parseInt(simulationDays, 10) || 3).keys()].map(day => (
day > 0 && (
<ReferenceLine