);
diff --git a/front/src/applications/stdcm/components/StdcmResults/SimulationReportSheet.tsx b/front/src/applications/stdcm/components/StdcmResults/SimulationReportSheet.tsx
index 0dc2c710117..29960461c02 100644
--- a/front/src/applications/stdcm/components/StdcmResults/SimulationReportSheet.tsx
+++ b/front/src/applications/stdcm/components/StdcmResults/SimulationReportSheet.tsx
@@ -2,11 +2,12 @@ import { useEffect, useState } from 'react';
import { Table, TR, TH, TD } from '@ag-media/react-pdf-table';
import { Page, Text, Image, Document, View, Link } from '@react-pdf/renderer';
+import type { TFunction } from 'i18next';
import { useTranslation } from 'react-i18next';
import iconAlert from 'assets/simulationReportSheet/icon_alert_fill.png';
import logoSNCF from 'assets/simulationReportSheet/logo_sncf_reseau.png';
-import type { PathStep } from 'reducers/osrdconf/types';
+import type { StdcmPathStep } from 'reducers/osrdconf/types';
import { extractHHMM, formatDateToString, formatDay } from 'utils/date';
import { msToKmh } from 'utils/physics';
import { capitalizeFirstLetter } from 'utils/strings';
@@ -15,6 +16,20 @@ import styles from './SimulationReportStyleSheet';
import type { SimulationReportSheetProps } from '../../types';
import { base64ToJpeg, getStopDurationTime } from '../../utils/formatSimulationReportSheet';
+const getSecondaryCode = ({ location }: StdcmPathStep) => {
+ if (location && ('uic' in location || 'trigram' in location)) {
+ return location.secondary_code;
+ }
+ return null;
+};
+
+const getStopType = (step: StdcmPathStep, t: TFunction) => {
+ if (!step.isVia) {
+ return t('serviceStop');
+ }
+ return capitalizeFirstLetter(t(`stdcm:trainPath.stopType.${step.stopType}`));
+};
+
const SimulationReportSheet = ({
stdcmLinkedPaths,
stdcmData,
@@ -65,11 +80,8 @@ const SimulationReportSheet = ({
[mapImageUrl]
);
- const getArrivalTime = (
- step: PathStep,
- { isFirstStep, isLastStep }: { isFirstStep?: boolean; isLastStep?: boolean }
- ) => {
- if (isFirstStep || isLastStep) {
+ const getArrivalTime = (step: StdcmPathStep) => {
+ if (!step.isVia) {
if (step.arrival && step.arrivalType === 'preciseTime') {
return extractHHMM(step.arrival);
}
@@ -191,8 +203,6 @@ const SimulationReportSheet = ({
{stdcmData.simulationPathSteps.map((step, index) => {
- const isFirstStep = index === 0;
- const isLastStep = index === stdcmData.simulationPathSteps.length - 1;
renderedIndex += 1;
return (
@@ -201,31 +211,27 @@ const SimulationReportSheet = ({
- {step.name || 'Unknown'}
+ {step.location?.name || 'Unknown'}
|
- {step.ch} |
+
+ {getSecondaryCode(step)}
+ |
- {getArrivalTime(step, { isLastStep })}
+ {getArrivalTime(step)}
|
- {getArrivalTime(step, { isFirstStep })}
+ {getArrivalTime(step)}
|
- {isFirstStep || isLastStep
- ? t('serviceStop')
- : capitalizeFirstLetter(
- t(
- `stdcm:trainPath.stopType.${stdcmData.simulationPathSteps[index].stopType}`
- )
- )}
+ {getStopType(step, t)}
|
@@ -305,7 +311,13 @@ const SimulationReportSheet = ({
const prevStep = operationalPointsList[index - 1];
const isViaInSimulationPath = stdcmData.simulationPathSteps
.slice(1, -1)
- .some((pathStep) => pathStep.name === step.name && pathStep.ch === step.ch);
+ .some(
+ ({ location }) =>
+ location &&
+ location.name === step.name &&
+ 'uic' in location &&
+ location.secondary_code === step.ch
+ );
const isViaWithoutStop = isViaInSimulationPath && step.duration === 0;
const isNotExtremity = !isFirstStep && !isLastStep;
const isStepWithDuration = step.duration !== 0 && !isLastStep;
diff --git a/front/src/applications/stdcm/components/StdcmResults/StdcmResults.tsx b/front/src/applications/stdcm/components/StdcmResults/StdcmResults.tsx
index 4a7962dbaf0..07612153176 100644
--- a/front/src/applications/stdcm/components/StdcmResults/StdcmResults.tsx
+++ b/front/src/applications/stdcm/components/StdcmResults/StdcmResults.tsx
@@ -6,6 +6,7 @@ import { useTranslation, Trans } from 'react-i18next';
import useConflictsMessages from 'applications/stdcm/hooks/useConflictsMessages';
import type { StdcmSimulation } from 'applications/stdcm/types';
+import { extractMarkersInfo } from 'applications/stdcm/utils';
import {
generateCodeNumber,
getOperationalPointsWithTimes,
@@ -67,9 +68,12 @@ const StcdmResults = ({
);
}, [outputs]);
- const simulationPathSteps = hasSimulationResults
- ? outputs.results.simulationPathSteps
- : undefined;
+ const simulationPathSteps = useMemo(() => {
+ if (!hasSimulationResults) {
+ return undefined;
+ }
+ return extractMarkersInfo(outputs.results.simulationPathSteps);
+ }, []);
return (
<>
diff --git a/front/src/applications/stdcm/components/StdcmResults/StdcmResultsTable.tsx b/front/src/applications/stdcm/components/StdcmResults/StdcmResultsTable.tsx
index 770c9ef5a10..236583f969a 100644
--- a/front/src/applications/stdcm/components/StdcmResults/StdcmResultsTable.tsx
+++ b/front/src/applications/stdcm/components/StdcmResults/StdcmResultsTable.tsx
@@ -52,7 +52,11 @@ const StcdmResultsTable = ({
const isLastStep = index === operationalPointsList.length - 1;
const prevStep = operationalPointsList[index - 1];
const isRequestedPathStep = stdcmData.simulationPathSteps.some(
- (pathStep) => pathStep.name === step.name && pathStep.ch === step.ch
+ ({ location }) =>
+ location &&
+ location.name === step.name &&
+ 'uic' in location &&
+ location.secondary_code === step.ch
);
const shouldRenderRow = isFirstStep || isRequestedPathStep || isLastStep;
const isPathStep =
diff --git a/front/src/applications/stdcm/hooks/useStaticPathfinding.ts b/front/src/applications/stdcm/hooks/useStaticPathfinding.ts
index f7b0cf91c8b..bdaa13e8ed7 100644
--- a/front/src/applications/stdcm/hooks/useStaticPathfinding.ts
+++ b/front/src/applications/stdcm/hooks/useStaticPathfinding.ts
@@ -26,10 +26,7 @@ const useStaticPathfinding = (infra?: InfraWithState) => {
osrdEditoastApi.endpoints.postInfraByInfraIdPathfindingBlocks.useMutation();
const pathStepsLocations = useMemo(
- () =>
- compact(
- pathSteps.map((step) => (step && (!('uic' in step) || step.uic !== -1) ? step : null))
- ),
+ () => compact(pathSteps.map((step) => step.location)),
[pathSteps]
);
diff --git a/front/src/applications/stdcm/hooks/useStdcm.ts b/front/src/applications/stdcm/hooks/useStdcm.ts
index fc06cd3492d..f4841167c50 100644
--- a/front/src/applications/stdcm/hooks/useStdcm.ts
+++ b/front/src/applications/stdcm/hooks/useStdcm.ts
@@ -119,7 +119,7 @@ const useStdcm = ({
rollingStock: stdcmRollingStock,
creationDate: new Date(),
speedLimitByTag,
- simulationPathSteps: osrdconf.pathSteps,
+ simulationPathSteps: osrdconf.stdcmPathSteps,
path: response.pathfinding_result,
} as StdcmConflictsResponse);
setStdcmTrainConflicts(response.conflicts); // Set conflicts
diff --git a/front/src/applications/stdcm/hooks/useStdcmForm.ts b/front/src/applications/stdcm/hooks/useStdcmForm.ts
index c9dad0963e1..92ea77c1774 100644
--- a/front/src/applications/stdcm/hooks/useStdcmForm.ts
+++ b/front/src/applications/stdcm/hooks/useStdcmForm.ts
@@ -6,9 +6,9 @@ import useStdcmTowedRollingStock from 'applications/stdcm/hooks/useStdcmTowedRol
import { useOsrdConfSelectors } from 'common/osrdContext';
import { useStoreDataForRollingStockSelector } from 'modules/rollingStock/components/RollingStockSelector/useStoreDataForRollingStockSelector';
import type { StdcmConfSelectors } from 'reducers/osrdconf/stdcmConf/selectors';
-import { extractDateAndTimefromISO } from 'utils/date';
import type { StdcmSimulationInputs } from '../types';
+import { getTimesInfoFromDate } from '../utils';
const useStdcmForm = (): StdcmSimulationInputs => {
const {
@@ -32,7 +32,7 @@ const useStdcmForm = (): StdcmSimulationInputs => {
const towedRollingStock = useStdcmTowedRollingStock();
const currentSimulationInputs = useMemo(() => {
- const originArrival = origin?.arrival ? extractDateAndTimefromISO(origin.arrival) : undefined;
+ const originArrival = getTimesInfoFromDate(origin.arrival);
return {
pathSteps,
diff --git a/front/src/applications/stdcm/types.ts b/front/src/applications/stdcm/types.ts
index 12ddb30cb7e..26665a58037 100644
--- a/front/src/applications/stdcm/types.ts
+++ b/front/src/applications/stdcm/types.ts
@@ -13,7 +13,7 @@ import type {
} from 'common/api/osrdEditoastApi';
import type { SpeedSpaceChartData } from 'modules/simulationResult/types';
import type { SuggestedOP } from 'modules/trainschedule/components/ManageTrainSchedule/types';
-import type { PathStep } from 'reducers/osrdconf/types';
+import type { StdcmPathStep } from 'reducers/osrdconf/types';
import type { ValueOf } from 'utils/types';
export type StdcmRequestStatus = ValueOf
;
@@ -26,7 +26,7 @@ export type StdcmSuccessResponse = Omit<
rollingStock: LightRollingStock;
creationDate: Date;
speedLimitByTag?: string;
- simulationPathSteps: PathStep[];
+ simulationPathSteps: StdcmPathStep[];
};
export type StdcmConflictsResponse = Extract<
@@ -36,7 +36,7 @@ export type StdcmConflictsResponse = Extract<
rollingStock: LightRollingStock;
creationDate: Date;
speedLimitByTag?: string;
- simulationPathSteps: PathStep[];
+ simulationPathSteps: StdcmPathStep[];
path: PathfindingResultSuccess;
};
@@ -111,7 +111,7 @@ export type AllowanceValue =
export type StdcmSimulationInputs = {
departureDate?: string;
departureTime?: string;
- pathSteps: (PathStep | null)[];
+ pathSteps: StdcmPathStep[];
consist?: {
tractionEngine?: RollingStockWithLiveries;
towedRollingStock?: TowedRollingStock;
diff --git a/front/src/applications/stdcm/utils/checkStdcmConfigErrors.ts b/front/src/applications/stdcm/utils/checkStdcmConfigErrors.ts
index a737f808ac6..d12d4de3c72 100644
--- a/front/src/applications/stdcm/utils/checkStdcmConfigErrors.ts
+++ b/front/src/applications/stdcm/utils/checkStdcmConfigErrors.ts
@@ -1,15 +1,14 @@
import type { TFunction } from 'i18next';
-import type { PathStep } from 'reducers/osrdconf/types';
+import type { StdcmPathStep } from 'reducers/osrdconf/types';
import { extractHHMM } from 'utils/date';
import { StdcmConfigErrorTypes, ArrivalTimeTypes, type StdcmConfigErrors } from '../types';
const checkStdcmConfigErrors = (
pathfindingStateError: boolean,
- origin: PathStep | null,
- destination: PathStep | null,
- pathSteps: (PathStep | null)[],
+ origin: Extract,
+ destination: Extract,
t: TFunction
): StdcmConfigErrors | undefined => {
const isOneOpPointMissing = !origin || !destination;
@@ -17,10 +16,6 @@ const checkStdcmConfigErrors = (
return undefined;
}
- if (pathSteps.some((step) => step === null || ('uic' in step && step.uic === -1))) {
- return { errorType: StdcmConfigErrorTypes.MISSING_LOCATION };
- }
-
if (pathfindingStateError) {
return { errorType: StdcmConfigErrorTypes.PATHFINDING_FAILED };
}
diff --git a/front/src/applications/stdcm/utils/formatStdcmConf.ts b/front/src/applications/stdcm/utils/formatStdcmConf.ts
index 4fbf6503fb3..267097283e9 100644
--- a/front/src/applications/stdcm/utils/formatStdcmConf.ts
+++ b/front/src/applications/stdcm/utils/formatStdcmConf.ts
@@ -13,9 +13,10 @@ import { setFailure } from 'reducers/main';
import type { OsrdStdcmConfState, StandardAllowance } from 'reducers/osrdconf/types';
import { dateTimeFormatting } from 'utils/date';
import { kmhToMs, tToKg } from 'utils/physics';
-import { ISO8601Duration2sec, sec2ms } from 'utils/timeManipulation';
+import { sec2ms } from 'utils/timeManipulation';
import createMargin from './createMargin';
+import { StdcmStopTypes } from '../types';
type ValidStdcmConfig = {
rollingStockId: number;
@@ -59,7 +60,17 @@ export const checkStdcmConf = (
maxSpeed,
} = osrdconf;
let error = false;
- if (pathSteps[0] === null) {
+
+ const origin = pathSteps.at(0)!;
+ if (origin.isVia) {
+ throw new Error('First step should not be a via');
+ }
+ const destination = pathSteps.at(-1)!;
+ if (destination.isVia) {
+ throw new Error('First step should not be a via');
+ }
+
+ if (!origin.location) {
error = true;
dispatch(
setFailure({
@@ -68,7 +79,7 @@ export const checkStdcmConf = (
})
);
}
- if (pathSteps[pathSteps.length - 1] === null) {
+ if (!destination.location) {
error = true;
dispatch(
setFailure({
@@ -105,12 +116,9 @@ export const checkStdcmConf = (
);
}
- const origin = pathSteps.at(0);
- const destination = pathSteps.at(-1);
-
- const originArrival = origin?.arrival;
- const destinationArrival = destination?.arrival;
- const isDepartureScheduled = origin?.arrivalType === 'preciseTime';
+ const originArrival = origin.arrival;
+ const destinationArrival = destination.arrival;
+ const isDepartureScheduled = origin.arrivalType === 'preciseTime';
const startDateTime = isDepartureScheduled
? new Date(originArrival!)
@@ -136,18 +144,29 @@ export const checkStdcmConf = (
if (error) return null;
const path = compact(osrdconf.stdcmPathSteps).map((step) => {
- const { arrival, tolerances, stopFor, arrivalType } = step;
- const location = getStepLocation(step);
-
- const duration = stopFor ? sec2ms(ISO8601Duration2sec(stopFor) || Number(stopFor)) : 0;
- const timingData =
- arrivalType === 'preciseTime' && arrival
- ? {
- arrival_time: arrival,
- arrival_time_tolerance_before: sec2ms(tolerances?.before ?? 0),
- arrival_time_tolerance_after: sec2ms(tolerances?.after ?? 0),
- }
- : undefined;
+ const location = getStepLocation(step.location!);
+
+ let timingData: PathfindingItem['timing_data'] | undefined;
+ let duration: number | undefined;
+ if (step.isVia) {
+ const { stopFor } = step;
+ if (step.stopType !== StdcmStopTypes.PASSAGE_TIME) {
+ duration = stopFor;
+ }
+ } else {
+ const { arrival, tolerances, arrivalType } = step;
+ if (arrivalType === 'preciseTime' && arrival) {
+ // if the step is either the origin or the destination and is scheduled,
+ // it must have a duration (because it's a stop)
+ timingData = {
+ arrival_time: arrival.toISOString(),
+ arrival_time_tolerance_before: sec2ms(tolerances?.before ?? 0),
+ arrival_time_tolerance_after: sec2ms(tolerances?.after ?? 0),
+ };
+ }
+ duration = 0;
+ }
+
return {
duration,
location,
diff --git a/front/src/applications/stdcm/utils/index.ts b/front/src/applications/stdcm/utils/index.ts
new file mode 100644
index 00000000000..a7acd385e6e
--- /dev/null
+++ b/front/src/applications/stdcm/utils/index.ts
@@ -0,0 +1,24 @@
+import type { MarkerInformation } from 'modules/trainschedule/components/ManageTrainSchedule/ManageTrainScheduleMap/ItineraryMarkers';
+import type { StdcmPathStep } from 'reducers/osrdconf/types';
+import { extractHHMM, extractDDMMYYYY } from 'utils/date';
+
+export const getTimesInfoFromDate = (date?: Date) =>
+ date
+ ? {
+ arrivalDate: extractDDMMYYYY(date), // ISO date part
+ arrivalTime: extractHHMM(date),
+ arrivalTimehours: date.getHours(),
+ arrivalTimeMinutes: date.getMinutes(),
+ }
+ : undefined;
+
+export const extractMarkersInfo = (pathSteps: StdcmPathStep[]) =>
+ pathSteps.reduce((acc, step) => {
+ if (step.location) {
+ acc.push({
+ coordinates: step.location.coordinates,
+ name: step.location.name,
+ });
+ }
+ return acc;
+ }, [] as MarkerInformation[]);
diff --git a/front/src/applications/stdcm/views/StdcmView.tsx b/front/src/applications/stdcm/views/StdcmView.tsx
index 041b4e1a568..882882235e1 100644
--- a/front/src/applications/stdcm/views/StdcmView.tsx
+++ b/front/src/applications/stdcm/views/StdcmView.tsx
@@ -80,7 +80,7 @@ const StdcmView = () => {
totalMass: consist?.totalMass,
maxSpeed: consist?.maxSpeed,
speedLimitByTag: consist?.speedLimitByTag,
- pathSteps: [...pathSteps],
+ stdcmPathSteps: [...pathSteps],
})
);
}
diff --git a/front/src/modules/pathfinding/helpers/getStepLocation.ts b/front/src/modules/pathfinding/helpers/getStepLocation.ts
index 0bae3255ebf..7bad5601a8b 100644
--- a/front/src/modules/pathfinding/helpers/getStepLocation.ts
+++ b/front/src/modules/pathfinding/helpers/getStepLocation.ts
@@ -1,8 +1,7 @@
import type { PathItemLocation } from 'common/api/osrdEditoastApi';
-import type { PathStep, StdcmPathStep } from 'reducers/osrdconf/types';
import { mToMm } from 'utils/physics';
-const getStepLocation = (step: PathStep | StdcmPathStep): PathItemLocation => {
+const getStepLocation = (step: T): PathItemLocation => {
if ('track' in step) {
// TODO: step offset should be in mm in the store /!\
// pathfinding blocks endpoint requires offsets in mm
@@ -12,12 +11,9 @@ const getStepLocation = (step: PathStep | StdcmPathStep): PathItemLocation => {
return { operational_point: step.operational_point };
}
if ('trigram' in step) {
- return { trigram: step.trigram, secondary_code: step.ch };
+ return { trigram: step.trigram, secondary_code: step.secondary_code };
}
- if (step.uic === -1) {
- throw new Error('Invalid UIC');
- }
- return { uic: step.uic, secondary_code: step.ch };
+ return { uic: step.uic, secondary_code: step.secondary_code };
};
export default getStepLocation;
diff --git a/front/src/modules/pathfinding/hooks/usePathfinding.ts b/front/src/modules/pathfinding/hooks/usePathfinding.ts
index 0d71aa17118..5f3718adff7 100644
--- a/front/src/modules/pathfinding/hooks/usePathfinding.ts
+++ b/front/src/modules/pathfinding/hooks/usePathfinding.ts
@@ -324,6 +324,7 @@ export const usePathfinding = (
name: correspondingOp.name,
uic: correspondingOp.uic,
ch: correspondingOp.ch,
+ secondary_code: correspondingOp.ch,
kp: correspondingOp.kp,
coordinates: correspondingOp.coordinates,
}),
diff --git a/front/src/modules/pathfinding/utils.ts b/front/src/modules/pathfinding/utils.ts
index 83d0f530483..07f1fb33d44 100644
--- a/front/src/modules/pathfinding/utils.ts
+++ b/front/src/modules/pathfinding/utils.ts
@@ -2,6 +2,7 @@ import { compact } from 'lodash';
import type {
GeoJsonLineString,
+ PathItemLocation,
PathProperties,
PathfindingInput,
PostInfraByInfraIdPathfindingBlocksApiArg,
@@ -52,7 +53,7 @@ export const matchPathStepAndOp = (
return step.track === op.track && step.offset === op.offsetOnTrack;
};
-export const getPathfindingQuery = ({
+export const getPathfindingQuery = ({
infraId,
rollingStock,
origin,
@@ -61,9 +62,9 @@ export const getPathfindingQuery = ({
}: {
infraId?: number;
rollingStock?: RollingStockWithLiveries;
- origin: PathStep | null;
- destination: PathStep | null;
- pathSteps: (PathStep | null)[];
+ origin: T | null;
+ destination: T | null;
+ pathSteps: (T | null)[];
}): PostInfraByInfraIdPathfindingBlocksApiArg | null => {
if (infraId && rollingStock && origin && destination) {
// Only origin and destination can be null so we can compact and we want to remove any via that would be null
diff --git a/front/src/reducers/index.ts b/front/src/reducers/index.ts
index 691fa0f9412..b44a8a8aeb7 100644
--- a/front/src/reducers/index.ts
+++ b/front/src/reducers/index.ts
@@ -1,6 +1,6 @@
import type { Action, Reducer, ReducersMapObject, AnyAction } from 'redux';
import type { PersistConfig } from 'redux-persist';
-import { persistCombineReducers, persistReducer } from 'redux-persist';
+import { createTransform, persistCombineReducers, persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage'; // defaults to localStorage
import createCompressor from 'redux-persist-transform-compress';
import { createFilter } from 'redux-persist-transform-filter';
@@ -22,7 +22,7 @@ import stdcmConfReducer, {
stdcmConfInitialState,
stdcmConfSlice,
} from 'reducers/osrdconf/stdcmConf';
-import type { OsrdConfState, OsrdStdcmConfState } from 'reducers/osrdconf/types';
+import type { OsrdConfState, OsrdStdcmConfState, StdcmPathStep } from 'reducers/osrdconf/types';
import simulationReducer, {
simulationResultsInitialState,
simulationResultsSlice,
@@ -30,6 +30,7 @@ import simulationReducer, {
import type { SimulationResultsState } from 'reducers/simulationResults/types';
import userReducer, { userInitialState, userSlice } from 'reducers/user';
import type { UserState } from 'reducers/user';
+import { isISOString } from 'utils/date';
import { type ConfSlice, defaultCommonConf } from './osrdconf/osrdConfCommon';
@@ -57,12 +58,26 @@ const saveUserFilter = createFilter('user', userWhiteList);
const saveMainFilter = createFilter('main', mainWhiteList);
+const dateTransform = createTransform(
+ null,
+ (outboundState: StdcmPathStep[]) =>
+ outboundState.map((step) => {
+ if (!step.isVia && step.arrival && isISOString(step.arrival as unknown as string)) {
+ return { ...step, arrival: new Date(step.arrival) };
+ }
+
+ return step;
+ }),
+ { whitelist: ['stdcmPathSteps'] }
+);
+
// Useful to only blacklist a sub-propertie of osrdconf
const buildOsrdConfPersistConfig = (
slice: ConfSlice
): PersistConfig => ({
key: slice.name,
storage,
+ transforms: [dateTransform],
blacklist: ['featureInfoClick'],
});
diff --git a/front/src/reducers/osrdconf/stdcmConf/index.ts b/front/src/reducers/osrdconf/stdcmConf/index.ts
index 6262f01f493..50a262f9fef 100644
--- a/front/src/reducers/osrdconf/stdcmConf/index.ts
+++ b/front/src/reducers/osrdconf/stdcmConf/index.ts
@@ -14,10 +14,9 @@ import { addElementAtIndex } from 'utils/array';
import type { ArrayElement } from 'utils/types';
export const stdcmConfInitialState: OsrdStdcmConfState = {
- // TODO: remove all the default uic values
stdcmPathSteps: [
- { id: nextId(), uic: -1, isVia: false, arrivalType: ArrivalTimeTypes.PRECISE_TIME },
- { id: nextId(), uic: -1, isVia: false, arrivalType: ArrivalTimeTypes.ASAP },
+ { id: nextId(), isVia: false, arrivalType: ArrivalTimeTypes.PRECISE_TIME },
+ { id: nextId(), isVia: false, arrivalType: ArrivalTimeTypes.ASAP },
],
standardStdcmAllowance: undefined,
totalMass: undefined,
@@ -76,7 +75,7 @@ export const stdcmConfSlice = createSlice({
OsrdStdcmConfState,
| 'rollingStockID'
| 'towedRollingStockID'
- | 'pathSteps'
+ | 'stdcmPathSteps'
| 'speedLimitByTag'
| 'totalLength'
| 'totalMass'
@@ -89,7 +88,7 @@ export const stdcmConfSlice = createSlice({
state.totalLength = action.payload.totalLength;
state.totalMass = action.payload.totalMass;
state.maxSpeed = action.payload.maxSpeed;
- state.pathSteps = action.payload.pathSteps;
+ state.stdcmPathSteps = action.payload.stdcmPathSteps;
state.speedLimitByTag = action.payload.speedLimitByTag;
},
updateStdcmStandardAllowance(
@@ -143,7 +142,6 @@ export const stdcmConfSlice = createSlice({
// Index takes count of the origin in the array
state.stdcmPathSteps = addElementAtIndex(state.stdcmPathSteps, action.payload, {
id: nextId(),
- uic: -1,
stopType: StdcmStopTypes.PASSAGE_TIME,
isVia: true,
});
diff --git a/front/src/reducers/osrdconf/stdcmConf/stdcmConfReducers.spec.ts b/front/src/reducers/osrdconf/stdcmConf/stdcmConfReducers.spec.ts
index 74c14e3efb7..e37aef83960 100644
--- a/front/src/reducers/osrdconf/stdcmConf/stdcmConfReducers.spec.ts
+++ b/front/src/reducers/osrdconf/stdcmConf/stdcmConfReducers.spec.ts
@@ -1,6 +1,8 @@
+import nextId from 'react-id-generator';
import { describe, it, expect } from 'vitest';
import { ArrivalTimeTypes, StdcmStopTypes } from 'applications/stdcm/types';
+import getStepLocation from 'modules/pathfinding/helpers/getStepLocation';
import {
stdcmConfInitialState,
stdcmConfSlice,
@@ -39,7 +41,7 @@ const testDataBuilder = {
};
const pathSteps = testDataBuilder.buildPathSteps();
-const [brest, rennes, lemans, paris] = pathSteps;
+const [_brest, rennes, _lemans, paris] = pathSteps;
const stdcmPathSteps = pathSteps.map(
(step, index) =>
({
@@ -58,7 +60,6 @@ const stdcmPathSteps = pathSteps.map(
const initialStateSTDCMConfig = {
rollingStockID: 10,
- pathSteps: [paris, lemans, rennes, brest],
speedLimitByTag: 'init-tag',
stdcmPathSteps,
};
@@ -98,10 +99,30 @@ describe('stdcmConfReducers', () => {
it('should handle updateStdcmConfigWithData', () => {
const store = createStore(initialStateSTDCMConfig);
+ const parisStdcm = {
+ id: nextId(),
+ isVia: false,
+ arrivalType: ArrivalTimeTypes.PRECISE_TIME,
+ location: {
+ ...getStepLocation(paris),
+ coordinates: paris.coordinates as [number, number],
+ name: paris.id,
+ },
+ } as StdcmPathStep;
+ const rennesStdcm = {
+ id: nextId(),
+ isVia: false,
+ arrivalType: ArrivalTimeTypes.ASAP,
+ location: {
+ ...getStepLocation(rennes),
+ coordinates: rennes.coordinates as [number, number],
+ name: rennes.id,
+ },
+ } as StdcmPathStep;
store.dispatch(
stdcmConfSliceActions.updateStdcmConfigWithData({
rollingStockID: 20,
- pathSteps: [paris, rennes],
+ stdcmPathSteps: [parisStdcm, rennesStdcm],
speedLimitByTag: 'new-tag',
})
);
@@ -145,7 +166,7 @@ describe('stdcmConfReducers', () => {
expect(origin.isVia).toBe(false);
const updates = {
arrivalType: ArrivalTimeTypes.ASAP,
- arrival: '2024-08-12T15:45:00.000+02:00',
+ arrival: new Date('2024-08-12T15:45:00.000+02:00'),
tolerances: {
before: 60,
after: 60,
@@ -162,7 +183,7 @@ describe('stdcmConfReducers', () => {
expect(via.isVia).toBe(true);
const updates = {
stopType: StdcmStopTypes.DRIVER_SWITCH,
- stopFor: 'PT60',
+ stopFor: 1,
};
store.dispatch(stdcmConfSliceActions.updateStdcmPathStep({ id: via.id, updates }));
@@ -175,7 +196,7 @@ describe('stdcmConfReducers', () => {
expect(destination.isVia).toBe(false);
const updates = {
arrivalType: ArrivalTimeTypes.ASAP,
- arrival: '2024-08-12T15:45:00.000+02:00',
+ arrival: new Date('2024-08-12T15:45:00.000+02:00'),
tolerances: {
before: 60,
after: 60,
diff --git a/front/src/reducers/osrdconf/types.ts b/front/src/reducers/osrdconf/types.ts
index d26fb8c1db7..27c73f585b3 100644
--- a/front/src/reducers/osrdconf/types.ts
+++ b/front/src/reducers/osrdconf/types.ts
@@ -91,6 +91,25 @@ export type PathStep = PathItemLocation & {
isInvalid?: boolean;
};
-export type StdcmPathStep = PathStep & {
- tolerances?: { before: number; after: number };
-} & ({ isVia: true; stopType: StdcmStopTypes } | { isVia: false; arrivalType: ArrivalTimeTypes });
+export type UicPathItemLocation = {
+ uic: number;
+ secondary_code?: string | null;
+ name: string;
+ coordinates: [number, number];
+};
+
+export type StdcmPathStep = {
+ id: string;
+ location?: PathItemLocation & {
+ name: string;
+ coordinates: [number, number];
+ };
+} & (
+ | { isVia: true; stopType: StdcmStopTypes; stopFor?: number }
+ | {
+ isVia: false;
+ arrivalType: ArrivalTimeTypes;
+ arrival?: Date;
+ tolerances?: { before: number; after: number };
+ }
+);
diff --git a/front/src/utils/__tests__/date.spec.ts b/front/src/utils/__tests__/date.spec.ts
index 57140f5b962..64a5b4b96d9 100644
--- a/front/src/utils/__tests__/date.spec.ts
+++ b/front/src/utils/__tests__/date.spec.ts
@@ -8,8 +8,6 @@ import {
parseDateTime,
extractDateAndTimefromISO,
isArrivalDateInSearchTimeWindow,
- formatLocaleDateToIsoDate,
- generateISODateFromDateTime,
} from 'utils/date';
describe('dateTimeToIso', () => {
@@ -138,18 +136,3 @@ describe('isArrivalDateInSearchTimeWindow', () => {
expect(result).toBe(false);
});
});
-
-describe('generateISODateFromDateTime', () => {
- it('should correctly set hours and minutes and return ISO string', () => {
- const schedule = {
- date: new Date('2024-08-01T00:00:00Z'),
- hours: 10,
- minutes: 30,
- };
- const expectedISODate = formatLocaleDateToIsoDate(new Date('2024-08-01T10:30:00Z'));
-
- const result = generateISODateFromDateTime(schedule);
-
- expect(result).toBe(expectedISODate);
- });
-});
diff --git a/front/src/utils/date.ts b/front/src/utils/date.ts
index 4aee17c966d..e06e45eda92 100644
--- a/front/src/utils/date.ts
+++ b/front/src/utils/date.ts
@@ -4,7 +4,6 @@ import customParseFormat from 'dayjs/plugin/customParseFormat';
import timezone from 'dayjs/plugin/timezone';
import utc from 'dayjs/plugin/utc';
-import type { ScheduleConstraint } from 'applications/stdcm/types';
import type { IsoDateTimeString, IsoDurationString } from 'common/types';
import i18n from 'i18n';
@@ -27,15 +26,16 @@ function extractHHMMSS(dateTimeString?: string) {
return dateTimeString.substring(11, 19);
}
-/**
- * @param dateTimeString date string in ISO format
- * @returns string "HH:MM"
- */
-export function extractHHMM(dateTimeString?: string) {
- if (!dateTimeString) {
+/** given a Date, returns its time "HH:MM" */
+export function extractHHMM(date?: Date) {
+ if (!date) {
return '';
}
- return dateTimeString.substring(11, 16);
+ return dayjs(date).format('HH:mm');
+}
+
+export function extractDDMMYYYY(date: Date) {
+ return dayjs(date).format('DD/MM/YYYY');
}
export function timestampToHHMMSS(timestamp: number) {
@@ -233,17 +233,6 @@ export function isArrivalDateInSearchTimeWindow(
return arrivalDate >= searchDatetimeWindow.begin && arrivalDate <= searchDatetimeWindow.end;
}
-/**
- * Generates an ISO date string from a given date and time.
- * @param {ScheduleConstraint} - An object containing the base date, the hours, and the minutes.
- * @returns {string} The ISO formatted date string.
- */
-export const generateISODateFromDateTime = ({ date, hours, minutes }: ScheduleConstraint) => {
- date.setHours(hours);
- date.setMinutes(minutes);
- return formatLocaleDateToIsoDate(date);
-};
-
/** Format a date to a string 'DD/MM/YY', for instance '01/01/24' */
export const formatDateString = (date?: Date | null) => {
if (!date) return '';
@@ -254,3 +243,9 @@ export const formatLocaleDate = (date: Date) => date.toLocaleString().substring(
export const isEqualDate = (searchDate: Date, startDate: Date) =>
formatLocaleDate(searchDate) === formatLocaleDate(startDate);
+
+/** Check if a string is a valid ISO string and can be converted into a date */
+export const isISOString = (val: string) => {
+ const d = new Date(val);
+ return !Number.isNaN(d.valueOf()) && d.toISOString() === val;
+};