Update settings add min<=max validation to ranges, minor text changes
This commit is contained in:
@@ -134,6 +134,10 @@ const Settings = ({
|
|||||||
// Track which tooltip is currently open (for mobile touch interaction)
|
// Track which tooltip is currently open (for mobile touch interaction)
|
||||||
const [openTooltipId, setOpenTooltipId] = React.useState<string | null>(null);
|
const [openTooltipId, setOpenTooltipId] = React.useState<string | null>(null);
|
||||||
|
|
||||||
|
// Validation state for range inputs
|
||||||
|
const [therapeuticRangeError, setTherapeuticRangeError] = React.useState<string>('');
|
||||||
|
const [yAxisRangeError, setYAxisRangeError] = React.useState<string>('');
|
||||||
|
|
||||||
// Track window width for responsive tooltip positioning
|
// Track window width for responsive tooltip positioning
|
||||||
const [isNarrowScreen, setIsNarrowScreen] = React.useState(
|
const [isNarrowScreen, setIsNarrowScreen] = React.useState(
|
||||||
typeof window !== 'undefined' ? window.innerWidth < 640 : false
|
typeof window !== 'undefined' ? window.innerWidth < 640 : false
|
||||||
@@ -226,6 +230,27 @@ const Settings = ({
|
|||||||
// Create defaults object for translation interpolation
|
// Create defaults object for translation interpolation
|
||||||
const defaultsForT = getDefaultsForTranslation(pkParams, therapeuticRange, uiSettings);
|
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
|
// Helper to update nested advanced settings
|
||||||
const updateAdvanced = (category: string, key: string, value: any) => {
|
const updateAdvanced = (category: string, key: string, value: any) => {
|
||||||
onUpdatePkParams('advanced', {
|
onUpdatePkParams('advanced', {
|
||||||
@@ -380,7 +405,8 @@ const Settings = ({
|
|||||||
min={0}
|
min={0}
|
||||||
placeholder={t('min')}
|
placeholder={t('min')}
|
||||||
required={true}
|
required={true}
|
||||||
errorMessage={t('errorTherapeuticRangeMinRequired') || 'Minimum therapeutic range is required'}
|
error={!!therapeuticRangeError || !therapeuticRange.min}
|
||||||
|
errorMessage={therapeuticRangeError || t('errorTherapeuticRangeMinRequired') || 'Minimum therapeutic range is required'}
|
||||||
/>
|
/>
|
||||||
<span className="text-muted-foreground">-</span>
|
<span className="text-muted-foreground">-</span>
|
||||||
<FormNumericInput
|
<FormNumericInput
|
||||||
@@ -391,7 +417,8 @@ const Settings = ({
|
|||||||
placeholder={t('max')}
|
placeholder={t('max')}
|
||||||
unit="ng/ml"
|
unit="ng/ml"
|
||||||
required={true}
|
required={true}
|
||||||
errorMessage={t('errorTherapeuticRangeMaxRequired') || 'Maximum therapeutic range is required'}
|
error={!!therapeuticRangeError || !therapeuticRange.max}
|
||||||
|
errorMessage={therapeuticRangeError || t('errorTherapeuticRangeMaxRequired') || 'Maximum therapeutic range is required'}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -461,6 +488,8 @@ const Settings = ({
|
|||||||
placeholder={t('auto')}
|
placeholder={t('auto')}
|
||||||
allowEmpty={true}
|
allowEmpty={true}
|
||||||
clearButton={true}
|
clearButton={true}
|
||||||
|
warning={!!yAxisRangeError}
|
||||||
|
warningMessage={yAxisRangeError}
|
||||||
/>
|
/>
|
||||||
<span className="text-muted-foreground">-</span>
|
<span className="text-muted-foreground">-</span>
|
||||||
<FormNumericInput
|
<FormNumericInput
|
||||||
@@ -472,6 +501,8 @@ const Settings = ({
|
|||||||
unit="ng/ml"
|
unit="ng/ml"
|
||||||
allowEmpty={true}
|
allowEmpty={true}
|
||||||
clearButton={true}
|
clearButton={true}
|
||||||
|
warning={!!yAxisRangeError}
|
||||||
|
warningMessage={yAxisRangeError}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ export const getDefaultState = (): AppState => ({
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
steadyStateConfig: { daysOnMedication: '7' }, // kept for backwards compatibility, now sourced from pkParams.advanced
|
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',
|
doseIncrement: '2.5',
|
||||||
uiSettings: {
|
uiSettings: {
|
||||||
showDayTimeOnXAxis: '24h',
|
showDayTimeOnXAxis: '24h',
|
||||||
@@ -168,7 +168,7 @@ export const getDefaultState = (): AppState => ({
|
|||||||
yAxisMin: '',
|
yAxisMin: '',
|
||||||
yAxisMax: '',
|
yAxisMax: '',
|
||||||
simulationDays: '5',
|
simulationDays: '5',
|
||||||
displayedDays: '2',
|
displayedDays: '1',
|
||||||
showTherapeuticRange: false,
|
showTherapeuticRange: false,
|
||||||
steadyStateDaysEnabled: true,
|
steadyStateDaysEnabled: true,
|
||||||
stickyChart: false,
|
stickyChart: false,
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ export const de = {
|
|||||||
|
|
||||||
showDayReferenceLines: "Tagestrenner anzeigen",
|
showDayReferenceLines: "Tagestrenner anzeigen",
|
||||||
showDayReferenceLinesTooltip: "Vertikale Linien und Statusanzeigen zwischen Tagen anzeigen (Standard: aktiviert).",
|
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).",
|
showTherapeuticRangeLinesTooltip: "Horizontale Referenzlinien für therapeutisches Min/Max anzeigen (Standard: aktiviert).",
|
||||||
simulationDuration: "Simulationsdauer",
|
simulationDuration: "Simulationsdauer",
|
||||||
simulationDurationTooltip: "Anzahl der zu simulierenden Tage. Längere Zeiträume zeigen Steady-State. Standard: {{simulationDays}} Tage.",
|
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",
|
yAxisRangeAutoButton: "A",
|
||||||
yAxisRangeAutoButtonTitle: "Bereich automatisch anhand des Datenbereichs bestimmen",
|
yAxisRangeAutoButtonTitle: "Bereich automatisch anhand des Datenbereichs bestimmen",
|
||||||
auto: "Auto",
|
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.",
|
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",
|
dAmphetamineParameters: "d-Amphetamin Parameter",
|
||||||
halfLife: "Eliminations-Halbwertszeit",
|
halfLife: "Eliminations-Halbwertszeit",
|
||||||
@@ -269,6 +269,8 @@ export const de = {
|
|||||||
errorConversionHalfLifeRequired: "⛔ Umwandlungs-Halbwertszeit ist erforderlich.",
|
errorConversionHalfLifeRequired: "⛔ Umwandlungs-Halbwertszeit ist erforderlich.",
|
||||||
errorTherapeuticRangeMinRequired: "⛔ Minimaler therapeutischer Bereich ist erforderlich.",
|
errorTherapeuticRangeMinRequired: "⛔ Minimaler therapeutischer Bereich ist erforderlich.",
|
||||||
errorTherapeuticRangeMaxRequired: "⛔ Maximaler 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.",
|
errorEliminationHalfLifeRequired: "⛔ Eliminations-Halbwertszeit ist erforderlich.",
|
||||||
|
|
||||||
// Field validation - Warnings
|
// Field validation - Warnings
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ export const en = {
|
|||||||
yAxisRangeAutoButton: "A",
|
yAxisRangeAutoButton: "A",
|
||||||
yAxisRangeAutoButtonTitle: "Determine range automatically based on data range",
|
yAxisRangeAutoButtonTitle: "Determine range automatically based on data range",
|
||||||
auto: "Auto",
|
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.",
|
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",
|
dAmphetamineParameters: "d-Amphetamine Parameters",
|
||||||
halfLife: "Elimination Half-life",
|
halfLife: "Elimination Half-life",
|
||||||
@@ -268,6 +268,8 @@ export const en = {
|
|||||||
errorAbsorptionRateRequired: "⛔ Absorption rate is required.",
|
errorAbsorptionRateRequired: "⛔ Absorption rate is required.",
|
||||||
errorTherapeuticRangeMinRequired: "⛔ Minimum therapeutic range is required.",
|
errorTherapeuticRangeMinRequired: "⛔ Minimum therapeutic range is required.",
|
||||||
errorTherapeuticRangeMaxRequired: "⛔ Maximum 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.",
|
errorEliminationHalfLifeRequired: "⛔ Elimination half-life is required.",
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user