({
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/modules/trainschedule/components/ManageTrainSchedule/ManageTrainScheduleMap/ItineraryMarkers.tsx b/front/src/modules/trainschedule/components/ManageTrainSchedule/ManageTrainScheduleMap/ItineraryMarkers.tsx
index 82b21e0f8d8..192a540ca81 100644
--- a/front/src/modules/trainschedule/components/ManageTrainSchedule/ManageTrainScheduleMap/ItineraryMarkers.tsx
+++ b/front/src/modules/trainschedule/components/ManageTrainSchedule/ManageTrainScheduleMap/ItineraryMarkers.tsx
@@ -13,8 +13,19 @@ import stdcmOrigin from 'assets/pictures/mapMarkers/start.svg';
import originSVG from 'assets/pictures/origin.svg';
import viaSVG from 'assets/pictures/via.svg';
import { useOsrdConfSelectors } from 'common/osrdContext';
-import type { PathStep } from 'reducers/osrdconf/types';
import { getNearestTrack } from 'utils/mapHelper';
+import { compact } from 'lodash';
+
+export type MarkerInformation = {
+ name?: string;
+ coordinates?: number[] | Position;
+ metadata?: {
+ lineCode: number;
+ lineName: string;
+ trackName: string;
+ trackNumber: number;
+ };
+};
enum MARKER_TYPE {
ORIGIN = 'origin',
@@ -22,8 +33,8 @@ enum MARKER_TYPE {
DESTINATION = 'destination',
}
-type MarkerInformation = {
- marker: PathStep;
+type MarkerProps = {
+ marker: MarkerInformation;
coordinates: number[] | Position;
imageSource: string;
} & (
@@ -38,7 +49,7 @@ type MarkerInformation = {
type ItineraryMarkersProps = {
map: Map;
- simulationPathSteps?: PathStep[];
+ simulationPathSteps?: MarkerInformation[];
showStdcmAssets: boolean;
};
@@ -46,7 +57,7 @@ const formatPointWithNoName = (
lineCode: number,
lineName: string,
trackName: string,
- markerType: MarkerInformation['type']
+ markerType: MarkerProps['type']
) => (
<>
@@ -57,7 +68,7 @@ const formatPointWithNoName = (
>
);
-const extractMarkerInformation = (pathSteps: (PathStep | null)[], showStdcmAssets: boolean) =>
+const extractMarkerInformation = (pathSteps: MarkerInformation[], showStdcmAssets: boolean) =>
pathSteps.reduce((acc, cur, index) => {
if (cur && cur.coordinates) {
if (index === 0) {
@@ -85,19 +96,19 @@ const extractMarkerInformation = (pathSteps: (PathStep | null)[], showStdcmAsset
}
}
return acc;
- }, [] as MarkerInformation[]);
+ }, [] as MarkerProps[]);
const ItineraryMarkers = ({ map, simulationPathSteps, showStdcmAssets }: ItineraryMarkersProps) => {
const { getPathSteps } = useOsrdConfSelectors();
const pathSteps = useSelector(getPathSteps);
const markersInformation = useMemo(
- () => extractMarkerInformation(simulationPathSteps || pathSteps, showStdcmAssets),
+ () => extractMarkerInformation(simulationPathSteps || compact(pathSteps), showStdcmAssets),
[simulationPathSteps, pathSteps, showStdcmAssets]
);
const getMarkerDisplayInformation = useCallback(
- (markerInfo: MarkerInformation) => {
+ (markerInfo: MarkerProps) => {
const {
marker: { coordinates: markerCoordinates, metadata: markerMetadata },
type: markerType,
diff --git a/front/src/modules/trainschedule/components/ManageTrainSchedule/Map.tsx b/front/src/modules/trainschedule/components/ManageTrainSchedule/Map.tsx
index 6dbcea9f83a..513266e4aca 100644
--- a/front/src/modules/trainschedule/components/ManageTrainSchedule/Map.tsx
+++ b/front/src/modules/trainschedule/components/ManageTrainSchedule/Map.tsx
@@ -47,12 +47,11 @@ import RenderPopup from 'modules/trainschedule/components/ManageTrainSchedule/Ma
import { updateViewport } from 'reducers/map';
import type { Viewport } from 'reducers/map';
import { getMap, getTerrain3DExaggeration } from 'reducers/map/selectors';
-import type { PathStep } from 'reducers/osrdconf/types';
import { useAppDispatch } from 'store';
import { getMapMouseEventNearestFeature } from 'utils/mapHelper';
import ItineraryLayer from './ManageTrainScheduleMap/ItineraryLayer';
-import ItineraryMarkers from './ManageTrainScheduleMap/ItineraryMarkers';
+import ItineraryMarkers, { type MarkerInformation } from './ManageTrainScheduleMap/ItineraryMarkers';
type MapProps = {
pathProperties?: ManageTrainSchedulePathProperties;
@@ -63,7 +62,7 @@ type MapProps = {
hideItinerary?: boolean;
preventPointSelection?: boolean;
mapId?: string;
- simulationPathSteps?: PathStep[];
+ simulationPathSteps?: MarkerInformation[];
showStdcmAssets?: boolean;
isFeasible?: boolean;
};
diff --git a/front/src/reducers/index.ts b/front/src/reducers/index.ts
index 691fa0f9412..2e8926d3f52 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,
@@ -32,6 +32,7 @@ import userReducer, { userInitialState, userSlice } from 'reducers/user';
import type { UserState } from 'reducers/user';
import { type ConfSlice, defaultCommonConf } from './osrdconf/osrdConfCommon';
+import { isISOString } from 'utils/date';
const compressor = createCompressor({
whitelist: ['rollingstock'],
@@ -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..711ca582126 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,
@@ -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/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..f0d019418ea 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,12 @@ 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 date.getHours() + ':' + date.getMinutes();
}
export function timestampToHHMMSS(timestamp: number) {
@@ -200,6 +196,10 @@ export function serializeDateTimeWithoutYear(date: Date): string {
return dayjsDate.format('DD/MM HH:mm:ss');
}
+export function formatDate(date: Date) {
+ return dayjs(date).format('DD/MM/YYYY');
+}
+
/**
* Convert an ISO date into a string formatted as 'DD/MM/YYYY' and extract the numeric values for hours and minutes.
* @param {string} arrivalTime - Arrival time at which the train should arrive at the location. (Format: 'YYYY-MM-DDTHH:mm:ss+HH:mm')
@@ -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;
+};