Skip to content

Commit

Permalink
front: add pathfinding request in stdcm
Browse files Browse the repository at this point in the history
  • Loading branch information
SarahBellaha committed Jun 26, 2024
1 parent 8fc5362 commit 5c18d2a
Show file tree
Hide file tree
Showing 14 changed files with 357 additions and 185 deletions.
1 change: 1 addition & 0 deletions front/public/locales/en/stdcm.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
},
"loaderImageLegend": "The TGV Nord line",
"notificationTitle": "Phase 1: from D-7 to D-1 5pm, on the Perrigny-Miramas axis.",
"pathfindingFailed": "No paths have been found for these waypoints.",
"pleaseWait": "Please wait…",
"simulation":{
"averageRequestTime": "For your request, the time required is generally 90 seconds.",
Expand Down
1 change: 1 addition & 0 deletions front/public/locales/fr/stdcm.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
},
"loaderImageLegend": "La ligne TGV Nord",
"notificationTitle": "Phase 1 : de J-7 à J-1 17h, sur l’axe Perrigny—Miramas.",
"pathfindingFailed": "Aucun chemin n'a été trouvé pour ces points de jalonnement.",
"pleaseWait": "Veuillez patientez…",
"simulation":{
"averageRequestTime": "Pour votre demande, le temps nécessaire est généralement de 90 secondes.",
Expand Down
80 changes: 70 additions & 10 deletions front/src/applications/stdcmV2/components/StdcmConfig.tsx
Original file line number Diff line number Diff line change
@@ -1,47 +1,107 @@
import React, { useRef, useEffect } from 'react';

import { Button } from '@osrd-project/ui-core';
import cx from 'classnames';
import { useTranslation } from 'react-i18next';

import type { ManageTrainSchedulePathProperties } from 'applications/operationalStudies/types';
import STDCM_REQUEST_STATUS from 'applications/stdcm/consts';
import useStdcm from 'applications/stdcm/hooks/useStdcm';
import { useOsrdConfActions } from 'common/osrdContext';
import usePathfindingV2 from 'modules/pathfinding/hook/usePathfinding';
import { Map } from 'modules/trainschedule/components/ManageTrainSchedule';
import type { StdcmConfSliceActions } from 'reducers/osrdconf/stdcmConf';
import { useAppDispatch } from 'store';

import StdcmConsist from './StdcmConsist';
import StdcmDestination from './StdcmDestination';
import StdcmLoader from './StdcmLoader';
import StdcmOrigin from './StdcmOrigin';
import StdcmVias from './StdcmVias';
import type { StdcmSimulationResult } from '../views/StdcmViewV2';

const StdcmConfig = ({
currentSimulationInputs,
pathProperties,
setPathProperties,
setCurrentSimulationInputs,
}: {
currentSimulationInputs: StdcmSimulationResult['input'] | undefined;
pathProperties?: ManageTrainSchedulePathProperties;
setPathProperties: (pathProperties?: ManageTrainSchedulePathProperties) => void;
setCurrentSimulationInputs: React.Dispatch<
React.SetStateAction<StdcmSimulationResult['input'] | undefined>
>;
}) => {
const { t } = useTranslation('stdcm');
const loaderRef = useRef<HTMLDivElement>(null);

const StdcmConfig = () => {
const { launchStdcmRequest, cancelStdcmRequest, currentStdcmRequestStatus } = useStdcm();
const isPending = currentStdcmRequestStatus === STDCM_REQUEST_STATUS.pending;
const loaderRef = useRef<HTMLDivElement>(null);
const { t } = useTranslation('stdcm');

const dispatch = useAppDispatch();
const { updateGridMarginAfter, updateGridMarginBefore, updateStdcmStandardAllowance } =
useOsrdConfActions() as StdcmConfSliceActions;

const { pathfindingState } = usePathfindingV2({
pathProperties,
setPathProperties,
});

useEffect(() => {
if (isPending) {
loaderRef?.current?.scrollIntoView({ behavior: 'smooth' });
}
}, [isPending]);

useEffect(() => {
dispatch(updateGridMarginAfter(35));
dispatch(updateGridMarginBefore(35));
dispatch(updateStdcmStandardAllowance({ type: 'time_per_distance', value: 4.5 }));
}, []);

return (
<div className="stdcm-v2__body">
<div className="stdcm-v2-simulation-settings">
<div className="stdcm-v2-consist-container">
<StdcmConsist disabled={isPending} />
<StdcmConsist
disabled={isPending}
setCurrentSimulationInputs={setCurrentSimulationInputs}
/>
</div>
<div className="stdcm-v2__separator" />
<div className="stdcm-v2-simulation-itinerary">
{/* //TODO: rename StdcmDefaultCard */}
{/* <StdcmDefaultCard text="Indiquer le sillon antérieur" Icon={<ArrowUp size="lg" />} /> */}
<StdcmOrigin disabled={isPending} />
{/* <StdcmDefaultCard text="Ajouter un passage" Icon={<Location size="lg" />} /> */}
<StdcmVias disabled={isPending} />
<StdcmDestination disabled={isPending} />
<StdcmOrigin
disabled={isPending}
setCurrentSimulationInputs={setCurrentSimulationInputs}
/>
<StdcmVias disabled={isPending} setCurrentSimulationInputs={setCurrentSimulationInputs} />
<StdcmDestination
disabled={isPending}
setCurrentSimulationInputs={setCurrentSimulationInputs}
/>
{/* <StdcmDefaultCard text="Indiquer le sillon postérieur" Icon={<ArrowDown size="lg" />} /> */}
<div className="stdcm-v2-launch-request">
<Button label={t('simulation.getSimulation')} onClick={() => launchStdcmRequest()} />
{/* //TODO: replace wizz-on-hover effect once we have the definitive one */}
<div
className={cx('stdcm-v2-launch-request', {
'wizz-on-hover': !pathfindingState.done,
'pb-5': !pathfindingState.error,
})}
>
{currentSimulationInputs && (
<Button
label={t('simulation.getSimulation')}
onClick={() => {
if (pathfindingState.done) {
launchStdcmRequest();
setCurrentSimulationInputs(undefined);
}
}}
/>
)}
{pathfindingState.error && <p className="mt-2 mb-3">{t('pathfindingFailed')}</p>}
</div>
{isPending && <StdcmLoader cancelStdcmRequest={cancelStdcmRequest} ref={loaderRef} />}
</div>
Expand Down
17 changes: 16 additions & 1 deletion front/src/applications/stdcmV2/components/StdcmConsist.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { useAppDispatch } from 'store';

import StdcmCard from './StdcmCard';
import StdcmSuggestions from './StdcmSuggestions';
import type { StdcmSimulationResult } from '../views/StdcmViewV2';

interface StdcmSuggestionsConsistOption
extends SelectOptionObject,
Expand All @@ -37,7 +38,15 @@ const ConsistCardTitle = ({
);
};

const StdcmConsist = ({ disabled = false }: { disabled?: boolean }) => {
const StdcmConsist = ({
setCurrentSimulationInputs,
disabled = false,
}: {
setCurrentSimulationInputs: React.Dispatch<
React.SetStateAction<StdcmSimulationResult['input'] | undefined>
>;
disabled?: boolean;
}) => {
const { t } = useTranslation('stdcm');
const { speedLimitByTag, speedLimitsByTags, dispatchUpdateSpeedLimitByTag } =
useStoreDataForSpeedLimitByTagSelector();
Expand Down Expand Up @@ -88,6 +97,12 @@ const StdcmConsist = ({ disabled = false }: { disabled?: boolean }) => {
} else {
searchMateriel('');
}
setCurrentSimulationInputs((prevState) => ({
...prevState,
consist: {
tractionEngine: rollingStock,
},
}));
}, [rollingStock]);

return (
Expand Down
15 changes: 14 additions & 1 deletion front/src/applications/stdcmV2/components/StdcmDestination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,17 @@ import { useAppDispatch } from 'store';

import StdcmCard from './StdcmCard';
import StdcmOperationalPoint from './StdcmOperationalPoint';
import type { StdcmSimulationResult } from '../views/StdcmViewV2';

const StdcmDestination = ({ disabled = false }: { disabled?: boolean }) => {
const StdcmDestination = ({
setCurrentSimulationInputs,
disabled = false,
}: {
setCurrentSimulationInputs: React.Dispatch<
React.SetStateAction<StdcmSimulationResult['input'] | undefined>
>;
disabled?: boolean;
}) => {
const { t } = useTranslation('stdcm');
const dispatch = useAppDispatch();
const { getDestinationV2 } = useOsrdConfSelectors();
Expand All @@ -21,6 +30,10 @@ const StdcmDestination = ({ disabled = false }: { disabled?: boolean }) => {

const updateDestinationV2Point = (pathStep: PathStep | null) => {
dispatch(updateDestinationV2(pathStep));
setCurrentSimulationInputs((prevState) => ({
...prevState,
destination: pathStep,
}));
};

return (
Expand Down
22 changes: 20 additions & 2 deletions front/src/applications/stdcmV2/components/StdcmOrigin.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { useEffect } from 'react';

import { useTranslation } from 'react-i18next';
import { MdPinDrop } from 'react-icons/md';
Expand All @@ -12,8 +12,17 @@ import { useAppDispatch } from 'store';

import StdcmCard from './StdcmCard';
import StdcmOperationalPoint from './StdcmOperationalPoint';
import type { StdcmSimulationResult } from '../views/StdcmViewV2';

const StdcmOrigin = ({ disabled = false }: { disabled?: boolean }) => {
const StdcmOrigin = ({
setCurrentSimulationInputs,
disabled = false,
}: {
setCurrentSimulationInputs: React.Dispatch<
React.SetStateAction<StdcmSimulationResult['input'] | undefined>
>;
disabled?: boolean;
}) => {
const { t } = useTranslation('stdcm');
const dispatch = useAppDispatch();
const { getOriginV2, getOriginDate, getOriginTime } = useOsrdConfSelectors();
Expand All @@ -27,6 +36,15 @@ const StdcmOrigin = ({ disabled = false }: { disabled?: boolean }) => {
dispatch(updateOriginV2(pathStep));
};

useEffect(() => {
setCurrentSimulationInputs((prevState) => ({
...prevState,
origin,
departureDate: originDate,
departureTime: originTime,
}));
}, [origin, originDate, originTime]);

return (
<StdcmCard
name={t('trainPath.origin')}
Expand Down
108 changes: 60 additions & 48 deletions front/src/applications/stdcmV2/components/StdcmVias.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useMemo } from 'react';
import React, { useEffect, useMemo } from 'react';

import { Input } from '@osrd-project/ui-core';
import { Location } from '@osrd-project/ui-icons';
Expand All @@ -15,18 +15,24 @@ import { ISO8601Duration2sec, formatDurationAsISO8601 } from 'utils/timeManipula

import StdcmCard from './StdcmCard';
import StdcmOperationalPoint from './StdcmOperationalPoint';
import type { StdcmSimulationResult } from '../views/StdcmViewV2';

const StdcmVias = ({ disabled = false }: { disabled?: boolean }) => {
const StdcmVias = ({
setCurrentSimulationInputs,
disabled = false,
}: {
setCurrentSimulationInputs: React.Dispatch<
React.SetStateAction<StdcmSimulationResult['input'] | undefined>
>;
disabled?: boolean;
}) => {
const { t } = useTranslation('stdcm');
const dispatch = useAppDispatch();
const { getPathSteps } = useOsrdConfSelectors();
const { updatePathSteps, updateViaStopTimeV2 } = useOsrdConfActions() as StdcmConfSliceActions;
const pathSteps = useSelector(getPathSteps);

const intermediatePoints = useMemo(
() => pathSteps.filter((_, index) => index !== 0 && index !== pathSteps.length - 1),
[pathSteps]
);
const intermediatePoints = useMemo(() => pathSteps.slice(1, -1), [pathSteps]);

const updatePathStepsList = (pathStep: PathStep | null, index: number) => {
const newPathSteps = replaceElementAtIndex(pathSteps, index, pathStep);
Expand All @@ -36,11 +42,10 @@ const StdcmVias = ({ disabled = false }: { disabled?: boolean }) => {
const updatePathStepStopTime = (stopTime: string, index: number) => {
const pathStepToUpdate = pathSteps[index];
if (!pathStepToUpdate) return;

dispatch(
updateViaStopTimeV2({
via: pathStepToUpdate,
duration: formatDurationAsISO8601(Number(stopTime || '0') * 60),
duration: formatDurationAsISO8601(Number(stopTime) * 60),
})
);
};
Expand All @@ -49,60 +54,67 @@ const StdcmVias = ({ disabled = false }: { disabled?: boolean }) => {
dispatch(updatePathSteps(pathSteps.filter((_, i) => i !== index)));
};

useEffect(() => {
setCurrentSimulationInputs((prevState) => ({
...prevState,
pathSteps,
}));
}, [pathSteps]);

return (
<div className="stdcm-v2-vias-list">
{intermediatePoints.length > 0 &&
intermediatePoints.map((pathStep, index) => (
<StdcmCard
key={index}
name={t('trainPath.vias')}
title={
<div>
<MdOutlineDirections color="darkgreen" />{' '}
<MdClear color="darkred" onClick={() => deletePathStep(index + 1)} />{' '}
</div>
} // TODO: Remove the clear button -> replace it by the "numbered point" icon
hasTip
disabled={disabled}
>
<div className="stdcm-v2-vias">
<StdcmOperationalPoint
updatePoint={(e) => updatePathStepsList(e, index + 1)}
point={pathStep}
disabled={disabled}
/>
{/* TODO: enable this select when the feature is implemented in the backend */}
{/* <div>
<select id="destination" name="destination" disabled>
<option value="asSoonAsPossible">{t('trainPath.asSoonAsPossible')}</option>
</select>
</div> */}
</div>
{pathStep && (
<div className="stdcm-v2-via-stop-for pl-2">
<Input
id="stdcm-v2-via-stop-time"
type="number"
label={t('trainPath.stopFor')}
onChange={(e) => updatePathStepStopTime(e.target.value, index + 1)}
value={pathStep.stopFor ? `${ISO8601Duration2sec(pathStep.stopFor) / 60}` : ''}
trailingContent="minutes"
intermediatePoints.map((pathStep, index) => {
const pathStepId = index + 1;
return (
<StdcmCard
key={pathStepId}
name={t('trainPath.vias')}
title={
<div>
<MdOutlineDirections color="darkgreen" />
<MdClear color="darkred" onClick={() => deletePathStep(pathStepId)} />
</div>
} // TODO: Remove icon and clear button -> replace them by the "numbered point" icon
hasTip
disabled={disabled}
>
<div className="stdcm-v2-vias">
<StdcmOperationalPoint
updatePoint={(e) => updatePathStepsList(e, pathStepId)}
point={pathStep}
disabled={disabled}
/>
</div>
)}
</StdcmCard>
))}
{pathStep && (
<div className="stdcm-v2-via-stop-for pl-2">
<Input
id="stdcm-v2-via-stop-time"
type="text"
label={t('trainPath.stopFor')}
onChange={(e) => {
const value = e.target.value.replace(/[\D.,]/g, '');
updatePathStepStopTime(value, pathStepId);
}}
value={pathStep.stopFor ? `${ISO8601Duration2sec(pathStep.stopFor) / 60}` : ''}
trailingContent="minutes"
/>
</div>
)}
</StdcmCard>
);
})}
<StdcmCard hasTip disabled={disabled}>
<button
type="button"
onClick={() => {
dispatch(updatePathSteps(addElementAtIndex(pathSteps, pathSteps.length - 1, null)));
}}
>
<span style={{ color: '#1844EF' }}>
<span className="stdcm-v2-via-icon">
<Location size="lg" variant="base" />
</span>
<span className="stdcm-v2-add-via__button pl-2">{t('trainPath.addVia')}</span>
<span className="stdcm-v2-add-via__button pl-3">{t('trainPath.addVia')}</span>
</button>
</StdcmCard>
</div>
Expand Down
Loading

0 comments on commit 5c18d2a

Please sign in to comment.