From 02b1209c2d69dd7e8c3be50c5a58306d0ef8349b Mon Sep 17 00:00:00 2001 From: Andreas Weyer Date: Mon, 2 Feb 2026 13:17:35 +0000 Subject: [PATCH] Update settings add min<=max validation to ranges, minor text changes --- src/components/settings.tsx | 35 +++++++++++++++++++++++++++++++++-- src/constants/defaults.ts | 4 ++-- src/locales/de.ts | 6 ++++-- src/locales/en.ts | 4 +++- 4 files changed, 42 insertions(+), 7 deletions(-) diff --git a/src/components/settings.tsx b/src/components/settings.tsx index bd9fbef..90086dc 100644 --- a/src/components/settings.tsx +++ b/src/components/settings.tsx @@ -134,6 +134,10 @@ const Settings = ({ // Track which tooltip is currently open (for mobile touch interaction) const [openTooltipId, setOpenTooltipId] = React.useState(null); + // Validation state for range inputs + const [therapeuticRangeError, setTherapeuticRangeError] = React.useState(''); + const [yAxisRangeError, setYAxisRangeError] = React.useState(''); + // Track window width for responsive tooltip positioning const [isNarrowScreen, setIsNarrowScreen] = React.useState( typeof window !== 'undefined' ? window.innerWidth < 640 : false @@ -226,6 +230,27 @@ const Settings = ({ // Create defaults object for translation interpolation const defaultsForT = getDefaultsForTranslation(pkParams, therapeuticRange, uiSettings); + // Validate range inputs + React.useEffect(() => { + // Therapeutic range validation (blocking error) + const minTherapeutic = parseFloat(therapeuticRange.min); + const maxTherapeutic = parseFloat(therapeuticRange.max); + if (!isNaN(minTherapeutic) && !isNaN(maxTherapeutic) && minTherapeutic >= maxTherapeutic) { + setTherapeuticRangeError(t('errorTherapeuticRangeInvalid')); + } else { + setTherapeuticRangeError(''); + } + + // Y-axis range validation (non-blocking warning) + const minYAxis = parseFloat(yAxisMin); + const maxYAxis = parseFloat(yAxisMax); + if (!isNaN(minYAxis) && !isNaN(maxYAxis) && minYAxis >= maxYAxis) { + setYAxisRangeError(t('errorYAxisRangeInvalid')); + } else { + setYAxisRangeError(''); + } + }, [therapeuticRange.min, therapeuticRange.max, yAxisMin, yAxisMax, t]); + // Helper to update nested advanced settings const updateAdvanced = (category: string, key: string, value: any) => { onUpdatePkParams('advanced', { @@ -380,7 +405,8 @@ const Settings = ({ min={0} placeholder={t('min')} required={true} - errorMessage={t('errorTherapeuticRangeMinRequired') || 'Minimum therapeutic range is required'} + error={!!therapeuticRangeError || !therapeuticRange.min} + errorMessage={therapeuticRangeError || t('errorTherapeuticRangeMinRequired') || 'Minimum therapeutic range is required'} /> - @@ -461,6 +488,8 @@ const Settings = ({ placeholder={t('auto')} allowEmpty={true} clearButton={true} + warning={!!yAxisRangeError} + warningMessage={yAxisRangeError} /> - diff --git a/src/constants/defaults.ts b/src/constants/defaults.ts index 7a075b2..fede593 100644 --- a/src/constants/defaults.ts +++ b/src/constants/defaults.ts @@ -159,7 +159,7 @@ export const getDefaultState = (): AppState => ({ } ], steadyStateConfig: { daysOnMedication: '7' }, // kept for backwards compatibility, now sourced from pkParams.advanced - therapeuticRange: { min: '', max: '' }, // Empty by default - users should personalize based on their response + therapeuticRange: { min: '10', max: '120' }, // min for adults and max for children for maximum range (users should personalize based on their response) doseIncrement: '2.5', uiSettings: { showDayTimeOnXAxis: '24h', @@ -168,7 +168,7 @@ export const getDefaultState = (): AppState => ({ yAxisMin: '', yAxisMax: '', simulationDays: '5', - displayedDays: '2', + displayedDays: '1', showTherapeuticRange: false, steadyStateDaysEnabled: true, stickyChart: false, diff --git a/src/locales/de.ts b/src/locales/de.ts index 6fcb1d9..572ff77 100644 --- a/src/locales/de.ts +++ b/src/locales/de.ts @@ -97,7 +97,7 @@ export const de = { showDayReferenceLines: "Tagestrenner anzeigen", showDayReferenceLinesTooltip: "Vertikale Linien und Statusanzeigen zwischen Tagen anzeigen (Standard: aktiviert).", - showTherapeuticRangeLines: "Therapeutischen Bereich anzeigen", + showTherapeuticRangeLines: "Therapeutischen Bereich anzeigen ", showTherapeuticRangeLinesTooltip: "Horizontale Referenzlinien für therapeutisches Min/Max anzeigen (Standard: aktiviert).", simulationDuration: "Simulationsdauer", simulationDurationTooltip: "Anzahl der zu simulierenden Tage. Längere Zeiträume zeigen Steady-State. Standard: {{simulationDays}} Tage.", @@ -108,7 +108,7 @@ export const de = { yAxisRangeAutoButton: "A", yAxisRangeAutoButtonTitle: "Bereich automatisch anhand des Datenbereichs bestimmen", auto: "Auto", - therapeuticRange: "Therapeutischer Bereich", + therapeuticRange: "Therapeutischer Bereich (d-Amphetamin)", therapeuticRangeTooltip: "Personalisierte Konzentrationsziele basierend auf DEINER individuellen Reaktion. Setze diese nachdem du beobachtet hast, welche Werte Symptomkontrolle vs. Nebenwirkungen bieten. Referenzbereiche (stark variabel): Erwachsene ~10-80 ng/mL, Kinder ~20-120 ng/mL (aufgrund geringeren Körpergewichts/Vd). Leer lassen wenn unsicher. Konsultiere deinen Arzt.", dAmphetamineParameters: "d-Amphetamin Parameter", halfLife: "Eliminations-Halbwertszeit", @@ -269,6 +269,8 @@ export const de = { errorConversionHalfLifeRequired: "⛔ Umwandlungs-Halbwertszeit ist erforderlich.", errorTherapeuticRangeMinRequired: "⛔ Minimaler therapeutischer Bereich ist erforderlich.", errorTherapeuticRangeMaxRequired: "⛔ Maximaler therapeutischer Bereich ist erforderlich.", + errorTherapeuticRangeInvalid: "⛔ Maximum muss größer als Minimum sein.", + errorYAxisRangeInvalid: "⚠️ Maximum muss größer als Minimum sein.", errorEliminationHalfLifeRequired: "⛔ Eliminations-Halbwertszeit ist erforderlich.", // Field validation - Warnings diff --git a/src/locales/en.ts b/src/locales/en.ts index d66b241..e177d6d 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -106,7 +106,7 @@ export const en = { yAxisRangeAutoButton: "A", yAxisRangeAutoButtonTitle: "Determine range automatically based on data range", auto: "Auto", - therapeuticRange: "Therapeutic Range", + therapeuticRange: "Therapeutic Range (d-Amphetamine)", therapeuticRangeTooltip: "Personalized concentration targets based on YOUR individual response. Set these after observing which levels provide symptom control vs. side effects. Reference ranges (highly variable): Adults ~10-80 ng/mL, Children ~20-120 ng/mL (due to lower body weight/Vd). Leave empty if unsure. Consult your physician.", dAmphetamineParameters: "d-Amphetamine Parameters", halfLife: "Elimination Half-life", @@ -268,6 +268,8 @@ export const en = { errorAbsorptionRateRequired: "⛔ Absorption rate is required.", errorTherapeuticRangeMinRequired: "⛔ Minimum therapeutic range is required.", errorTherapeuticRangeMaxRequired: "⛔ Maximum therapeutic range is required.", + errorTherapeuticRangeInvalid: "⛔ Maximum must be greater than minimum.", + errorYAxisRangeInvalid: "⚠️ Maximum must be greater than minimum.", errorEliminationHalfLifeRequired: "⛔ Elimination half-life is required.",