diff --git a/front/src/modules/timesStops/helpers/__tests__/utils.spec.ts b/front/src/modules/timesStops/helpers/__tests__/utils.spec.ts index 56f181b0cff..5ab5890b84e 100644 --- a/front/src/modules/timesStops/helpers/__tests__/utils.spec.ts +++ b/front/src/modules/timesStops/helpers/__tests__/utils.spec.ts @@ -286,6 +286,47 @@ describe('updateDaySinceDeparture', () => { ]; expect(result).toEqual(expected); }); + it('should handle departure exactly at midnight', () => { + const pathWaypointRows = [ + { + opId: 'd9a382bc', + name: 'St', + uic: 75, + ch: 'BV', + arrival: { time: '00:00:00' }, + }, + { + opId: 'd9b38600', + name: 'Ge', + uic: 86, + ch: 'BX', + arrival: { time: '01:00:00' }, + }, + ] as TimesStopsInputRow[]; + const startTime = '2024-08-13T00:00:00'; + const result = updateDaySinceDeparture(pathWaypointRows, startTime, { + keepFirstIndexArrival: true, + }); + const expected = [ + { + opId: 'd9a382bc', + name: 'St', + uic: 75, + ch: 'BV', + arrival: { time: '00:00:00', daySinceDeparture: 0 }, + departure: undefined, + }, + { + opId: 'd9b38600', + name: 'Ge', + uic: 86, + ch: 'BX', + arrival: { time: '01:00:00', daySinceDeparture: 0 }, + departure: undefined, + }, + ]; + expect(result).toEqual(expected); + }); }); describe('2 day span', () => { it('should add day 1 field', () => { @@ -329,6 +370,103 @@ describe('updateDaySinceDeparture', () => { ]; expect(result).toEqual(expected); }); + it('should handle exactly midnight', () => { + const pathWaypointRows = [ + { + opId: 'd9c92cb4', + name: 'Ge', + uic: 86, + ch: 'BV', + arrival: { time: '23:50:00' }, + }, + { + opId: 'd9b38600', + name: 'Ge', + uic: 86, + ch: 'BX', + arrival: { time: '00:00:00' }, + }, + ] as TimesStopsInputRow[]; + const startTime = '2024-08-13T23:50:00'; + const result = updateDaySinceDeparture(pathWaypointRows, startTime, { + keepFirstIndexArrival: true, + }); + const expected = [ + { + opId: 'd9c92cb4', + name: 'Ge', + uic: 86, + ch: 'BV', + arrival: { time: '23:50:00', daySinceDeparture: 0 }, + departure: undefined, + }, + { + opId: 'd9b38600', + name: 'Ge', + uic: 86, + ch: 'BX', + arrival: { time: '00:00:00', daySinceDeparture: 1, dayDisplayed: true }, + departure: undefined, + }, + ]; + expect(result).toEqual(expected); + }); + it('should handle a waypoint exactly at midnight in the middle', () => { + const pathWaypointRows = [ + { + opId: 'd9a382bc', + name: 'St', + uic: 75, + ch: 'BV', + arrival: { time: '23:45:00' }, + }, + { + opId: 'd9b38600', + name: 'Ge', + uic: 86, + ch: 'BX', + arrival: { time: '00:00:00' }, + }, + { + opId: 'd9a382bd', + name: 'Fr', + uic: 87, + ch: 'BY', + arrival: { time: '01:30:00' }, + }, + ] as TimesStopsInputRow[]; + const startTime = '2024-08-13T23:45:00'; + const result = updateDaySinceDeparture(pathWaypointRows, startTime, { + keepFirstIndexArrival: true, + }); + const expected = [ + { + opId: 'd9a382bc', + name: 'St', + uic: 75, + ch: 'BV', + arrival: { time: '23:45:00', daySinceDeparture: 0 }, + departure: undefined, + }, + { + opId: 'd9b38600', + name: 'Ge', + uic: 86, + ch: 'BX', + arrival: { time: '00:00:00', daySinceDeparture: 1, dayDisplayed: true }, + departure: undefined, + }, + { + opId: 'd9a382bd', + name: 'Fr', + uic: 87, + ch: 'BY', + arrival: { time: '01:30:00', daySinceDeparture: 1 }, + departure: undefined, + }, + ]; + expect(result).toEqual(expected); + }); it('should add display flag for the first time in the new day', () => { const TimesStopsInputRows = [ { @@ -566,6 +704,109 @@ describe('updateDaySinceDeparture', () => { ]; expect(result).toEqual(expected); }); + it('should handle a three-day span with two midnights', () => { + const pathWaypointRows = [ + { + opId: 'd9a382bc', + name: 'St', + uic: 75, + ch: 'BV', + arrival: { time: '23:45:00' }, + }, + { + opId: 'd9b38600', + name: 'Ge', + uic: 86, + ch: 'BX', + arrival: { time: '00:00:00' }, + }, + { + opId: 'd9a382bd', + name: 'Fr', + uic: 87, + ch: 'BY', + arrival: { time: '01:30:00' }, + }, + { + opId: 'd9a382be', + name: 'Lm', + uic: 88, + ch: 'BZ', + arrival: { time: '23:50:00' }, + }, + { + opId: 'd9a382bf', + name: 'Nc', + uic: 89, + ch: 'CA', + arrival: { time: '00:00:00' }, + }, + { + opId: 'd9a382c0', + name: 'Po', + uic: 90, + ch: 'CB', + arrival: { time: '03:00:00' }, + }, + ] as TimesStopsInputRow[]; + + const startTime = '2024-08-13T23:45:00'; + const result = updateDaySinceDeparture(pathWaypointRows, startTime, { + keepFirstIndexArrival: true, + }); + + const expected = [ + { + opId: 'd9a382bc', + name: 'St', + uic: 75, + ch: 'BV', + arrival: { time: '23:45:00', daySinceDeparture: 0 }, + departure: undefined, + }, + { + opId: 'd9b38600', + name: 'Ge', + uic: 86, + ch: 'BX', + arrival: { time: '00:00:00', daySinceDeparture: 1, dayDisplayed: true }, + departure: undefined, + }, + { + opId: 'd9a382bd', + name: 'Fr', + uic: 87, + ch: 'BY', + arrival: { time: '01:30:00', daySinceDeparture: 1 }, + departure: undefined, + }, + { + opId: 'd9a382be', + name: 'Lm', + uic: 88, + ch: 'BZ', + arrival: { time: '23:50:00', daySinceDeparture: 1 }, + departure: undefined, + }, + { + opId: 'd9a382bf', + name: 'Nc', + uic: 89, + ch: 'CA', + arrival: { time: '00:00:00', daySinceDeparture: 2, dayDisplayed: true }, + departure: undefined, + }, + { + opId: 'd9a382c0', + name: 'Po', + uic: 90, + ch: 'CB', + arrival: { time: '03:00:00', daySinceDeparture: 2 }, + departure: undefined, + }, + ]; + expect(result).toEqual(expected); + }); }); }); diff --git a/front/src/modules/timesStops/helpers/utils.ts b/front/src/modules/timesStops/helpers/utils.ts index 5368cf4c838..0b301130b7e 100644 --- a/front/src/modules/timesStops/helpers/utils.ts +++ b/front/src/modules/timesStops/helpers/utils.ts @@ -211,11 +211,13 @@ export function updateDaySinceDeparture( return pathWaypointRows.map((pathWaypoint, index) => { const { arrival, stopFor } = pathWaypoint; - const arrivalInSeconds = arrival?.time ? time2sec(arrival.time) : null; let formattedArrival: TimeExtraDays | undefined; - if (arrivalInSeconds) { - if (arrivalInSeconds < previousTime) { + + if (arrivalInSeconds !== null) { + const isMidnight = arrival?.time === '00:00:00'; + + if ((arrivalInSeconds < previousTime || isMidnight) && !(isMidnight && index === 0)) { currentDaySinceDeparture += 1; formattedArrival = { time: arrival!.time, @@ -228,14 +230,17 @@ export function updateDaySinceDeparture( daySinceDeparture: currentDaySinceDeparture, }; } - previousTime = arrivalInSeconds; + previousTime = isMidnight ? 0 : arrivalInSeconds; } let formattedDeparture: TimeExtraDays | undefined; - if (stopFor && arrivalInSeconds) { + + if (stopFor && arrivalInSeconds !== null) { const departureInSeconds = (arrivalInSeconds + Number(stopFor)) % SECONDS_IN_A_DAY; const isAfterMidnight = departureInSeconds < previousTime; - if (isAfterMidnight) { + const isDepartureMidnight = departureInSeconds === 0; + + if (isAfterMidnight || isDepartureMidnight) { currentDaySinceDeparture += 1; formattedDeparture = { time: secToHoursString(departureInSeconds, { withSeconds: true }), @@ -250,7 +255,6 @@ export function updateDaySinceDeparture( } previousTime = departureInSeconds; } - return { ...pathWaypoint, arrival: keepFirstIndexArrival || index > 0 ? formattedArrival : undefined,