diff --git a/front/src/applications/stdcm/components/OldAllowances/Allowance.tsx b/front/src/applications/stdcm/components/OldAllowances/Allowance.tsx deleted file mode 100644 index c562cad417c..00000000000 --- a/front/src/applications/stdcm/components/OldAllowances/Allowance.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import React from 'react'; -import { TFunction } from 'react-i18next'; -import { identity, isNumber } from 'lodash'; - -import { FaTrash } from 'react-icons/fa'; - -import { Allowance, AllowanceValue, RangeAllowance } from 'common/api/osrdEditoastApi'; -import { Train } from 'reducers/osrdsimulation/types'; -import { TYPES_UNITS, ALLOWANCE_UNITS_KEYS } from './allowancesConsts'; - -function valueWithUnits(allowanceValue: AllowanceValue | undefined, t: TFunction) { - if (!allowanceValue) { - return ''; - } - const label = t(`allowanceTypes.${allowanceValue?.value_type}`); - const unitSymbol = ALLOWANCE_UNITS_KEYS[allowanceValue.value_type]; - let value; - // extremely dumb solution for now to comply with TS compiler. - // the symbol (s, %, or min/100km) should be - // added to the AllowanceValue, directly in the backend - if (allowanceValue.value_type === 'time') { - value = allowanceValue[TYPES_UNITS.time]; - } else if (allowanceValue.value_type === 'time_per_distance') { - value = allowanceValue[TYPES_UNITS.time_per_distance]; - } else if (allowanceValue.value_type === 'percentage') { - value = allowanceValue[TYPES_UNITS.percentage]; - } - return `${label} /${value}${unitSymbol}`; -} - -interface AllowanceProps { - data: T; - distribution?: 'MARECO' | 'LINEAR'; - allowanceType?: Allowance['allowance_type']; - delAllowance: (idx: number, allowanceType?: Allowance['allowance_type']) => void; - idx: number; - t: TFunction; - selectedTrain: Train; -} - -function Allowance({ - data: { begin_position, end_position, value } = {} as T, - distribution, - allowanceType, - delAllowance, - idx, - selectedTrain, - t = identity, -}: AllowanceProps) { - const position2name = (position?: number) => { - if (!isNumber(position) || !selectedTrain) { - return '-'; - } - const place = selectedTrain.base.stops.find((element) => element.position === position); - return place && place.name !== null - ? `${place.name} (${Math.round(position)}m)` - : `${position}m`; - }; - - return ( -
-
-
- {idx + 1} -
-
{position2name(begin_position)}
-
{position2name(end_position)}
-
- {t(`distributions.${distribution?.toLowerCase()}`)} -
-
{valueWithUnits(value, t)}
-
- -
-
-
- ); -} - -export default Allowance; diff --git a/front/src/applications/stdcm/components/OldAllowances/EmptyLine.tsx b/front/src/applications/stdcm/components/OldAllowances/EmptyLine.tsx deleted file mode 100644 index 40a4f2aa9d4..00000000000 --- a/front/src/applications/stdcm/components/OldAllowances/EmptyLine.tsx +++ /dev/null @@ -1,228 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import { useSelector } from 'react-redux'; -import { useTranslation } from 'react-i18next'; -import classNames from 'classnames'; - -import { Allowance, RangeAllowance, EngineeringAllowance } from 'common/api/osrdEditoastApi'; - -import InputGroupSNCF, { InputGroupSNCFValue } from 'common/BootstrapSNCF/InputGroupSNCF'; -import InputSNCF from 'common/BootstrapSNCF/InputSNCF'; -import ModalBodySNCF from 'common/BootstrapSNCF/ModalSNCF/ModalBodySNCF'; -import SelectSNCF from 'common/BootstrapSNCF/SelectSNCF'; -import { useModal } from 'common/BootstrapSNCF/ModalSNCF'; -import { getSelectedTrain } from 'reducers/osrdsimulation/selectors'; -import OPModal from './OPModal'; -import { AllowanceType, TYPES_UNITS } from './allowancesConsts'; - -function getAllowanceValue(values: RangeAllowance | EngineeringAllowance) { - const { value } = values; - if (value?.value_type === 'time_per_distance') { - return value.minutes || 0; - } - if (value?.value_type === 'time') { - return value.seconds || 0; - } - if (value?.value_type === 'percentage') { - return value.percentage || 0; - } - return 0; -} - -function getNewLine( - allowanceType: string, - defaultDistributionId: string | undefined, - marecoBeginPosition: number, - marecoEndPosition?: number -) { - const selectedTrain = useSelector(getSelectedTrain); - - if (selectedTrain) { - if (allowanceType === 'engineering') { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - return { - allowance_type: 'engineering', - distribution: defaultDistributionId, - begin_position: 0, - end_position: selectedTrain.base.stops[selectedTrain.base.stops.length - 1].position, - value: { - value_type: 'time', - seconds: 0, - }, - } as T; - } - return { - begin_position: marecoBeginPosition ?? 0, - end_position: - marecoEndPosition ?? selectedTrain.base.stops[selectedTrain.base.stops.length - 1].position, - value: { - value_type: 'time', - seconds: 0, - }, - } as T; - } - return {} as T; -} - -interface EmptyLineProps { - allowanceTypes: AllowanceType[]; - distributionsTypes: { - id: string; - label: string; - }[]; - handleChange: (allowance: T) => void; - allowanceType: Allowance['allowance_type']; - marecoBeginPosition?: number; - marecoEndPosition?: number; - defaultDistributionId?: Allowance['distribution']; -} - -function EmptyLine(props: EmptyLineProps) { - const { - allowanceTypes, - distributionsTypes, - handleChange, - allowanceType, - marecoBeginPosition = 0, - marecoEndPosition, - defaultDistributionId, - } = props; - const { openModal } = useModal(); - - const allowanceNewDatas = getNewLine( - allowanceType, - defaultDistributionId, - marecoBeginPosition, - marecoEndPosition - ); - const [values, setValues] = useState(allowanceNewDatas); - const [fromTo, setFromTo] = useState('from'); - const { t } = useTranslation(['allowances']); - - useEffect(() => { - setValues({ - ...values, - distribution: defaultDistributionId, - }); - }, [defaultDistributionId]); - - const handleType = (type: InputGroupSNCFValue) => { - if (type.type !== undefined) { - setValues({ - ...values, - value: { - value_type: type.type, - [TYPES_UNITS[type.type as keyof typeof TYPES_UNITS]]: - type.value === '' || type.value === undefined ? '' : +type.value, - }, - }); - } - }; - - return ( -
-
- {t('from')} - setValues({ ...values, begin_position: parseInt(e.target.value, 10) })} - value={values.begin_position} - placeholder={t('begin_position')} - unit="m" - isInvalid={Number(values.begin_position) >= Number(values.end_position)} - noMargin - sm - /> - -
-
- {t('to')} - setValues({ ...values, end_position: parseInt(e.target.value, 10) })} - value={values.end_position} - placeholder={t('end_position')} - unit="m" - isInvalid={Number(values.begin_position) >= Number(values.end_position)} - noMargin - sm - /> - -
-
- { - if (e) - setValues({ - ...values, - distribution: e.id, - }); - }} - /> -
-
- -
-
- -
-
- ); -} - -export default EmptyLine; diff --git a/front/src/applications/stdcm/components/OldAllowances/OPModal.jsx b/front/src/applications/stdcm/components/OldAllowances/OPModal.jsx deleted file mode 100644 index cf53a8526a1..00000000000 --- a/front/src/applications/stdcm/components/OldAllowances/OPModal.jsx +++ /dev/null @@ -1,44 +0,0 @@ -import { ModalContext } from 'common/BootstrapSNCF/ModalSNCF/ModalProvider'; -import PropTypes from 'prop-types'; -import React, { useContext } from 'react'; -import nextId from 'react-id-generator'; -import { useSelector } from 'react-redux'; -import { getSelectedTrain } from 'reducers/osrdsimulation/selectors'; - -export default function OPModal(props) { - const { values, setValues, fromTo } = props; - const selectedTrain = useSelector(getSelectedTrain); - const { closeModal } = useContext(ModalContext); - return ( - - - - - - - - - {selectedTrain.base.stops.map((stop) => ( - { - setValues({ ...values, [fromTo]: stop.position }); - closeModal(); - }} - > - - - - ))} - -
NomPosition
{stop.name}{Math.round(stop.position) / 1000}
- ); -} - -OPModal.propTypes = { - fromTo: PropTypes.string.isRequired, - setValues: PropTypes.func.isRequired, - values: PropTypes.object.isRequired, -}; diff --git a/front/src/applications/stdcm/components/OldAllowances/StandardAllowanceDefault.tsx b/front/src/applications/stdcm/components/OldAllowances/StandardAllowanceDefault.tsx deleted file mode 100644 index 8c50639e8ca..00000000000 --- a/front/src/applications/stdcm/components/OldAllowances/StandardAllowanceDefault.tsx +++ /dev/null @@ -1,207 +0,0 @@ -import React, { useEffect, useMemo, useState, useCallback, SetStateAction } from 'react'; -import debounce from 'lodash/debounce'; -import InputGroupSNCF, { InputGroupSNCFValue } from 'common/BootstrapSNCF/InputGroupSNCF'; -import SelectSNCF, { SelectOptionObject } from 'common/BootstrapSNCF/SelectSNCF'; -import InputSNCF from 'common/BootstrapSNCF/InputSNCF'; -import { StandardAllowance, TrainSchedule } from 'common/api/osrdEditoastApi'; -import { TYPES_UNITS, ALLOWANCE_UNITS_KEYS, AllowanceType } from './allowancesConsts'; - -interface StandardAllowanceDefaultProps { - distributionsTypes?: SelectOptionObject[]; - trainDetail?: TrainSchedule; - changeType?: (type: unknown, typekey: string) => void; - options?: { - immediateMutation?: boolean; - setDistribution?: boolean; - }; - title?: string; - t?: (key: string) => string; - typeKey?: string; - getBaseValue?: (typeKey: string) => { - type: 'percentage' | 'time' | 'time_per_distance'; - value: number; - }; - getAllowanceTypes?: (typeKey: string) => AllowanceType[]; - isCondensed?: boolean; -} - -const StandardAllowanceDefault = (props: StandardAllowanceDefaultProps) => { - const { - distributionsTypes, - trainDetail, - t, - options, - title, - changeType, - typeKey, - getBaseValue, - getAllowanceTypes, - isCondensed, - } = props; - - const [value, setValue] = useState<{ type: keyof typeof TYPES_UNITS; value: number }>({ - type: 'time', - value: 0, - }); - const [allowanceTypes, setAllowanceTypes] = useState([ - { - id: 'percentage', - label: t ? t('allowanceTypes.percentage') : '', - unit: ALLOWANCE_UNITS_KEYS.percentage, - }, - ]); - - let distributionType: SelectOptionObject = { id: '', label: '' }; - if (distributionsTypes) [distributionType] = distributionsTypes; - - const [distribution, setDistribution] = useState( - distributionType - ); - - const debouncedChangeType = useMemo( - () => - debounce( - (type) => { - if (changeType) changeType(type, typeKey as string); - }, - 500, - { - leading: false, - trailing: true, - } - ), - [typeKey, changeType] - ); - - const handleType = useCallback( - (newTypeValue: InputGroupSNCFValue) => { - if (newTypeValue.type !== undefined) { - const processedType = { - type: newTypeValue.type, - value: - newTypeValue.value === '' || newTypeValue.value === undefined - ? '' - : +newTypeValue.value, - }; - setValue( - processedType as SetStateAction<{ type: keyof typeof TYPES_UNITS; value: number }> - ); - debouncedChangeType(processedType); - } - }, - [debouncedChangeType] - ); - - useEffect(() => { - let thereIsStandard = false; - - trainDetail?.allowances?.forEach((allowance) => { - if (allowance.allowance_type === 'standard' && allowance.ranges) { - const currentDistribution = allowance.distribution; - if (allowance.default_value?.value_type) { - const findValue = (newAllowance: StandardAllowance): number | undefined => { - if (newAllowance.default_value?.value_type === 'time') { - return newAllowance.default_value.seconds; - } - if (newAllowance.default_value?.value_type === 'time_per_distance') { - return newAllowance.default_value.minutes; - } - if (newAllowance.default_value?.value_type === 'percentage') { - return newAllowance.default_value.percentage; - } - return undefined; - }; - setValue({ - type: allowance.default_value.value_type, - value: findValue(allowance) || 0, - }); - } - setDistribution(() => ({ - id: currentDistribution || '', - label: t ? t(`distributions.${currentDistribution?.toLowerCase()}`) : '', - })); - thereIsStandard = true; - } - }); - if (!thereIsStandard) { - setValue({ - type: 'time', - value: 0, - }); - } - }, [trainDetail, t]); - - useEffect(() => { - if (getBaseValue) setValue(getBaseValue(typeKey as string)); - }, [getBaseValue, typeKey]); - - useEffect(() => { - if (getAllowanceTypes) setAllowanceTypes(getAllowanceTypes(typeKey as string)); - }, [getAllowanceTypes, typeKey]); - - useEffect(() => { - if (allowanceTypes[0].label === 'time') - allowanceTypes[0].label = t ? t('allowanceTypes.time') : ''; - }, [allowanceTypes, t]); - - return ( -
- {!isCondensed && ( - - )} - -
-
- {options?.setDistribution && ( - <> -
{t ? t('perDefaultValue') : ''}
-
- setDistribution(e)} - value={distribution} - /> -
- - )} - {allowanceTypes.length > 1 ? ( - - ) : ( - - handleType({ - type: allowanceTypes[0].id, - value: e.target.value, - }) - } - value={value.value} - unit={allowanceTypes[0].unit} - type="text" - condensed={isCondensed} - sm - noMargin - /> - )} -
-
-
- ); -}; - -export default StandardAllowanceDefault; diff --git a/front/src/applications/stdcm/components/OldAllowances/withOSRDStdcmParams.tsx b/front/src/applications/stdcm/components/OldAllowances/withOSRDStdcmParams.tsx deleted file mode 100644 index 6d165766645..00000000000 --- a/front/src/applications/stdcm/components/OldAllowances/withOSRDStdcmParams.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import { noop } from 'lodash'; -import React, { ComponentType, useState } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; -import { useTranslation } from 'react-i18next'; -import { - updateGridMarginBefore, - updateGridMarginAfter, - updateStdcmStandardAllowance, -} from 'reducers/osrdconf'; -import { - getGridMarginBefore, - getGridMarginAfter, - getStandardStdcmAllowance, -} from 'reducers/osrdconf/selectors'; -import { StandardAllowance } from 'applications/operationalStudies/consts'; -import SingleAllowance from './StandardAllowanceDefault'; - -import { ALLOWANCE_UNITS_KEYS } from './allowancesConsts'; - -function withOSRDStdcmParams(Component: ComponentType) { - return (hocProps: T) => { - const { t } = useTranslation(['allowances']); - const dispatch = useDispatch(); - const gridMarginBefore = useSelector(getGridMarginBefore); - const gridMarginAfter = useSelector(getGridMarginAfter); - const stdcmStandardAllowance = useSelector(getStandardStdcmAllowance); - - const allowanceTypes = [ - { - id: 'time', - label: t('allowanceTypes.time'), - unit: ALLOWANCE_UNITS_KEYS.time, - }, - ]; - - const standardAllowanceTypes = [ - { - id: 'percentage', - label: t('allowanceTypes.percentage'), - unit: ALLOWANCE_UNITS_KEYS.percentage, - }, - { - id: 'time_per_distance', - label: t('allowanceTypes.time_per_distance'), - unit: ALLOWANCE_UNITS_KEYS.time_per_distance, - }, - ]; - - // Do not change the keys (id, label) without checking implications - const distributionsTypes = [ - { - id: 'LINEAR', - label: t('distributions.linear'), - }, - { - id: 'MARECO', - label: t('distributions.mareco'), - }, - ]; - - const [trainDetail] = useState({ allowances: [] }); - - const changeType = (type: StandardAllowance, typeKey: string) => { - if (typeKey === 'gridMarginBefore') { - dispatch(updateGridMarginBefore(type.value || 0)); - } else if (typeKey === 'gridMarginAfter') { - dispatch(updateGridMarginAfter(type.value || 0)); - } else if (typeKey === 'standardStdcmAllowance') { - dispatch(updateStdcmStandardAllowance(type)); - } - }; - - const getAllowanceTypes = (typeKey: string) => { - if (typeKey === 'standardStdcmAllowance') { - return standardAllowanceTypes; - } - return allowanceTypes; - }; - - const getBaseValue = (typeKey: string) => { - if (typeKey === 'gridMarginBefore') { - return { type: 'time', value: gridMarginBefore }; - } - if (typeKey === 'gridMarginAfter') { - return { type: 'time', value: gridMarginAfter }; - } - if (typeKey === 'standardStdcmAllowance') { - return stdcmStandardAllowance || { type: 'time', value: 0 }; - } - return { type: 'time', value: 0 }; - }; - - return ( - - ); - }; -} - -export default withOSRDStdcmParams(SingleAllowance); diff --git a/front/src/applications/stdcm/components/STDCMAllowances.tsx b/front/src/applications/stdcm/components/STDCMAllowances.tsx deleted file mode 100644 index 0f5b35835b3..00000000000 --- a/front/src/applications/stdcm/components/STDCMAllowances.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import React from 'react'; -import StdcmSingleAllowance from 'applications/stdcm/components/OldAllowances/withOSRDStdcmParams'; -import { useTranslation } from 'react-i18next'; - -const STDCMAllowances = () => { - const { t } = useTranslation('allowances'); - - return ( -
-
-
-
{t('allowances:gridMarginBeforeAfter')}
-
-
- -
-
- -
-
-
-
-
{t('allowances:standardAllowance')}
- -
-
-
- ); -}; - -export default STDCMAllowances; diff --git a/front/src/applications/stdcm/components/OldAllowances/allowancesConsts.tsx b/front/src/applications/stdcm/components/allowancesConsts.tsx similarity index 100% rename from front/src/applications/stdcm/components/OldAllowances/allowancesConsts.tsx rename to front/src/applications/stdcm/components/allowancesConsts.tsx diff --git a/front/src/applications/stdcm/formatStcmConf.ts b/front/src/applications/stdcm/formatStcmConf.ts index fe45f0b4390..caab0abe425 100644 --- a/front/src/applications/stdcm/formatStcmConf.ts +++ b/front/src/applications/stdcm/formatStcmConf.ts @@ -2,7 +2,7 @@ import { Dispatch } from 'redux'; import { TFunction } from 'i18next'; import { PathQuery, PostStdcmApiArg } from 'common/api/osrdEditoastApi'; -import { createAllowanceValue } from 'applications/stdcm/components/OldAllowances/allowancesConsts'; +import { createAllowanceValue } from 'applications/stdcm/components/allowancesConsts'; import { STDCM_MODES, OsrdStdcmConfState } from 'applications/operationalStudies/consts'; import { time2sec } from 'utils/timeManipulation'; import { makeEnumBooleans } from 'utils/constants'; diff --git a/front/src/applications/stdcm/views/OSRDCStdcmConfig.tsx b/front/src/applications/stdcm/views/OSRDCStdcmConfig.tsx index d0a3eae8f7b..889f60dc3dc 100644 --- a/front/src/applications/stdcm/views/OSRDCStdcmConfig.tsx +++ b/front/src/applications/stdcm/views/OSRDCStdcmConfig.tsx @@ -19,7 +19,7 @@ import { import { getSelectedTrain } from 'reducers/osrdsimulation/selectors'; import { RollingStockSelector } from 'modules/rollingStock/components/RollingStockSelector'; import { osrdEditoastApi } from 'common/api/osrdEditoastApi'; -import STDCMAllowances from '../components/STDCMAllowances'; +import STDCMAllowances from '../../../modules/allowances/components/STDCMAllowances'; import OSRDStdcmResults from './OSRDStdcmResults'; import RunningTime from '../components/RunningTime'; diff --git a/front/src/modules/allowances/components/STDCMAllowances.tsx b/front/src/modules/allowances/components/STDCMAllowances.tsx new file mode 100644 index 00000000000..c37735acc2a --- /dev/null +++ b/front/src/modules/allowances/components/STDCMAllowances.tsx @@ -0,0 +1,97 @@ +import React from 'react'; +import { useDispatch, useSelector } from 'react-redux'; + +import { useTranslation } from 'react-i18next'; + +import InputSNCF from 'common/BootstrapSNCF/InputSNCF'; +import InputGroupSNCF, { InputGroupSNCFValue } from 'common/BootstrapSNCF/InputGroupSNCF'; + +import { + getGridMarginBefore, + getGridMarginAfter, + getStandardStdcmAllowance, +} from 'reducers/osrdconf/selectors'; +import { + updateGridMarginAfter, + updateGridMarginBefore, + updateStdcmStandardAllowance, +} from 'reducers/osrdconf'; +import { StandardAllowance } from 'applications/operationalStudies/consts'; +import { AllowanceValue } from 'common/api/osrdEditoastApi'; +import { ALLOWANCE_UNITS_KEYS } from '../../../applications/stdcm/components/allowancesConsts'; + +const STDCMAllowances = () => { + const { t } = useTranslation('allowances'); + const dispatch = useDispatch(); + const gridMarginBefore = useSelector(getGridMarginBefore); + const gridMarginAfter = useSelector(getGridMarginAfter); + const stdcmStandardAllowance = useSelector(getStandardStdcmAllowance); + const standardAllowanceTypes = [ + { + id: 'percentage', + label: ALLOWANCE_UNITS_KEYS.percentage, + }, + { + id: 'time_per_distance', + label: ALLOWANCE_UNITS_KEYS.time_per_distance, + }, + ]; + + const onchangeType = (newTypeValue: InputGroupSNCFValue) => { + if (newTypeValue.type == null) return; + const processedType: StandardAllowance = { + type: newTypeValue.type as AllowanceValue['value_type'], + value: + newTypeValue.value === '' || newTypeValue.value === undefined ? 0 : +newTypeValue.value, + }; + + dispatch(updateStdcmStandardAllowance(processedType)); + }; + + return ( +
+
+ dispatch(updateGridMarginBefore(+e.target.value || 0))} + sm + noMargin + label={t('allowances:gridMarginBeforeAfter')} + /> +
+
+ dispatch(updateGridMarginAfter(+e.target.value || 0))} + sm + noMargin + label=" " + /> +
+
+ + +
+
+ ); +}; + +export default STDCMAllowances;