Fix therapeutic range input

This commit is contained in:
2025-11-24 18:48:20 +00:00
parent c4ddf1f32b
commit 84c88ea6d3
4 changed files with 70 additions and 61 deletions

View File

@@ -139,7 +139,7 @@ const MedPlanAssistant = () => {
therapeuticRange={therapeuticRange} therapeuticRange={therapeuticRange}
uiSettings={uiSettings} uiSettings={uiSettings}
onUpdatePkParams={(key, value) => updateNestedState('pkParams', key, value)} onUpdatePkParams={(key, value) => updateNestedState('pkParams', key, value)}
onUpdateTherapeuticRange={(key, value) => updateNestedState('therapeuticRange', key, { [key]: value })} onUpdateTherapeuticRange={(key, value) => updateNestedState('therapeuticRange', key, value)}
onUpdateUiSetting={updateUiSetting} onUpdateUiSetting={updateUiSetting}
onReset={handleReset} onReset={handleReset}
t={t} t={t}

View File

@@ -10,11 +10,14 @@ const NumericInput = ({
unit, unit,
align = 'right', // 'left', 'center', 'right' align = 'right', // 'left', 'center', 'right'
allowEmpty = false, // Allow empty value (e.g., for "Auto" mode) allowEmpty = false, // Allow empty value (e.g., for "Auto" mode)
clearButton = false, // Show clear button (with allowEmpty=true)
errorMessage = 'This field is required' // Error message for mandatory empty fields errorMessage = 'This field is required' // Error message for mandatory empty fields
}) => { }) => {
const [hasError, setHasError] = React.useState(false); const [hasError, setHasError] = React.useState(false);
const [showErrorTooltip, setShowErrorTooltip] = React.useState(false); const [showErrorTooltip, setShowErrorTooltip] = React.useState(false);
const containerRef = React.useRef(null); const containerRef = React.useRef(null);
const showClearButton = clearButton && allowEmpty;
// Determine decimal places based on increment // Determine decimal places based on increment
const getDecimalPlaces = () => { const getDecimalPlaces = () => {
const inc = String(increment || '1'); const inc = String(increment || '1');
@@ -158,14 +161,14 @@ const NumericInput = ({
return ( return (
<div <div
ref={containerRef} ref={containerRef}
className="relative" className="relative inline-block"
onMouseEnter={handleMouseEnter} onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave} onMouseLeave={handleMouseLeave}
> >
<div className="relative inline-flex items-center"> <div className="relative inline-flex items-center">
<button <button
onClick={() => updateValue(-1)} onClick={() => updateValue(-1)}
className="px-2 py-1 border rounded-l-md bg-gray-100 hover:bg-gray-200 text-lg font-bold" className="px-2 py-1 border rounded-l-md bg-gray-100 bg-gray-100 hover:bg-gray-200 text-gray-600 hover:text-gray-800 text-lg font-bold"
tabIndex={-1} tabIndex={-1}
> >
- -
@@ -183,15 +186,15 @@ const NumericInput = ({
/> />
<button <button
onClick={() => updateValue(1)} onClick={() => updateValue(1)}
className={`px-2 py-1 border bg-gray-100 hover:bg-gray-200 text-lg font-bold ${!allowEmpty ? 'rounded-r-md' : ''}`} className={`px-2 py-1 border-t border-b ${showClearButton ? 'border-l' : 'border-l border-r rounded-r-md'} bg-gray-100 bg-gray-100 hover:bg-gray-200 text-gray-600 hover:text-gray-800 text-lg font-bold`}
tabIndex={-1} tabIndex={-1}
> >
+ +
</button> </button>
{allowEmpty && ( {showClearButton && (
<button <button
onClick={handleClear} onClick={handleClear}
className="px-2 py-1 border rounded-r-md bg-gray-100 hover:bg-gray-200 text-gray-600 hover:text-gray-800" className="px-2 py-1 border rounded-r-md bg-gray-100 bg-gray-100 hover:bg-gray-200 text-gray-600 hover:text-gray-800 text-gray-600 hover:text-gray-800"
tabIndex={-1} tabIndex={-1}
title="Clear (set to Auto)" title="Clear (set to Auto)"
> >
@@ -203,8 +206,8 @@ const NumericInput = ({
{hasError && ( {hasError && (
<div className="absolute inset-0 border-2 border-red-500 rounded-md pointer-events-none" style={{ zIndex: 10 }} /> <div className="absolute inset-0 border-2 border-red-500 rounded-md pointer-events-none" style={{ zIndex: 10 }} />
)} )}
</div>
{unit && <span className="ml-2 text-gray-500 text-sm whitespace-nowrap">{unit}</span>} {unit && <span className="ml-2 text-gray-500 text-sm whitespace-nowrap">{unit}</span>}
</div>
{hasError && showErrorTooltip && ( {hasError && showErrorTooltip && (
<div <div
className={`absolute z-50 bg-white border-2 border-red-500 rounded-md shadow-lg p-2 flex items-start gap-2 ${ className={`absolute z-50 bg-white border-2 border-red-500 rounded-md shadow-lg p-2 flex items-start gap-2 ${

View File

@@ -30,8 +30,8 @@ const Settings = ({
</label> </label>
</div> </div>
<div>
<label className="block font-medium text-gray-600 pt-2">{t.simulationDuration}</label> <label className="block font-medium text-gray-600 pt-2">{t.simulationDuration}</label>
<div className="w-40">
<NumericInput <NumericInput
value={simulationDays} value={simulationDays}
onChange={val => onUpdateUiSetting('simulationDays', val)} onChange={val => onUpdateUiSetting('simulationDays', val)}
@@ -43,8 +43,8 @@ const Settings = ({
/> />
</div> </div>
<div>
<label className="block font-medium text-gray-600">{t.displayedDays}</label> <label className="block font-medium text-gray-600">{t.displayedDays}</label>
<div className="w-40">
<NumericInput <NumericInput
value={displayedDays} value={displayedDays}
onChange={val => onUpdateUiSetting('displayedDays', val)} onChange={val => onUpdateUiSetting('displayedDays', val)}
@@ -56,6 +56,7 @@ const Settings = ({
/> />
</div> </div>
<div>
<label className="block font-medium text-gray-600 pt-2">{t.yAxisRange}</label> <label className="block font-medium text-gray-600 pt-2">{t.yAxisRange}</label>
<div className="flex items-center mt-1"> <div className="flex items-center mt-1">
<div className="w-30"> <div className="w-30">
@@ -66,6 +67,7 @@ const Settings = ({
min={0} min={0}
placeholder={t.auto} placeholder={t.auto}
allowEmpty={true} allowEmpty={true}
clearButton={true}
/> />
</div> </div>
<span className="text-gray-500 px-2">-</span> <span className="text-gray-500 px-2">-</span>
@@ -78,10 +80,13 @@ const Settings = ({
placeholder={t.auto} placeholder={t.auto}
unit="ng/ml" unit="ng/ml"
allowEmpty={true} allowEmpty={true}
clearButton={true}
/> />
</div> </div>
</div> </div>
</div>
<div>
<label className="block font-medium text-gray-600">{t.therapeuticRange}</label> <label className="block font-medium text-gray-600">{t.therapeuticRange}</label>
<div className="flex items-center mt-1"> <div className="flex items-center mt-1">
<div className="w-30"> <div className="w-30">
@@ -107,9 +112,10 @@ const Settings = ({
/> />
</div> </div>
</div> </div>
</div>
<h3 className="text-lg font-semibold mt-4 pt-4 border-t">{t.dAmphetamineParameters}</h3> <h3 className="text-lg font-semibold mt-4 pt-4 border-t">{t.dAmphetamineParameters}</h3>
<div className="w-40"> <div>
<label className="block font-medium text-gray-600">{t.halfLife}</label> <label className="block font-medium text-gray-600">{t.halfLife}</label>
<NumericInput <NumericInput
value={pkParams.damph.halfLife} value={pkParams.damph.halfLife}
@@ -122,7 +128,7 @@ const Settings = ({
</div> </div>
<h3 className="text-lg font-semibold mt-4 pt-4 border-t">{t.lisdexamfetamineParameters}</h3> <h3 className="text-lg font-semibold mt-4 pt-4 border-t">{t.lisdexamfetamineParameters}</h3>
<div className="w-40"> <div>
<label className="block font-medium text-gray-600">{t.conversionHalfLife}</label> <label className="block font-medium text-gray-600">{t.conversionHalfLife}</label>
<NumericInput <NumericInput
value={pkParams.ldx.halfLife} value={pkParams.ldx.halfLife}
@@ -133,7 +139,7 @@ const Settings = ({
errorMessage={t.fieldRequired} errorMessage={t.fieldRequired}
/> />
</div> </div>
<div className="w-40"> <div>
<label className="block font-medium text-gray-600">{t.absorptionRate}</label> <label className="block font-medium text-gray-600">{t.absorptionRate}</label>
<NumericInput <NumericInput
value={pkParams.ldx.absorptionRate} value={pkParams.ldx.absorptionRate}

View File

@@ -16,7 +16,7 @@ export const getDefaultState = () => ({
{ time: '01:00', dose: '0', label: 'night' }, { time: '01:00', dose: '0', label: 'night' },
], ],
steadyStateConfig: { daysOnMedication: '7' }, steadyStateConfig: { daysOnMedication: '7' },
therapeuticRange: { min: '11.5', max: '14' }, therapeuticRange: { min: '10.5', max: '11.5' },
doseIncrement: '2.5', doseIncrement: '2.5',
uiSettings: { uiSettings: {
showDayTimeXAxis: true, showDayTimeXAxis: true,