Files
jrshikoku/stateBox/useElesite.tsx

119 lines
4.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useState, useEffect } from "react";
import { AS } from "../storageControl";
import { STORAGE_KEYS } from "@/constants";
import { API_ENDPOINTS } from "@/constants";
import type { ElesiteResponse, ElesiteData } from "@/types/unyohub";
type ElesiteHook = {
/** えれサイト使用設定 */
useElesite: boolean;
/** えれサイトデータ */
elesiteData: ElesiteResponse;
/** 指定した列番の運用情報を文字列で取得 */
getElesiteByTrainNumber: (trainNumber: string) => string | null;
/** 指定した列番に紐づくエントリの配列を取得 */
getElesiteEntriesByTrainNumber: (trainNumber: string) => ElesiteData[];
/** えれサイト使用設定を更新 */
setUseElesite: (value: boolean) => void;
};
export const useElesite = (): ElesiteHook => {
const [useElesite, setUseElesiteState] = useState(false);
const [elesiteData, setElesiteData] = useState<ElesiteResponse>([]);
// 初期読み込み
useEffect(() => {
AS.getItem(STORAGE_KEYS.USE_ELESITE).then((value) => {
setUseElesiteState(value === true || value === "true");
});
AS.getItem(STORAGE_KEYS.ELESITE_DATA).then((value) => {
if (value) {
try {
setElesiteData(JSON.parse(value as string));
} catch (e) {
console.error("Failed to parse elesite data", e);
}
}
});
}, []);
// データ更新処理
useEffect(() => {
if (!useElesite) return;
const fetchElesiteData = async () => {
try {
const cacheBuster = '?_=' + Date.now();
const response = await fetch(API_ENDPOINTS.ELESITE_DATA + cacheBuster);
const data = await response.json();
setElesiteData(data);
await AS.setItem(STORAGE_KEYS.ELESITE_DATA, JSON.stringify(data));
} catch (error) {
console.error("Failed to fetch elesite data", error);
}
};
fetchElesiteData();
// 10分ごとにデータを更新
const interval = setInterval(fetchElesiteData, 10 * 60 * 1000);
return () => clearInterval(interval);
}, [useElesite]);
// 列番から編成名を取得formation_config.units 優先)
const getElesiteByTrainNumber = (trainNumber: string): string | null => {
if (!useElesite || elesiteData.length === 0) return null;
const results: string[] = [];
// 高松(left_station)側のユニットを先に表示
// (heading_to === "left") === is_leading が true → 高松(left)端のユニット
const sortedEntries = [...elesiteData].sort((a, b) => {
const aNav = a.trains?.find(t => t.train_number === trainNumber)?.nav;
const bNav = b.trains?.find(t => t.train_number === trainNumber)?.nav;
const aIsLeft = (aNav?.heading_to === "left") === (aNav?.is_leading === true);
const bIsLeft = (bNav?.heading_to === "left") === (bNav?.is_leading === true);
if (aIsLeft === bIsLeft) return 0;
return aIsLeft ? -1 : 1;
});
for (const entry of sortedEntries) {
if (!entry.trains) continue;
const found = entry.trains.find(train => train.train_number === trainNumber);
if (!found) continue;
// units が1件以上ある場合のみ編成名を返す空 units は報告なし扱い)
const units = entry.formation_config?.units;
const formText = units?.length
? units.map(u => u.formation).join('+')
: null;
if (formText) results.push(formText);
}
return results.length > 0 ? results.join(', ') : null;
};
// 列番に紐づくエントリをすべて取得
const getElesiteEntriesByTrainNumber = (trainNumber: string): ElesiteData[] => {
if (!useElesite || elesiteData.length === 0) return [];
return elesiteData.filter(
(unyo) => unyo.trains?.some((t) => t.train_number === trainNumber)
);
};
// 設定を更新
const setUseElesite = (value: boolean) => {
setUseElesiteState(value);
AS.setItem(STORAGE_KEYS.USE_ELESITE, value.toString());
};
return {
useElesite,
elesiteData,
getElesiteByTrainNumber,
getElesiteEntriesByTrainNumber,
setUseElesite,
};
};