Update NumericInput size and decimal digits
This commit is contained in:
@@ -15,7 +15,7 @@ const DeviationList = ({
|
|||||||
<div className="bg-amber-50 p-5 rounded-lg shadow-sm border border-amber-200">
|
<div className="bg-amber-50 p-5 rounded-lg shadow-sm border border-amber-200">
|
||||||
<h2 className="text-xl font-semibold mb-4 text-gray-700">{t.deviationsFromPlan}</h2>
|
<h2 className="text-xl font-semibold mb-4 text-gray-700">{t.deviationsFromPlan}</h2>
|
||||||
{deviations.map((dev, index) => (
|
{deviations.map((dev, index) => (
|
||||||
<div key={index} className="flex items-center space-x-2 mb-2 p-2 bg-white rounded flex-wrap">
|
<div key={index} className="flex items-center gap-3 mb-2 p-2 bg-white rounded flex-wrap">
|
||||||
<select
|
<select
|
||||||
value={dev.dayOffset || 0}
|
value={dev.dayOffset || 0}
|
||||||
onChange={e => onDeviationChange(index, 'dayOffset', parseInt(e.target.value, 10))}
|
onChange={e => onDeviationChange(index, 'dayOffset', parseInt(e.target.value, 10))}
|
||||||
@@ -40,11 +40,11 @@ const DeviationList = ({
|
|||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={() => onRemoveDeviation(index)}
|
onClick={() => onRemoveDeviation(index)}
|
||||||
className="text-red-500 hover:text-red-700 font-bold text-lg"
|
className="text-red-500 hover:text-red-700 font-bold text-lg px-1"
|
||||||
>
|
>
|
||||||
×
|
×
|
||||||
</button>
|
</button>
|
||||||
<div className="flex items-center mt-1" title={t.additionalTooltip}>
|
<div className="flex items-center" title={t.additionalTooltip}>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
id={`add_dose_${index}`}
|
id={`add_dose_${index}`}
|
||||||
@@ -52,7 +52,7 @@ const DeviationList = ({
|
|||||||
onChange={e => onDeviationChange(index, 'isAdditional', e.target.checked)}
|
onChange={e => onDeviationChange(index, 'isAdditional', e.target.checked)}
|
||||||
className="h-4 w-4 rounded border-gray-300 text-sky-600 focus:ring-sky-500"
|
className="h-4 w-4 rounded border-gray-300 text-sky-600 focus:ring-sky-500"
|
||||||
/>
|
/>
|
||||||
<label htmlFor={`add_dose_${index}`} className="ml-2 text-xs text-gray-600">
|
<label htmlFor={`add_dose_${index}`} className="ml-2 text-xs text-gray-600 whitespace-nowrap">
|
||||||
{t.additional}
|
{t.additional}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,13 +1,42 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
const NumericInput = ({ value, onChange, increment, min = -Infinity, max = Infinity, placeholder, unit }) => {
|
const NumericInput = ({
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
increment,
|
||||||
|
min = -Infinity,
|
||||||
|
max = Infinity,
|
||||||
|
placeholder,
|
||||||
|
unit,
|
||||||
|
align = 'right' // 'left', 'center', 'right'
|
||||||
|
}) => {
|
||||||
|
// Determine decimal places based on increment
|
||||||
|
const getDecimalPlaces = () => {
|
||||||
|
const inc = String(increment || '1');
|
||||||
|
const decimalIndex = inc.indexOf('.');
|
||||||
|
if (decimalIndex === -1) return 0;
|
||||||
|
return inc.length - decimalIndex - 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
const decimalPlaces = getDecimalPlaces();
|
||||||
|
|
||||||
|
// Format value for display
|
||||||
|
const formatValue = (val) => {
|
||||||
|
const num = Number(val);
|
||||||
|
if (isNaN(num)) return val;
|
||||||
|
return num.toFixed(decimalPlaces);
|
||||||
|
};
|
||||||
|
|
||||||
const updateValue = (direction) => {
|
const updateValue = (direction) => {
|
||||||
const numIncrement = parseFloat(increment) || 1;
|
const numIncrement = parseFloat(increment) || 1;
|
||||||
let numValue = parseFloat(value) || 0;
|
let numValue = Number(value);
|
||||||
|
if (isNaN(numValue)) {
|
||||||
|
numValue = min !== -Infinity ? min : 0;
|
||||||
|
}
|
||||||
numValue += direction * numIncrement;
|
numValue += direction * numIncrement;
|
||||||
numValue = Math.max(min, numValue);
|
numValue = Math.max(min, numValue);
|
||||||
numValue = Math.min(max, numValue);
|
numValue = Math.min(max, numValue);
|
||||||
const finalValue = String(Math.round(numValue * 100) / 100);
|
const finalValue = formatValue(numValue);
|
||||||
onChange(finalValue);
|
onChange(finalValue);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -20,16 +49,38 @@ const NumericInput = ({ value, onChange, increment, min = -Infinity, max = Infin
|
|||||||
|
|
||||||
const handleChange = (e) => {
|
const handleChange = (e) => {
|
||||||
const val = e.target.value;
|
const val = e.target.value;
|
||||||
|
// Only allow valid numbers or empty string
|
||||||
if (val === '' || /^-?\d*\.?\d*$/.test(val)) {
|
if (val === '' || /^-?\d*\.?\d*$/.test(val)) {
|
||||||
|
// Prevent object values
|
||||||
|
if (typeof val === 'object') return;
|
||||||
onChange(val);
|
onChange(val);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleBlur = (e) => {
|
||||||
|
const val = e.target.value;
|
||||||
|
if (val !== '' && !isNaN(Number(val))) {
|
||||||
|
// Format the value when user finishes editing
|
||||||
|
onChange(formatValue(val));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get alignment class
|
||||||
|
const getAlignmentClass = () => {
|
||||||
|
switch (align) {
|
||||||
|
case 'left': return 'text-left';
|
||||||
|
case 'center': return 'text-center';
|
||||||
|
case 'right': return 'text-right';
|
||||||
|
default: return 'text-right';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center w-full">
|
<div className="flex items-center w-full">
|
||||||
<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 hover:bg-gray-200 text-lg font-bold"
|
||||||
|
tabIndex={-1}
|
||||||
>
|
>
|
||||||
-
|
-
|
||||||
</button>
|
</button>
|
||||||
@@ -38,12 +89,15 @@ const NumericInput = ({ value, onChange, increment, min = -Infinity, max = Infin
|
|||||||
value={value}
|
value={value}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
|
onBlur={handleBlur}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
className="p-2 border-t border-b w-full text-sm text-center"
|
style={{ width: '4em', minWidth: '4em', maxWidth: '8em' }}
|
||||||
|
className={`p-2 border-t border-b text-sm ${getAlignmentClass()}`}
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
onClick={() => updateValue(1)}
|
onClick={() => updateValue(1)}
|
||||||
className="px-2 py-1 border rounded-r-md bg-gray-100 hover:bg-gray-200 text-lg font-bold"
|
className="px-2 py-1 border rounded-r-md bg-gray-100 hover:bg-gray-200 text-lg font-bold"
|
||||||
|
tabIndex={-1}
|
||||||
>
|
>
|
||||||
+
|
+
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ const Settings = ({
|
|||||||
</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 space-x-2 mt-1">
|
<div className="flex items-center space-x-3 mt-1">
|
||||||
<div className="w-32">
|
<div className="w-32">
|
||||||
<NumericInput
|
<NumericInput
|
||||||
value={yAxisMin}
|
value={yAxisMin}
|
||||||
@@ -66,7 +66,7 @@ const Settings = ({
|
|||||||
unit="ng/ml"
|
unit="ng/ml"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-gray-500">-</span>
|
<span className="text-gray-500 px-2">-</span>
|
||||||
<div className="w-32">
|
<div className="w-32">
|
||||||
<NumericInput
|
<NumericInput
|
||||||
value={yAxisMax}
|
value={yAxisMax}
|
||||||
@@ -80,7 +80,7 @@ const Settings = ({
|
|||||||
</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 space-x-2 mt-1">
|
<div className="flex items-center space-x-3 mt-1">
|
||||||
<div className="w-32">
|
<div className="w-32">
|
||||||
<NumericInput
|
<NumericInput
|
||||||
value={therapeuticRange.min}
|
value={therapeuticRange.min}
|
||||||
@@ -91,7 +91,7 @@ const Settings = ({
|
|||||||
unit="ng/ml"
|
unit="ng/ml"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<span className="text-gray-500">-</span>
|
<span className="text-gray-500 px-2">-</span>
|
||||||
<div className="w-32">
|
<div className="w-32">
|
||||||
<NumericInput
|
<NumericInput
|
||||||
value={therapeuticRange.max}
|
value={therapeuticRange.max}
|
||||||
|
|||||||
Reference in New Issue
Block a user