Skip to content

Commit b8ebc0e

Browse files
committed
fixup! Add tolerancePicker component and styling
1 parent 8c4d3a7 commit b8ebc0e

File tree

3 files changed

+146
-55
lines changed

3 files changed

+146
-55
lines changed

ui-core/src/components/inputs/TolerancePicker.tsx

+87-52
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,72 @@
1-
import React, { useState, useRef } from 'react';
1+
/* eslint-disable react-hooks/exhaustive-deps */
2+
import React, { useState, useRef, useMemo, useEffect } from 'react';
23
import Input, { InputProps } from './Input';
34
import Modal from '../Modal';
5+
import cx from 'classnames';
6+
import { StatusWithMessage } from './StatusMessage';
47

5-
const TolerancePicker: React.FC<InputProps> = (inputProps) => {
8+
type ToleranceRange = { label: string; value: number };
9+
10+
export type ToleranceValues = {
11+
minusTolerance: number;
12+
plusTolerance: number;
13+
};
14+
15+
export type TolerancePickerProps = Omit<InputProps, 'value'> & {
16+
onToleranceChange: (toleranceValues: ToleranceValues) => void;
17+
toleranceRanges: ToleranceRange[];
18+
toleranceValues?: ToleranceValues;
19+
};
20+
21+
const TolerancePicker: React.FC<TolerancePickerProps> = ({
22+
onToleranceChange,
23+
toleranceRanges,
24+
toleranceValues: { minusTolerance, plusTolerance } = {
25+
minusTolerance: toleranceRanges[0].value,
26+
plusTolerance: toleranceRanges[0].value,
27+
},
28+
...inputProps
29+
}) => {
630
const [showPicker, setShowPicker] = useState(false);
7-
const [minusTolerance, setMinusTolerance] = useState('00');
8-
const [plusTolerance, setPlusTolerance] = useState('00');
9-
const [inputValue, setInputValue] = useState('');
31+
const [inputValue, setInputValue] = useState(
32+
`-${toleranceRanges[0].label}/+${toleranceRanges[0].label}`
33+
);
34+
const [warningStatus, setWarningStatus] = useState<StatusWithMessage | undefined>(undefined);
1035
const inputRef = useRef<HTMLInputElement>(null);
1136

12-
const handleTimeChange = (newMinusTolerance: string, newPlusTolerance: string) => {
13-
setMinusTolerance(newMinusTolerance);
14-
setPlusTolerance(newPlusTolerance);
15-
const formattedValue = `-${newMinusTolerance}/+${newPlusTolerance}`;
16-
setInputValue(formattedValue);
17-
};
37+
const { minusToleranceIndex, plusToleranceIndex } = useMemo(() => {
38+
const minusToleranceIndex = toleranceRanges.findIndex(
39+
(range) => range.value === minusTolerance
40+
);
41+
const plusToleranceIndex = toleranceRanges.findIndex((range) => range.value === plusTolerance);
42+
if (minusToleranceIndex < 0 || plusToleranceIndex < 0)
43+
setWarningStatus({
44+
status: 'warning',
45+
message: "One of the values isn't included in the ranges provided.",
46+
});
47+
return { minusToleranceIndex, plusToleranceIndex };
48+
}, [minusTolerance, plusTolerance, toleranceRanges]);
49+
50+
const getToleranceLabel = (toleranceIndex: number) =>
51+
`${toleranceIndex < 0 ? '' : toleranceRanges[toleranceIndex].label}`;
1852

19-
const TOLERANCE_RANGES = [
20-
'00',
21-
'05',
22-
'10',
23-
'15',
24-
'20',
25-
'25',
26-
'30',
27-
'35',
28-
'40',
29-
'45',
30-
'1h',
31-
'1h15',
32-
'1h30',
33-
'1h45',
34-
'2h',
35-
'2h30',
36-
'3h00',
37-
'3h30',
38-
'4h00',
39-
];
53+
useEffect(() => {
54+
const formattedInputValue = `-${getToleranceLabel(minusToleranceIndex)}/+${getToleranceLabel(plusToleranceIndex)}`;
55+
setInputValue(formattedInputValue);
56+
}, [minusTolerance, plusTolerance]);
4057

4158
return (
4259
<div className="tolerance-picker">
4360
<div>
4461
<Input
4562
{...inputProps}
4663
value={inputValue}
64+
// Event not used for now
4765
onChange={(e) => {
4866
setInputValue(e.target.value);
4967
setShowPicker(true);
5068
}}
69+
statusWithMessage={warningStatus}
5170
readOnly
5271
onClick={() => setShowPicker(!showPicker)}
5372
type="text"
@@ -59,33 +78,49 @@ const TolerancePicker: React.FC<InputProps> = (inputProps) => {
5978
<div className="time-tolerance">
6079
<div className="time-picker-section">
6180
<div className="tolerance-grid">
62-
{TOLERANCE_RANGES.map((tolerance, index) => (
63-
<button
64-
key={tolerance}
65-
className={`minute ${minusTolerance === tolerance ? 'selected' : ''}`}
66-
style={{ gridArea: `a${index + 1}` }}
67-
onClick={() => handleTimeChange(tolerance, plusTolerance)}
68-
>
69-
{`-${tolerance}`}
70-
</button>
71-
))}
81+
{toleranceRanges.map((tolerance, index) => {
82+
const { label, value } = tolerance;
83+
return (
84+
<button
85+
key={`${label}-${index}`}
86+
className={cx('minute', { selected: minusTolerance === value })}
87+
style={{ gridArea: `a${index + 1}` }}
88+
onClick={() =>
89+
onToleranceChange({
90+
minusTolerance: value,
91+
plusTolerance: toleranceRanges[plusToleranceIndex].value,
92+
})
93+
}
94+
>
95+
{`-${label}`}
96+
</button>
97+
);
98+
})}
7299
</div>
73100
</div>
74101

75102
<div className="divider" />
76103

77104
<div className="time-picker-section">
78105
<div className="tolerance-grid plus-tolerance">
79-
{TOLERANCE_RANGES.map((tolerance, index) => (
80-
<button
81-
key={tolerance}
82-
className={`minute ${plusTolerance === tolerance ? 'selected' : ''}`}
83-
style={{ gridArea: `a${index + 1}` }}
84-
onClick={() => handleTimeChange(minusTolerance, tolerance)}
85-
>
86-
{`+${tolerance}`}
87-
</button>
88-
))}
106+
{toleranceRanges.map((tolerance, index) => {
107+
const { label, value } = tolerance;
108+
return (
109+
<button
110+
key={`${label}-${index}`}
111+
className={cx('minute', { selected: plusTolerance === value })}
112+
style={{ gridArea: `a${index + 1}` }}
113+
onClick={() =>
114+
onToleranceChange({
115+
minusTolerance: toleranceRanges[minusToleranceIndex].value,
116+
plusTolerance: value,
117+
})
118+
}
119+
>
120+
{`+${label}`}
121+
</button>
122+
);
123+
})}
89124
</div>
90125
</div>
91126
</div>

ui-core/src/index.ts

+4
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,7 @@ export { default as RadioButton, RadioButtonProps } from './components/inputs/Ra
1717
export { default as RadioGroup, RadioGroupProps } from './components/inputs/RadioGroup';
1818
export { default as Select, SelectProps } from './components/Select';
1919
export { default as TimePicker } from './components/inputs/TimePicker';
20+
export {
21+
default as TolerancePicker,
22+
type TolerancePickerProps,
23+
} from './components/inputs/TolerancePicker';

ui-core/src/stories/TolerancePicker.stories.tsx

+55-3
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,67 @@
1-
import React from 'react';
1+
import React, { useEffect, useState } from 'react';
22
import { Meta, StoryObj } from '@storybook/react';
3-
import TolerancePicker from '../components/inputs/TolerancePicker';
3+
import TolerancePicker, {
4+
TolerancePickerProps,
5+
ToleranceValues,
6+
} from '../components/inputs/TolerancePicker';
47

58
import '@osrd-project/ui-core/dist/theme.css';
69

10+
const TolerancePickerStory = (props: TolerancePickerProps) => {
11+
const [toleranceValues, setToleranceValues] = useState(props.toleranceValues);
12+
const onToleranceChange = ({ minusTolerance, plusTolerance }: ToleranceValues) => {
13+
setToleranceValues({ minusTolerance, plusTolerance });
14+
};
15+
16+
const toleranceRanges = [
17+
{ label: '00', value: 0 },
18+
{ label: '05', value: 300 },
19+
{ label: '10', value: 600 },
20+
{ label: '15', value: 900 },
21+
{ label: '20', value: 1200 },
22+
{ label: '25', value: 1500 },
23+
{ label: '30', value: 1800 },
24+
{ label: '35', value: 2100 },
25+
{ label: '40', value: 2400 },
26+
{ label: '45', value: 2700 },
27+
{ label: '1h00', value: 3600 },
28+
{ label: '1h15', value: 4500 },
29+
{ label: '1h30', value: 5400 },
30+
{ label: '1h45', value: 6300 },
31+
{ label: '2h00', value: 7200 },
32+
{ label: '2h30', value: 9000 },
33+
{ label: '3h00', value: 10800 },
34+
{ label: '3h30', value: 12600 },
35+
{ label: '4h00', value: 14400 },
36+
];
37+
38+
useEffect(() => {
39+
setToleranceValues(props.toleranceValues);
40+
}, [props.toleranceValues]);
41+
42+
return (
43+
<TolerancePicker
44+
{...props}
45+
toleranceValues={toleranceValues}
46+
toleranceRanges={toleranceRanges}
47+
onToleranceChange={onToleranceChange}
48+
/>
49+
);
50+
};
51+
752
const meta: Meta<typeof TolerancePicker> = {
853
component: TolerancePicker,
954
args: {
1055
label: 'TolerancePicker',
1156
id: 'time-picker',
1257
},
13-
title: 'TolerancePicker',
58+
argTypes: {
59+
toleranceValues: {
60+
minusTolerance: 'string',
61+
plusTolerance: 'string',
62+
},
63+
},
64+
title: 'core/TolerancePicker',
1465
tags: ['autodocs'],
1566
decorators: [
1667
(Story) => (
@@ -19,6 +70,7 @@ const meta: Meta<typeof TolerancePicker> = {
1970
</div>
2071
),
2172
],
73+
render: TolerancePickerStory,
2274
};
2375

2476
export default meta;

0 commit comments

Comments
 (0)