Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/clamp duration #737

Merged
merged 2 commits into from
Nov 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 6 additions & 14 deletions src/components/duration/duration.scss
Original file line number Diff line number Diff line change
@@ -1,17 +1,9 @@
.input-field {
width: 100px;
margin-right: 10px
}
.field-group {
.duration-fields,
.duration-field {
display: flex;
align-items: center;
gap: 1rem;
}

.input-field-group {
display: flex;
align-items: first baseline;
margin: 5px;
.duration-field {
gap: .5rem;
}

.input-label {
margin-right: 5px;
}
11 changes: 7 additions & 4 deletions src/components/duration/duration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,13 @@ function Duration(props: LunaticComponentProps<'Duration'>) {
description={description}
handleChange={handleChange}
>
<div className="container">
{label}
<DurationInput value={value} format={format} onChange={onChange} />
</div>
<DurationInput
id={id}
label={label}
value={value}
format={format}
onChange={onChange}
/>
</LunaticComponent>
);
}
Expand Down
42 changes: 25 additions & 17 deletions src/components/duration/durationInput.tsx
Original file line number Diff line number Diff line change
@@ -1,45 +1,53 @@
import { Fragment, useState } from 'react';
import { type ReactNode, useState } from 'react';
import { objectKeys } from '../../utils/object';
import { formatDuration } from './formatDuration';
import { getDurationFromValue } from './getDurationFromValue';
import { type Formats, labelByUnit, propsByUnit } from './durationUtils';
import {
clampDuration,
type Formats,
labelByUnit,
propsByUnit,
} from './durationUtils';
import classnames from 'classnames';

const DurationInput = ({
value,
format,
onChange,
}: {
type Props = {
label?: ReactNode;
id?: string;
value: string | null;
format: Formats;
onChange: (s: string | null) => void;
}) => {
};

const DurationInput = ({ value, format, onChange, label }: Props) => {
// We need to keep an internal state since one field can be empty (null value in duration)
// but we still send "0" and we don't want the field to display "0"
const [duration, setDuration] = useState(getDurationFromValue(value, format));

// Generate handler for a specific unit field (year, month...)
const changeHandler =
(unit: string) =>
(unit: 'hours' | 'minutes' | 'months' | 'years') =>
(e: {
// CheckValidity function is used to apply constraints to a field Ex: (min, max)
target: { valueAsNumber: number; checkValidity: () => boolean };
}) => {
if (!e.target.checkValidity()) {
return;
}
const fieldValue = Number.isNaN(e.target.valueAsNumber)
? null
: e.target.valueAsNumber;
const fieldValue = clampDuration(
Number.isNaN(e.target.valueAsNumber) ? null : e.target.valueAsNumber,
unit
);
const newDuration = { ...duration, [unit]: fieldValue };
onChange(formatDuration(newDuration));
setDuration(newDuration);
};

return (
<div className="field-group">
<div className="input-field-group">
<fieldset className={classnames('lunatic-input')}>
{label && <legend>{label}</legend>}
<div className="duration-fields">
{objectKeys(duration).map((unit) => (
<Fragment key={unit}>
<div className="duration-field" key={unit}>
<label htmlFor={`${unit}Input`} className="input-label">
{labelByUnit[unit]}
</label>
Expand All @@ -51,10 +59,10 @@ const DurationInput = ({
onChange={changeHandler(unit)}
{...propsByUnit[unit]}
/>
</Fragment>
</div>
))}
</div>
</div>
</fieldset>
);
};

Expand Down
25 changes: 21 additions & 4 deletions src/components/duration/durationUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ export type DurationValue = {
export type Formats = 'PTnHnM' | 'PnYnM';

export const propsByUnit = {
hours: { min: '0', max: '23' },
minutes: { min: '0', max: '59' },
months: { min: '0', max: '11' },
years: { min: '0' },
hours: { min: 0, max: 23, size: 2, style: { width: '2.5em' } },
minutes: { min: 0, max: 59, size: 2, style: { width: '2.5em' } },
months: { min: 0, max: 11, size: 2, style: { width: '2.5em' } },
years: { min: 0, size: 4, style: { width: '4em' } },
};

export const labelByUnit = {
Expand All @@ -20,3 +20,20 @@ export const labelByUnit = {
months: 'Mois : ',
years: 'Années :',
};

export function clampDuration(
value: number | null,
unit: keyof typeof propsByUnit
) {
if (value === null) {
return value;
}
const props = propsByUnit[unit];
if (value < props.min) {
return props.min;
}
if ('max' in props && value > props.max) {
return props.max;
}
return value;
}
8 changes: 4 additions & 4 deletions src/stories/duration/duration.stories.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from 'react';
import defaultArgTypes from '../utils/default-arg-types';
import Orchestrator from '../utils/orchestrator';
import source from './source';
import source1 from './source1';
import moisSource from './mois';
import timeSource from './time';

const stories = {
title: 'Components/Duration',
Expand All @@ -15,11 +15,11 @@ export default stories;
const Template = (args) => <Orchestrator {...args} />;
export const DateDuration = Template.bind({});

DateDuration.args = { id: 'durationAnnéesMois', source };
DateDuration.args = { id: 'durationAnnéesMois', source: moisSource };

export const TimeDuration = Template.bind({});

TimeDuration.args = {
id: 'durationHeureMinute',
source: source1,
source: timeSource,
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"page": "1",
"maxPage": "1",
"label": {
"value": "\"➡ 1. \" || \"Duration \"",
"value": "\"➡ 1. \" || \"Duration (format: PnYnM) \"",
"type": "VTL|MD"
},
"description": { "value": "\"Description\"", "type": "VTL|MD" },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"page": "1",
"maxPage": "1",
"label": {
"value": "\"➡ 1. \" || \"Duration \"",
"value": "\"➡ 1. \" || \"Duration (format: PTnHnM) \"",
"type": "VTL|MD"
},
"description": { "value": "\"Description\"", "type": "VTL|MD" },
Expand Down