Skip to content

Commit 78906cb

Browse files
committed
front: add placeholders in rolling stock editor form
1 parent 545da67 commit 78906cb

File tree

7 files changed

+156
-48
lines changed

7 files changed

+156
-48
lines changed

front/public/locales/en/rollingstock.json

+2
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@
6161
"invalidForm": "Invalid form",
6262
"missingName": "Please fill the name of the new rolling stock",
6363
"missingEffortCurves": "Please fill in at least one effort-speed curve",
64+
"missingInformationAutomaticallyFilled_one": "The following filed was initialized by default: {{invalidFields}}.",
65+
"missingInformationAutomaticallyFilled_other": "The following fileds were initialized by default: {{invalidFields}}.",
6466
"rollingStockAdded": "Rolling stock added",
6567
"rollingStockUpdated": "Rolling stock updated",
6668
"rollingStockDeleted": "Rolling stock deleted",

front/public/locales/fr/rollingstock.json

+2
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@
6262
"invalidForm": "Formulaire incomplet",
6363
"missingName": "Veuillez renseigner un nom",
6464
"missingEffortCurves": "Veuillez renseigner une courbe effort-vitesse",
65+
"missingInformationAutomaticallyFilled_one": "Le champ suivant a été initialisé par défaut: {{invalidFields}}.",
66+
"missingInformationAutomaticallyFilled_other": "Les champs suivants ont été initialisés par défaut: {{invalidFields}}.",
6567
"rollingStockAdded": "Le matériel roulant a été ajouté.",
6668
"rollingStockUpdated": "Le matériel roulant a été mis à jour.",
6769
"rollingStockDeleted": "Le matériel roulant a été supprimé.",

front/src/modules/rollingStock/components/RollingStockEditor/RollingStockEditorForm.tsx

+44-24
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@ import {
77
} from 'common/api/osrdEditoastApi';
88
import { useModal } from 'common/BootstrapSNCF/ModalSNCF';
99
import { useDispatch, useSelector } from 'react-redux';
10-
import { setFailure, setSuccess } from 'reducers/main';
10+
import { addFailureNotification, setFailure, setSuccess } from 'reducers/main';
1111
import Tabs, { TabProps } from 'common/Tabs';
1212
import RollingStockEditorFormModal from 'modules/rollingStock/components/RollingStockEditor/RollingStockEditorFormModal';
1313
import {
1414
getRollingStockEditorDefaultValues,
1515
getDefaultRollingStockMode,
1616
rollingStockEditorQueryArg,
17+
checkRollingStockFormValidity,
1718
} from 'modules/rollingStock/helpers/utils';
1819
import {
1920
RollingStockEditorParameter,
@@ -53,6 +54,7 @@ const RollingStockEditorForm = ({
5354

5455
const [isValid, setIsValid] = useState(true);
5556
const [optionValue, setOptionValue] = useState('');
57+
const [errorMessage, setErrorMessage] = useState('');
5658

5759
const selectedTractionMode = useSelector(getTractionMode);
5860

@@ -149,22 +151,35 @@ const RollingStockEditorForm = ({
149151

150152
const submit = (e: React.FormEvent<HTMLFormElement>, data: RollingStockParametersValues) => {
151153
e.preventDefault();
154+
let error: undefined | { name: string; message: string };
152155
if (!data.name) {
153-
dispatch(
154-
setFailure({
155-
name: t('messages.invalidForm'),
156-
message: t('messages.missingName'),
157-
})
158-
);
156+
error = {
157+
name: t('messages.invalidForm'),
158+
message: t('messages.missingName'),
159+
};
159160
} else if (!selectedTractionMode || !currentRsEffortCurve) {
160-
dispatch(
161-
setFailure({
162-
name: t('messages.invalidForm'),
163-
message: t('messages.missingEffortCurves'),
161+
error = {
162+
name: t('messages.invalidForm'),
163+
message: t('messages.missingEffortCurves'),
164+
};
165+
}
166+
if (error) {
167+
dispatch(addFailureNotification(error));
168+
return;
169+
}
170+
171+
const { invalidFields, validRollingStockForm } = checkRollingStockFormValidity(data);
172+
if (invalidFields.length) {
173+
setRollingStockValues(validRollingStockForm);
174+
setErrorMessage(
175+
t('messages.missingInformationAutomaticallyFilled', {
176+
invalidFields: invalidFields.map((field) => t(field).toLowerCase()).join(', '),
177+
count: invalidFields.length,
164178
})
165179
);
166180
} else {
167-
const payload = rollingStockEditorQueryArg(data, currentRsEffortCurve);
181+
setErrorMessage('');
182+
const payload = rollingStockEditorQueryArg(validRollingStockForm, currentRsEffortCurve!);
168183
openModal(
169184
<RollingStockEditorFormModal
170185
setAddOrEditState={setAddOrEditState}
@@ -256,18 +271,23 @@ const RollingStockEditorForm = ({
256271
onSubmit={(e) => submit(e, rollingStockValues)}
257272
>
258273
<Tabs pills fullWidth tabs={[tabRollingStockDetails, tabRollingStockCurves]} />
259-
<div className="d-flex justify-content-between align-items-center">
260-
<div className="ml-auto my-3 pr-3">
261-
<button
262-
type="button"
263-
className="btn btn-secondary mr-2 py-1 px-2"
264-
onClick={() => cancel()}
265-
>
266-
{t('translation:common.cancel')}
267-
</button>
268-
<button type="submit" className="btn btn-primary py-1 px-2" disabled={!isValid}>
269-
{t('translation:common.confirm')}
270-
</button>
274+
<div className="d-flex justify-content-end">
275+
<div className="d-flex flex-column justify-content-end">
276+
{errorMessage && (
277+
<p className="text-danger mb-1 ml-auto error-message text-wrap">{errorMessage}</p>
278+
)}
279+
<div className="d-flex justify-content-end">
280+
<button
281+
type="button"
282+
className="btn btn-secondary mr-2 py-1 px-2"
283+
onClick={() => cancel()}
284+
>
285+
{t('translation:common.cancel')}
286+
</button>
287+
<button type="submit" className="btn btn-primary py-1 px-2" disabled={!isValid}>
288+
{t('translation:common.confirm')}
289+
</button>
290+
</div>
271291
</div>
272292
</div>
273293
</form>

front/src/modules/rollingStock/components/RollingStockEditor/RollingStockEditorFormHelpers.tsx

+17-10
Original file line numberDiff line numberDiff line change
@@ -141,15 +141,19 @@ const RollingStockEditorParameterFormColumn = ({
141141
label={t(`${property.title}`)}
142142
typeValue={property.type}
143143
type={optionValue}
144-
value={rollingStockValues[property.title] as string | number}
144+
value={
145+
rollingStockValues[property.title] !== undefined
146+
? (rollingStockValues[property.title] as string | number)
147+
: ''
148+
}
145149
options={property.units.map((unit) => ({
146150
id: `${property.title}-${unit}`,
147151
label: unit,
148152
}))}
149153
handleType={(type) => {
150154
setRollingStockValues({
151155
...rollingStockValues,
152-
[property.title]: Number(type.value) || 0,
156+
[property.title]: type.value !== '' ? Number(type.value) : undefined,
153157
} as SetStateAction<RollingStockParametersValues>);
154158
setOptionValue(type.type as string);
155159
}}
@@ -205,17 +209,20 @@ const RollingStockEditorParameterFormColumn = ({
205209
}
206210
unit={property.unit}
207211
value={
208-
property.title !== 'basePowerClass'
209-
? (rollingStockValues[property.title] as number)
210-
: rollingStockValues[property.title] ?? ''
212+
rollingStockValues[property.title] !== undefined
213+
? (rollingStockValues[property.title] as string | number)
214+
: ''
211215
}
212-
onChange={(e) =>
216+
onChange={({ target: { value } }) => {
217+
let newValue: string | number | undefined = value;
218+
if (property.title !== 'basePowerClass') {
219+
newValue = value !== '' ? Number(value) : undefined;
220+
}
213221
setRollingStockValues({
214222
...rollingStockValues,
215-
[property.title]:
216-
property.title !== 'basePowerClass' ? +e.target.value : e.target.value,
217-
})
218-
}
223+
[property.title]: newValue,
224+
});
225+
}}
219226
sm
220227
isFlex
221228
key={index}

front/src/modules/rollingStock/consts.ts

+41-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ export const effortCurveCondKeys: EffortCurveCondKeys = {
5959
powerRestrictions: 'power_restriction_code',
6060
};
6161

62-
export type RollingStockParametersValues = {
62+
export type RollingStockParametersValidValues = {
6363
// TODO: remove this line in the type
6464
[key: string]: string | number | null | EffortCurves | RollingStockBase['power_restrictions'];
6565
railjsonVersion: string;
@@ -93,6 +93,46 @@ export type RollingStockParametersValues = {
9393
powerRestrictions: RollingStockBase['power_restrictions'];
9494
};
9595

96+
export type RollingStockParametersValues = {
97+
// TODO: remove this line in the type
98+
[key: string]:
99+
| string
100+
| number
101+
| null
102+
| EffortCurves
103+
| RollingStockBase['power_restrictions']
104+
| undefined;
105+
railjsonVersion: string;
106+
name: string;
107+
detail: string;
108+
family: string;
109+
grouping: string;
110+
number: string;
111+
reference: string;
112+
series: string;
113+
subseries: string;
114+
type: string;
115+
unit: string;
116+
length?: number;
117+
mass?: number;
118+
maxSpeed?: number;
119+
startupTime?: number;
120+
startupAcceleration?: number;
121+
comfortAcceleration?: number;
122+
gammaValue?: number;
123+
inertiaCoefficient?: number;
124+
loadingGauge: 'G1' | 'G2' | 'GA' | 'GB' | 'GB1' | 'GC' | 'FR3.3' | 'FR3.3/GB/G2' | 'GLOTT';
125+
rollingResistanceA?: number;
126+
rollingResistanceB?: number;
127+
rollingResistanceC?: number;
128+
electricalPowerStartupTime: number | null;
129+
raisePantographTime: number | null;
130+
defaultMode: string | null;
131+
effortCurves: EffortCurves;
132+
basePowerClass: string | null;
133+
powerRestrictions: RollingStockBase['power_restrictions'];
134+
};
135+
96136
export type SchemaProperty = {
97137
title: string;
98138
type: string;

front/src/modules/rollingStock/helpers/utils.ts

+45-13
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { Comfort, RollingStock, RollingStockUpsertPayload } from 'common/api/osrdEditoastApi';
2-
import { isNull, some } from 'lodash';
2+
import { has, isNull, omitBy, some } from 'lodash';
33
import {
44
EffortCurves,
5+
RollingStockParametersValidValues,
56
RollingStockParametersValues,
67
STANDARD_COMFORT_LEVEL,
78
THERMAL_TRACTION_IDENTIFIER,
@@ -19,18 +20,7 @@ const newRollingStockValues = {
1920
subseries: '',
2021
type: '',
2122
unit: '',
22-
length: 0,
23-
mass: 0,
24-
maxSpeed: 0,
25-
startupTime: 0,
26-
startupAcceleration: 0,
27-
comfortAcceleration: 0.01,
28-
gammaValue: 0.01,
29-
inertiaCoefficient: 1,
3023
loadingGauge: 'G1' as RollingStockParametersValues['loadingGauge'],
31-
rollingResistanceA: 0,
32-
rollingResistanceB: 0,
33-
rollingResistanceC: 0,
3424
electricalPowerStartupTime: null,
3525
raisePantographTime: null,
3626
basePowerClass: null,
@@ -124,7 +114,7 @@ export const getRollingStockEditorDefaultValues = (
124114
};
125115

126116
export const rollingStockEditorQueryArg = (
127-
data: RollingStockParametersValues,
117+
data: RollingStockParametersValidValues,
128118
currentRsEffortCurve: RollingStock['effort_curves']
129119
): RollingStockUpsertPayload => ({
130120
name: data.name,
@@ -166,6 +156,48 @@ export const rollingStockEditorQueryArg = (
166156
base_power_class: data.basePowerClass || null,
167157
});
168158

159+
export const checkRollingStockFormValidity = (
160+
rollingStockForm: RollingStockParametersValues
161+
): { invalidFields: string[]; validRollingStockForm: RollingStockParametersValidValues } => {
162+
const invalidFields = [
163+
'length',
164+
'mass',
165+
'maxSpeed',
166+
'startupAcceleration',
167+
'comfortAcceleration',
168+
'startupTime',
169+
'gammaValue',
170+
'inertiaCoefficient',
171+
'rollingResistanceA',
172+
'rollingResistanceB',
173+
'rollingResistanceC',
174+
].reduce(
175+
(result, field) =>
176+
!has(rollingStockForm, field) || rollingStockForm[field] === undefined
177+
? [...result, field]
178+
: result,
179+
[] as string[]
180+
);
181+
182+
return {
183+
invalidFields,
184+
validRollingStockForm: {
185+
length: 0,
186+
maxSpeed: 0,
187+
startupAcceleration: 0,
188+
comfortAcceleration: 0.01,
189+
mass: 0,
190+
startupTime: 0,
191+
gammaValue: 0.01,
192+
inertiaCoefficient: 1,
193+
rollingResistanceA: 0,
194+
rollingResistanceB: 0,
195+
rollingResistanceC: 0,
196+
...omitBy(rollingStockForm, (value) => value === undefined),
197+
} as RollingStockParametersValidValues,
198+
};
199+
};
200+
169201
export const createEmptyCurve = (
170202
comfort: Comfort,
171203
electricalProfile: string | null = null,

front/src/styles/scss/applications/rollingStockEditor/_rollingStockForm.scss

+5
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@
6262
}
6363
}
6464

65+
.error-message {
66+
max-width: 100%;
67+
text-align: end;
68+
}
69+
6570
.rollingstock-card-body {
6671
height: 18rem;
6772
}

0 commit comments

Comments
 (0)