- 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.
130 lines
4.2 KiB
TypeScript
130 lines
4.2 KiB
TypeScript
import { useState, useEffect } from 'react';
|
|
import { AS } from '@/storageControl';
|
|
import { STORAGE_KEYS } from '@/constants';
|
|
import { logger } from '@/utils/logger';
|
|
import { useCurrentTrainData } from '@/stateBox/useCurrentTrain';
|
|
import { useTrainMenu } from '@/stateBox/useTrainMenu';
|
|
import type { trainDataType } from '@/lib/trainPositionTextArray';
|
|
import { lineIdFromStationNumber } from '@/lib/checkDuplicateTrainData';
|
|
import { findReversalPoints } from '@/lib/eachTrainInfoCoreLib/findReversalPoints';
|
|
|
|
export const useTrainPosition = (
|
|
trainNum: string,
|
|
stopStationIDList: string[][]
|
|
) => {
|
|
const {
|
|
getCurrentStationData,
|
|
getCurrentStationDataList,
|
|
getPosition,
|
|
} = useCurrentTrainData();
|
|
const { updatePermission } = useTrainMenu();
|
|
const [currentTrainData, setCurrentTrainData] = useState<trainDataType | undefined>();
|
|
const [currentTrainDataList, setCurrentTrainDataList] = useState<trainDataType[]>([]);
|
|
const [currentPosition, setCurrentPosition] = useState<string[]>([]);
|
|
const [currentPositionList, setCurrentPositionList] = useState<string[][]>([]);
|
|
const [trainPositionSwitch, setTrainPositionSwitch] = useState<string>('false');
|
|
|
|
useEffect(() => {
|
|
const candidates = getCurrentStationDataList(trainNum);
|
|
const routeLineCounts = new Map<string, number>();
|
|
for (const stationNumber of stopStationIDList.flat()) {
|
|
const line = lineIdFromStationNumber(stationNumber);
|
|
if (line) routeLineCounts.set(line, (routeLineCounts.get(line) ?? 0) + 1);
|
|
}
|
|
const routeLineIds = [...routeLineCounts.entries()]
|
|
.sort(([, countA], [, countB]) => countB - countA)
|
|
.map(([line]) => line);
|
|
const selected = getCurrentStationData(trainNum, routeLineIds);
|
|
const visible = updatePermission
|
|
? candidates
|
|
: selected
|
|
? [selected]
|
|
: [];
|
|
logger.debug('Train position data:', visible);
|
|
setCurrentTrainDataList(visible);
|
|
setCurrentTrainData(visible[0]);
|
|
}, [
|
|
getCurrentStationData,
|
|
getCurrentStationDataList,
|
|
stopStationIDList,
|
|
trainNum,
|
|
updatePermission,
|
|
]);
|
|
|
|
useEffect(() => {
|
|
if (!stopStationIDList.length || !currentTrainDataList.length) {
|
|
setCurrentPositionList([]);
|
|
setCurrentPosition([]);
|
|
return;
|
|
}
|
|
|
|
const positions = currentTrainDataList.map((train) => {
|
|
const position = getPosition(train);
|
|
const next = position ? [...position] : [];
|
|
if (next.length > 1) {
|
|
// 伊予市駅の特殊処理
|
|
const iyoIndex = stopStationIDList.findIndex((d) => d.includes('U14'));
|
|
|
|
if (next[0] === '-Iyo') {
|
|
next[0] = stopStationIDList[iyoIndex - 1]?.[0];
|
|
} else if (next[0] === '+Iyo') {
|
|
next[0] = stopStationIDList[iyoIndex + 1]?.[0];
|
|
}
|
|
|
|
if (next[1] === '+Iyo') {
|
|
next[1] = stopStationIDList[iyoIndex + 1]?.[0];
|
|
} else if (next[1] === '-Iyo') {
|
|
next[1] = stopStationIDList[iyoIndex - 1]?.[0];
|
|
}
|
|
}
|
|
return next;
|
|
});
|
|
setCurrentPositionList(positions);
|
|
setCurrentPosition(positions[0] ?? []);
|
|
}, [currentTrainDataList, stopStationIDList, getPosition]);
|
|
|
|
useEffect(() => {
|
|
AS.getItem(STORAGE_KEYS.TRAIN_POSITION_SWITCH)
|
|
.then((value) => {
|
|
if (value) setTrainPositionSwitch(value);
|
|
})
|
|
.catch(() => AS.setItem(STORAGE_KEYS.TRAIN_POSITION_SWITCH, 'true'));
|
|
}, []);
|
|
|
|
const mergePoints = (includeReversal: boolean) => {
|
|
const merged = stopStationIDList.map(() => false);
|
|
for (const position of currentPositionList) {
|
|
const candidate = findReversalPoints(
|
|
position,
|
|
stopStationIDList,
|
|
includeReversal,
|
|
);
|
|
if (!candidate) continue;
|
|
candidate.forEach((point, index) => {
|
|
merged[index] = merged[index] || point;
|
|
});
|
|
}
|
|
return merged;
|
|
};
|
|
|
|
const points =
|
|
trainPositionSwitch === 'true'
|
|
? mergePoints(true)
|
|
: stopStationIDList.map(() => false);
|
|
|
|
const pointsDisplay =
|
|
trainPositionSwitch === 'true'
|
|
? mergePoints(false)
|
|
: stopStationIDList.map(() => false);
|
|
|
|
return {
|
|
currentTrainData,
|
|
currentTrainDataList,
|
|
currentPosition,
|
|
currentPositionList,
|
|
points,
|
|
pointsDisplay,
|
|
trainPositionSwitch,
|
|
};
|
|
};
|