- Add `currentTrainMetadata.ts` to manage carrying forward official position metadata between train snapshots. - Introduce `lineDisplayName.ts` for mapping line IDs to display names. - Create `officialPositionCache.ts` for parsing and serializing official position data with cache validation. - Enhance `officialPositionService.ts` to support persistent caching of official positions and improve resolver functionality. - Update `requestCoordinator.ts` to allow cancellation of polling requests without disposing of the coordinator. - Modify `trainTimeFiltering.ts` to incorporate line ID context when checking for duplicate train data. - Refactor `useCurrentTrain.tsx` to support polling for current train data with official position enrichment. - Add tests for new features, including persistent cache behavior and handling of ambiguous train data.
60 lines
1.7 KiB
TypeScript
60 lines
1.7 KiB
TypeScript
import type { trainDataType } from "@/lib/trainPositionTextArray";
|
|
import {
|
|
officialPositionLookupKey,
|
|
type OfficialPositionLookupInput,
|
|
} from "@/lib/domain/railway";
|
|
|
|
const toLookupInput = (
|
|
train: trainDataType,
|
|
): OfficialPositionLookupInput | null => {
|
|
if (
|
|
typeof train.Pos !== "string" ||
|
|
train.Pos.length === 0 ||
|
|
typeof train.Line !== "string" ||
|
|
train.Line.length === 0 ||
|
|
train.PosNum === undefined ||
|
|
(typeof train.PosNum === "string" && train.PosNum.length === 0) ||
|
|
(typeof train.PosNum === "number" && !Number.isFinite(train.PosNum))
|
|
) {
|
|
return null;
|
|
}
|
|
return {
|
|
line: train.Line,
|
|
pos: train.Pos,
|
|
posNum: train.PosNum,
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Keeps the currently displayed official metadata while the next current-train
|
|
* snapshot is being enriched. Only an identical line/position/position-number
|
|
* tuple may carry metadata forward.
|
|
*/
|
|
export const carryForwardOfficialPositionMetadata = (
|
|
next: readonly trainDataType[],
|
|
previous: readonly trainDataType[],
|
|
): trainDataType[] => {
|
|
const metadataByKey = new Map<
|
|
string,
|
|
NonNullable<trainDataType["officialPosition"]>
|
|
>();
|
|
|
|
for (const train of previous) {
|
|
if (!train.officialPosition) continue;
|
|
const input = toLookupInput(train);
|
|
if (!input) continue;
|
|
metadataByKey.set(
|
|
officialPositionLookupKey(input),
|
|
train.officialPosition,
|
|
);
|
|
}
|
|
|
|
return next.map((train) => {
|
|
if (train.officialPosition) return train;
|
|
const input = toLookupInput(train);
|
|
if (!input) return train;
|
|
const metadata = metadataByKey.get(officialPositionLookupKey(input));
|
|
return metadata ? { ...train, officialPosition: metadata } : train;
|
|
});
|
|
};
|