Skip to content

Commit

Permalink
front: implement new function to update departureTime after train drag
Browse files Browse the repository at this point in the history
  • Loading branch information
clarani authored and Math-R committed Jan 6, 2025
1 parent 7f29d0c commit 6607ec8
Show file tree
Hide file tree
Showing 7 changed files with 242 additions and 184 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,11 @@ import useScenarioData from 'applications/operationalStudies/hooks/useScenarioDa
import ImportTrainSchedule from 'applications/operationalStudies/views/ImportTrainSchedule';
import ManageTrainSchedule from 'applications/operationalStudies/views/ManageTrainSchedule';
import SimulationResults from 'applications/operationalStudies/views/SimulationResults';
import { osrdEditoastApi } from 'common/api/osrdEditoastApi';
import type {
InfraWithState,
ScenarioResponse,
TimetableDetailedResult,
TrainScheduleResult,
TrainScheduleBase,
} from 'common/api/osrdEditoastApi';
import ScenarioLoaderMessage from 'modules/scenario/components/ScenarioLoaderMessage';
import TimetableManageTrainSchedule from 'modules/trainschedule/components/ManageTrainSchedule/TimetableManageTrainSchedule';
Expand All @@ -45,7 +43,6 @@ const ScenarioContent = ({
}: ScenarioDescriptionProps) => {
const { t } = useTranslation('operationalStudies/scenario');
const dispatch = useAppDispatch();
const [putTrainScheduleById] = osrdEditoastApi.endpoints.putTrainScheduleById.useMutation();

const [displayTrainScheduleManagement, setDisplayTrainScheduleManagement] = useState<string>(
MANAGE_TRAIN_SCHEDULE_TYPES.none
Expand All @@ -54,14 +51,13 @@ const ScenarioContent = ({
const [trainIdToEdit, setTrainIdToEdit] = useState<number>();
const [isMacro, setIsMacro] = useState(false);
const {
selectedTrainId,
selectedTrainSummary,
trainScheduleSummaries,
trainSchedules,
projectionData,
conflicts,
upsertTrainSchedules,
removeTrains,
updateTrainDepartureTime,
} = useScenarioData(scenario, timetable, infra);

const [ngeDto, setNgeDto] = useState<NetzgrafikDto>();
Expand All @@ -87,31 +83,6 @@ const ScenarioContent = ({
}
}, [isMacro]);

const handleTrainDrop = async (trainId: number, newDepartureTime: Date) => {
const draggedTrain = trainSchedules?.find((train) => train.id === trainId);
const updatedDepartureTime = newDepartureTime.toISOString();
if (!draggedTrain?.constraint_distribution) {
console.error('Train ou distribution des contraintes non trouvé');
return;
}

const updatedTrainSchedule: TrainScheduleBase = {
...draggedTrain,
start_time: updatedDepartureTime || draggedTrain.start_time,
};
try {
const trainScheduleResult = await putTrainScheduleById({
id: trainId,
trainScheduleForm: updatedTrainSchedule,
}).unwrap();
upsertTrainSchedules([trainScheduleResult], false);
} catch (error) {
console.error(error);
} finally {
console.log('Train schedule updated');
}
};

const handleNGEOperation = (event: NGEEvent, netzgrafikDto: NetzgrafikDto) => {
handleOperation({
event,
Expand Down Expand Up @@ -164,7 +135,6 @@ const ScenarioContent = ({
<Timetable
setDisplayTrainScheduleManagement={setDisplayTrainScheduleManagement}
infraState={infra.state}
selectedTrainId={selectedTrainId}
conflicts={conflicts}
upsertTrainSchedules={upsertTrainSchedules}
removeTrains={removeTrains}
Expand Down Expand Up @@ -232,8 +202,8 @@ const ScenarioContent = ({
projectionData={projectionData}
infraId={infra.id}
conflicts={conflicts}
selectedTrainSummary={selectedTrainSummary}
handleTrainDrop={handleTrainDrop}
trainScheduleSummaries={trainScheduleSummaries}
updateTrainDepartureTime={updateTrainDepartureTime}
/>
)
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const formatTrainScheduleSummaries = (

const trainScheduleWithDetails = relevantTrainSchedules.map((trainSchedule) => {
const rollingStock = rollingStocks.find((rs) => rs.name === trainSchedule.rolling_stock_name);

const trainSummary = rawSummaries[trainSchedule.id];

if (!trainSummary) return null;
Expand Down
209 changes: 139 additions & 70 deletions front/src/applications/operationalStudies/hooks/useScenarioData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,37 +10,33 @@ import {
type TimetableDetailedResult,
type TrainScheduleResult,
} from 'common/api/osrdEditoastApi';
import { setFailure } from 'reducers/main';
import {
getSelectedTrainId,
getTrainIdUsedForProjection,
} from 'reducers/simulationResults/selectors';
import { useAppDispatch } from 'store';
import { castErrorToFailure } from 'utils/error';
import { useOsrdConfSelectors } from 'common/osrdContext';
import { getTrainIdUsedForProjection } from 'reducers/simulationResults/selectors';
import { mapBy } from 'utils/types';

import useAutoUpdateProjection from './useAutoUpdateProjection';
import useLazyLoadTrains from './useLazyLoadTrains';
import usePathProjection from './usePathProjection';
import formatTrainScheduleSummaries from '../helpers/formatTrainScheduleSummaries';

const useScenarioData = (
scenario: ScenarioResponse,
timetable: TimetableDetailedResult,
infra: InfraWithState
) => {
const dispatch = useAppDispatch();
const { getElectricalProfileSetId } = useOsrdConfSelectors();
const electricalProfileSetId = useSelector(getElectricalProfileSetId);
const trainIdUsedForProjection = useSelector(getTrainIdUsedForProjection);
const selectedTrainId = useSelector(getSelectedTrainId);

const [trainSchedules, setTrainSchedules] = useState<TrainScheduleResult[]>();
const [trainIdsToFetch, setTrainIdsToFetch] = useState<number[]>();

const { data: rawTrainSchedules, error: fetchTrainSchedulesError } =
osrdEditoastApi.endpoints.postTrainSchedule.useQuery({
body: {
ids: timetable.train_ids,
},
});
const [fetchTrainSchedules] = osrdEditoastApi.endpoints.postTrainSchedule.useLazyQuery();
const [putTrainScheduleById] = osrdEditoastApi.endpoints.putTrainScheduleById.useMutation();
const [postTrainScheduleSimulationSummary] =
osrdEditoastApi.endpoints.postTrainScheduleSimulationSummary.useLazyQuery();
const { data: { results: rollingStocks } = { results: null } } =
osrdEditoastApi.endpoints.getLightRollingStock.useQuery({ pageSize: 1000 });

const projectionPath = usePathProjection(infra);

Expand All @@ -59,15 +55,16 @@ const useScenarioData = (
trainSchedules,
});

const { data: conflicts } = osrdEditoastApi.endpoints.getTimetableByIdConflicts.useQuery(
{
id: scenario.timetable_id,
infraId: scenario.infra_id,
},
{
skip: !allTrainsLoaded,
}
);
const { data: conflicts, refetch: refetchConflicts } =
osrdEditoastApi.endpoints.getTimetableByIdConflicts.useQuery(
{
id: scenario.timetable_id,
infraId: scenario.infra_id,
},
{
skip: !allTrainsLoaded,
}
);

const trainScheduleSummaries = useMemo(
() => sortBy(Array.from(trainScheduleSummariesById.values()), 'startTime'),
Expand All @@ -87,13 +84,18 @@ const useScenarioData = (
useAutoUpdateProjection(infra, timetable.train_ids, trainScheduleSummaries);

useEffect(() => {
if (!rawTrainSchedules) {
setTrainSchedules(undefined);
} else {
const fetchTrains = async () => {
const rawTrainSchedules = await fetchTrainSchedules({
body: {
ids: timetable.train_ids,
},
}).unwrap();
const sortedTrainSchedules = sortBy(rawTrainSchedules, 'start_time');
setTrainSchedules(sortedTrainSchedules);
}
}, [rawTrainSchedules]);
};

fetchTrains();
}, []);

// first load of the trainScheduleSummaries
useEffect(() => {
Expand All @@ -103,32 +105,24 @@ const useScenarioData = (
}
}, [trainSchedules, infra.state]);

useEffect(() => {
if (fetchTrainSchedulesError) {
dispatch(setFailure(castErrorToFailure(fetchTrainSchedulesError)));
}
}, [fetchTrainSchedulesError]);

const upsertTrainSchedules = useCallback(
(trainSchedulesToUpsert: TrainScheduleResult[], shallRemoveProjectedTrain: boolean = true) => {
(trainSchedulesToUpsert: TrainScheduleResult[]) => {
setProjectedTrainsById((prev) => {
const newProjectedTrainsById = new Map(prev);
trainSchedulesToUpsert.forEach((trainSchedule) => {
newProjectedTrainsById.delete(trainSchedule.id);
});
return newProjectedTrainsById;
});

setTrainSchedules((prev) => {
const newTrainSchedulesById = {
...keyBy(prev, 'id'),
...keyBy(trainSchedulesToUpsert, 'id'),
};
const newTrainSchedules = sortBy(Object.values(newTrainSchedulesById), 'start_time');
return newTrainSchedules;
return sortBy(Object.values(newTrainSchedulesById), 'start_time');
});

if (shallRemoveProjectedTrain) {
setProjectedTrainsById((prev) => {
const newProjectedTrainsById = new Map(prev);
trainSchedulesToUpsert.forEach((trainSchedule) => {
newProjectedTrainsById.delete(trainSchedule.id);
});
return newProjectedTrainsById;
});
}
const sortedTrainSchedulesToUpsert = sortBy(trainSchedulesToUpsert, 'start_time');
setTrainIdsToFetch(sortedTrainSchedulesToUpsert.map((trainSchedule) => trainSchedule.id));
},
Expand Down Expand Up @@ -161,29 +155,104 @@ const useScenarioData = (
});
}, []);

return {
selectedTrainId,
selectedTrainSummary: selectedTrainId
? trainScheduleSummariesById.get(selectedTrainId)
: undefined,
trainScheduleSummaries,
trainSchedules,
projectionData:
trainScheduleUsedForProjection && projectionPath
? {
trainSchedule: trainScheduleUsedForProjection,
...projectionPath,
projectedTrains,
projectionLoaderData: {
allTrainsProjected,
totalTrains: timetable.train_ids.length,
},
}
: undefined,
conflicts,
removeTrains,
upsertTrainSchedules,
};
/** Update only depature time of a train */
const updateTrainDepartureTime = useCallback(
async (trainId: number, newDeparture: Date) => {
const trainSchedule = trainSchedules?.find((train) => train.id === trainId);

if (!trainSchedule) {
throw new Error('Train non trouvé');
}

const trainScheduleResult = await putTrainScheduleById({
id: trainId,
trainScheduleForm: {
...trainSchedule,
start_time: newDeparture.toISOString(),
},
}).unwrap();

setProjectedTrainsById((prev) => {
const newProjectedTrainsById = new Map(prev);
newProjectedTrainsById.set(trainScheduleResult.id, {
...newProjectedTrainsById.get(trainScheduleResult.id)!,
departureTime: newDeparture,
});
return newProjectedTrainsById;
});

setTrainSchedules((prev) => {
const newTrainSchedulesById = {
...keyBy(prev, 'id'),
...keyBy([trainScheduleResult], 'id'),
};
const newTrainSchedules = sortBy(Object.values(newTrainSchedulesById), 'start_time');
return newTrainSchedules;
});

// update its summary
const rawSummaries = await postTrainScheduleSimulationSummary({
body: {
infra_id: scenario.infra_id,
ids: [trainId],
electrical_profile_set_id: electricalProfileSetId,
},
}).unwrap();
const summaries = formatTrainScheduleSummaries(
[trainId],
rawSummaries,
mapBy([trainScheduleResult], 'id'),
rollingStocks!
);
setTrainScheduleSummariesById((prev) => {
const newTrainScheduleSummariesById = new Map(prev);
newTrainScheduleSummariesById.set(trainId, summaries.get(trainId)!);
return newTrainScheduleSummariesById;
});

// fetch conflicts
refetchConflicts();
},
[trainSchedules, rollingStocks]
);

const results = useMemo(
() => ({
trainScheduleSummaries,
trainSchedules,
projectionData:
trainScheduleUsedForProjection && projectionPath
? {
trainSchedule: trainScheduleUsedForProjection,
...projectionPath,
projectedTrains,
projectionLoaderData: {
allTrainsProjected,
totalTrains: timetable.train_ids.length,
},
}
: undefined,
conflicts,
removeTrains,
upsertTrainSchedules,
updateTrainDepartureTime,
}),
[
trainScheduleSummaries,
trainSchedules,
trainScheduleUsedForProjection,
projectionPath,
projectedTrains,
allTrainsProjected,
timetable.train_ids.length,
conflicts,
removeTrains,
upsertTrainSchedules,
updateTrainDepartureTime,
]
);

return results;
};

export default useScenarioData;
Loading

0 comments on commit 6607ec8

Please sign in to comment.