diff --git a/front/src/applications/stdcmV2/components/StdcmDestination.tsx b/front/src/applications/stdcmV2/components/StdcmDestination.tsx index a15eb35b25c..b08229e12fd 100644 --- a/front/src/applications/stdcmV2/components/StdcmDestination.tsx +++ b/front/src/applications/stdcmV2/components/StdcmDestination.tsx @@ -1,4 +1,4 @@ -import { useEffect, useMemo } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; @@ -8,7 +8,7 @@ import type { StdcmConfSliceActions } from 'reducers/osrdconf/stdcmConf'; import type { PathStep } from 'reducers/osrdconf/types'; import { useAppDispatch } from 'store'; import { replaceElementAtIndex } from 'utils/array'; -import { extractDateAndTimefromISO } from 'utils/date'; +import { extractDateAndTimefromISO, generateISOArrival } from 'utils/date'; import StdcmCard from './StdcmCard'; import StdcmOperationalPoint from './StdcmOperationalPoint'; @@ -24,6 +24,13 @@ const StdcmDestination = ({ }) => { const { t } = useTranslation('stdcm'); const dispatch = useAppDispatch(); + + const [arrivalDateInput, setArrivalDateInput] = useState(undefined); + const [arrivalTimeInput, setArrivalTimeInput] = useState<{ hours: number; minutes: number }>({ + hours: 0, + minutes: 0, + }); + const { updateDestination, updateDestinationArrival, @@ -59,10 +66,21 @@ const StdcmDestination = ({ const updateDestinationPoint = (pathStep: PathStep | null) => { dispatch(updateDestination(pathStep)); + if (arrivalDateInput && arrivalTimeInput) { + const newOpArrival = generateISOArrival(arrivalDateInput, arrivalTimeInput); + dispatch(updateDestinationArrival(newOpArrival)); + } }; - const onDestinationArrivalChange = (arrival: string) => { - dispatch(updateDestinationArrival(arrival)); + const onDestinationArrivalChange = ( + date: Date, + { hours, minutes }: { hours: number; minutes: number } + ) => { + setArrivalDateInput(date); + setArrivalTimeInput({ hours, minutes }); + + const newOpArrival = generateISOArrival(date, { hours, minutes }); + dispatch(updateDestinationArrival(newOpArrival)); }; const onDestinationArrivalTypeChange = (arrivalType: ArrivalTimeTypes) => { diff --git a/front/src/applications/stdcmV2/components/StdcmOpSchedule.tsx b/front/src/applications/stdcmV2/components/StdcmOpSchedule.tsx index 922089d7eda..b4d4877d391 100644 --- a/front/src/applications/stdcmV2/components/StdcmOpSchedule.tsx +++ b/front/src/applications/stdcmV2/components/StdcmOpSchedule.tsx @@ -6,13 +6,13 @@ import { useTranslation } from 'react-i18next'; import { useSelector } from 'react-redux'; import { useOsrdConfSelectors } from 'common/osrdContext'; -import { formatLocaleDateToIsoDate, isArrivalDateInSearchTimeWindow } from 'utils/date'; +import { isArrivalDateInSearchTimeWindow } from 'utils/date'; import type { ArrivalTimeTypes } from '../types'; type StdcmOpScheduleProps = { disabled: boolean; - onArrivalChange: (arrival: string) => void; + onArrivalChange: (date: Date, { hours, minutes }: { hours: number; minutes: number }) => void; onArrivalTypeChange: (arrivalType: ArrivalTimeTypes) => void; onArrivalToleranceChange: ({ toleranceBefore, @@ -77,13 +77,6 @@ const StdcmOpSchedule = ({ }; }, [opTimingData, opToleranceValues, searchDatetimeWindow]); - const updateOpArrival = (date: Date, { hours, minutes }: { hours: number; minutes: number }) => { - date.setHours(hours); - date.setMinutes(minutes); - const newOpArrival = formatLocaleDateToIsoDate(date); - onArrivalChange(newOpArrival); - }; - return (
@@ -121,7 +114,7 @@ const StdcmOpSchedule = ({ : undefined, }} onDateChange={(e) => { - updateOpArrival(e, { + onArrivalChange(e, { hours: arrivalTimeHours || 0, minutes: arrivalTimeMinutes || 0, }); @@ -135,7 +128,7 @@ const StdcmOpSchedule = ({ hours={arrivalTimeHours} minutes={arrivalTimeMinutes} onTimeChange={({ hours, minutes }) => { - updateOpArrival(arrivalDate, { + onArrivalChange(arrivalDate, { hours, minutes, }); diff --git a/front/src/applications/stdcmV2/components/StdcmOrigin.tsx b/front/src/applications/stdcmV2/components/StdcmOrigin.tsx index 21b5d88efb8..c75d6ba102f 100644 --- a/front/src/applications/stdcmV2/components/StdcmOrigin.tsx +++ b/front/src/applications/stdcmV2/components/StdcmOrigin.tsx @@ -1,4 +1,4 @@ -import { useEffect, useMemo } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; @@ -8,7 +8,7 @@ import type { StdcmConfSliceActions } from 'reducers/osrdconf/stdcmConf'; import type { PathStep } from 'reducers/osrdconf/types'; import { useAppDispatch } from 'store'; import { replaceElementAtIndex } from 'utils/array'; -import { extractDateAndTimefromISO } from 'utils/date'; +import { extractDateAndTimefromISO, generateISOArrival } from 'utils/date'; import StdcmCard from './StdcmCard'; import StdcmOperationalPoint from './StdcmOperationalPoint'; @@ -25,6 +25,11 @@ const StdcmOrigin = ({ const { t } = useTranslation('stdcm'); const dispatch = useAppDispatch(); + const [arrivalDateInput, setArrivalDateInput] = useState(undefined); + const [arrivalTimeInput, setArrivalTimeInput] = useState< + { hours: number; minutes: number } | undefined + >(undefined); + const { updateOrigin, updateOriginArrival, updateOriginArrivalType, updateOriginTolerances } = useOsrdConfActions() as StdcmConfSliceActions; @@ -50,10 +55,21 @@ const StdcmOrigin = ({ const updateOriginPoint = (pathStep: PathStep | null) => { dispatch(updateOrigin(pathStep)); + if (arrivalDateInput && arrivalTimeInput) { + const newOpArrival = generateISOArrival(arrivalDateInput, arrivalTimeInput); + dispatch(updateOriginArrival(newOpArrival)); + } }; - const onOriginArrivalChange = (arrival: string) => { - dispatch(updateOriginArrival(arrival)); + const onOriginArrivalChange = ( + date: Date, + { hours, minutes }: { hours: number; minutes: number } + ) => { + setArrivalDateInput(date); + setArrivalTimeInput({ hours, minutes }); + + const newOpArrival = generateISOArrival(date, { hours, minutes }); + dispatch(updateOriginArrival(newOpArrival)); }; const onOriginArrivalTypeChange = (arrivalType: ArrivalTimeTypes) => { diff --git a/front/src/reducers/osrdconf/osrdConfCommon/index.ts b/front/src/reducers/osrdconf/osrdConfCommon/index.ts index 738a030939d..3c091a02971 100644 --- a/front/src/reducers/osrdconf/osrdConfCommon/index.ts +++ b/front/src/reducers/osrdconf/osrdConfCommon/index.ts @@ -302,19 +302,21 @@ export function buildCommonConfReducers(): CommonConfRe state.startTime = action.payload; }, updateOrigin(state: Draft, action: PayloadAction>) { + const prevOriginArrivalType = state.pathSteps[0]?.arrivalType; const newPoint = action.payload ? { ...action.payload, - arrivalType: ArrivalTimeTypes.PRECISE_TIME, + arrivalType: prevOriginArrivalType || ArrivalTimeTypes.PRECISE_TIME, } : null; state.pathSteps = updateOriginPathStep(state.pathSteps, newPoint, true); }, updateDestination(state: Draft, action: PayloadAction>) { + const prevDestinationArrivalType = state.pathSteps[state.pathSteps.length - 1]?.arrivalType; const newPoint = action.payload ? { ...action.payload, - arrivalType: ArrivalTimeTypes.ASAP, + arrivalType: prevDestinationArrivalType || ArrivalTimeTypes.ASAP, } : null; state.pathSteps = updateDestinationPathStep(state.pathSteps, newPoint, true); diff --git a/front/src/utils/__tests__/date.spec.ts b/front/src/utils/__tests__/date.spec.ts index 2199132bbae..2ffab647d23 100644 --- a/front/src/utils/__tests__/date.spec.ts +++ b/front/src/utils/__tests__/date.spec.ts @@ -6,6 +6,8 @@ import { parseDateTime, extractDateAndTimefromISO, isArrivalDateInSearchTimeWindow, + formatLocaleDateToIsoDate, + generateISOArrival, } from 'utils/date'; describe('dateTimeToIso', () => { @@ -134,3 +136,15 @@ describe('isArrivalDateInSearchTimeWindow', () => { expect(result).toBe(false); }); }); + +describe('generateISOArrival', () => { + it('should correctly set hours and minutes and return ISO string', () => { + const date = new Date('2024-08-01T00:00:00Z'); + const time = { hours: 10, minutes: 30 }; + const expectedISODate = formatLocaleDateToIsoDate(new Date('2024-08-01T10:30:00Z')); + + const result = generateISOArrival(date, time); + + expect(result).toBe(expectedISODate); + }); +}); diff --git a/front/src/utils/date.ts b/front/src/utils/date.ts index 07b14482cc7..56242b153d5 100644 --- a/front/src/utils/date.ts +++ b/front/src/utils/date.ts @@ -229,3 +229,18 @@ export function isArrivalDateInSearchTimeWindow( const arrivalDate = new Date(arrivalTime); return arrivalDate >= searchDatetimeWindow.begin && arrivalDate <= searchDatetimeWindow.end; } + +/** + * Generates an ISO arrival date string based on the provided date, hours, and minutes. + * @param {Date} date - The base date. + * @param {{ hours: number; minutes: number }} - An object containing the hours and the minutes of the arrival time. + * @returns {string} The ISO formatted arrival date string. + */ +export const generateISOArrival = ( + date: Date, + { hours, minutes }: { hours: number; minutes: number } +) => { + date.setHours(hours); + date.setMinutes(minutes); + return formatLocaleDateToIsoDate(date); +};