feat: add date formatting and stale check for Unyohub entries in TrainDataSources
This commit is contained in:
@@ -59,6 +59,24 @@ const formatHHMM = (iso: string): string => {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* "YYYY-MM-DD HH:MM:SS" 形式の文字列を "M/D HH:MM" 形式にフォーマット
|
||||
* ISO 8601 文字列にも対応
|
||||
*/
|
||||
const formatDateHHMM = (datetime: string): string => {
|
||||
try {
|
||||
// "YYYY-MM-DD HH:MM:SS" → space を T に置換して安全にパース
|
||||
const d = new Date(datetime.replace(" ", "T"));
|
||||
const mo = d.getMonth() + 1;
|
||||
const day = d.getDate();
|
||||
const h = d.getHours().toString().padStart(2, "0");
|
||||
const m = d.getMinutes().toString().padStart(2, "0");
|
||||
return `${mo}/${day} ${h}:${m}`;
|
||||
} catch {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
export const TrainDataSources: FC<{ payload?: TrainDataSourcesPayload }> = ({
|
||||
payload,
|
||||
}) => {
|
||||
@@ -189,6 +207,37 @@ export const TrainDataSources: FC<{ payload?: TrainDataSourcesPayload }> = ({
|
||||
(e) => !!e.formations && e.formations.trim() !== "",
|
||||
);
|
||||
|
||||
// 最終投稿日時(エントリ中の最新値)
|
||||
const unyohubLastPostedDatetime =
|
||||
unyohubEntries
|
||||
.map((e) => e.last_posted_datetime)
|
||||
.filter((d): d is string => !!d)
|
||||
.sort()
|
||||
.at(-1) ?? null;
|
||||
|
||||
// 投稿日時が今日でない場合はカードを薄く表示("YYYY-MM-DD HH:MM:SS" 形式)
|
||||
const todayDateStr = new Date().toLocaleDateString("sv"); // "YYYY-MM-DD"
|
||||
const isUnyohubStale =
|
||||
unyohubLastPostedDatetime == null ||
|
||||
!unyohubLastPostedDatetime.startsWith(todayDateStr);
|
||||
|
||||
// 運用グループ名(重複除去して最大3件)
|
||||
const unyohubGroupNames = [
|
||||
...new Set(
|
||||
nonEmptyFormationEntries
|
||||
.map((e) => e.operation_group_name)
|
||||
.filter((n) => !!n && n.trim() !== ""),
|
||||
),
|
||||
]
|
||||
.slice(0, 3)
|
||||
.join(" / ");
|
||||
|
||||
// 新フィールドのチップ表示フラグ
|
||||
const hubHasIsQuotation = unyohubEntries.some((e) => e.is_quotation === true);
|
||||
const hubHasFromBeginner = unyohubEntries.some((e) => e.from_beginner === true);
|
||||
const hubHasCommentExists = unyohubEntries.some((e) => e.comment_exists === true);
|
||||
const hubHasHiddenByDefault = unyohubEntries.some((e) => e.hidden_by_default === true);
|
||||
|
||||
// 先頭エントリで direction を取得し、表示順を決定:
|
||||
// outbound → position_forward 昇順 (pos=1 が宇和島/南端側)
|
||||
// inbound → position_forward 降順 (pos=MAX が宇和島/南端側)
|
||||
@@ -218,7 +267,38 @@ export const TrainDataSources: FC<{ payload?: TrainDataSourcesPayload }> = ({
|
||||
const formationDetail = (
|
||||
<View style={styles.operationDetailBlock}>
|
||||
{hasNonEmptyFormations && (
|
||||
<Text style={[styles.unitIdText, { color: colors.textAccent }]}>{formationNames}</Text>
|
||||
<Text style={[styles.unitIdText, { color: colors.textAccent, opacity: isUnyohubStale ? 0.4 : 1 }]}>{formationNames}</Text>
|
||||
)}
|
||||
{unyohubGroupNames !== "" && (
|
||||
<Text style={[styles.subText, { color: colors.textSecondary }]}>{unyohubGroupNames}</Text>
|
||||
)}
|
||||
{(hubHasIsQuotation || hubHasFromBeginner || hubHasCommentExists || hubHasHiddenByDefault) && (
|
||||
<View style={styles.metaChipRow}>
|
||||
{hubHasIsQuotation && (
|
||||
<View style={styles.metaChip}>
|
||||
<MaterialCommunityIcons name="content-copy" size={11} color="#888" />
|
||||
<Text style={styles.metaChipText}>引用データ</Text>
|
||||
</View>
|
||||
)}
|
||||
{hubHasFromBeginner && (
|
||||
<View style={[styles.metaChip, styles.metaChipOrange]}>
|
||||
<MaterialCommunityIcons name="account-school" size={11} color="#f57c00" />
|
||||
<Text style={[styles.metaChipText, { color: "#f57c00" }]}>初心者投稿</Text>
|
||||
</View>
|
||||
)}
|
||||
{hubHasCommentExists && (
|
||||
<View style={styles.metaChip}>
|
||||
<MaterialCommunityIcons name="comment-text-outline" size={11} color="#0077aa" />
|
||||
<Text style={[styles.metaChipText, { color: "#0077aa" }]}>コメントあり</Text>
|
||||
</View>
|
||||
)}
|
||||
{hubHasHiddenByDefault && (
|
||||
<View style={[styles.metaChip, styles.metaChipOrange]}>
|
||||
<MaterialCommunityIcons name="eye-off-outline" size={11} color="#f57c00" />
|
||||
<Text style={[styles.metaChipText, { color: "#f57c00" }]}>非表示設定</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
)}
|
||||
<RefDirectionBanner
|
||||
rows={[{ leftLabel: "宇和島/宿毛/阿波海南" }]}
|
||||
@@ -363,9 +443,11 @@ export const TrainDataSources: FC<{ payload?: TrainDataSourcesPayload }> = ({
|
||||
color={colors.textSecondary}
|
||||
title="鉄道運用Hub"
|
||||
label="外部コミュニティデータ"
|
||||
sub={
|
||||
sub={
|
||||
hasNonEmptyFormations
|
||||
? ""
|
||||
? unyohubLastPostedDatetime
|
||||
? `最終投稿: ${formatDateHHMM(unyohubLastPostedDatetime)}`
|
||||
: ""
|
||||
: unyoCount > 0
|
||||
? "数日の運用報告なし"
|
||||
: "この列車の運用データはありません"
|
||||
|
||||
@@ -366,6 +366,22 @@ export const injectJavascriptData = ({
|
||||
return foundUnyos.map(u => u.formations + '(' + u.position_forward + '-' + u.position_rear + ')').join(', ');
|
||||
};
|
||||
|
||||
/** 今日付の投稿があるか判定("YYYY-MM-DD ..." 形式の last_posted_datetime) */
|
||||
const isUnyohubStale = (trainNumber) => {
|
||||
if (!unyohubData || unyohubData.length === 0) return true;
|
||||
const today = new Date();
|
||||
const yyyy = today.getFullYear();
|
||||
const mm = String(today.getMonth() + 1).padStart(2, '0');
|
||||
const dd = String(today.getDate()).padStart(2, '0');
|
||||
const todayStr = yyyy + '-' + mm + '-' + dd;
|
||||
const matchedEntries = unyohubData.filter(
|
||||
u => u.trains && u.trains.some(t => t.train_number === trainNumber)
|
||||
&& u.formations && u.formations.trim() !== ""
|
||||
);
|
||||
if (matchedEntries.length === 0) return true;
|
||||
return !matchedEntries.some(u => u.last_posted_datetime && u.last_posted_datetime.startsWith(todayStr));
|
||||
};
|
||||
|
||||
const getElesiteFormation = (trainNumber) => {
|
||||
if (!${useElesite === "true"} || !elesiteData || elesiteData.length === 0) {
|
||||
return null;
|
||||
@@ -739,8 +755,9 @@ export const injectJavascriptData = ({
|
||||
const optionalTextColor = optionalText.includes("最終") ? "red" : "black";
|
||||
const unyohubFormation = getUnyohubFormation(列番データ);
|
||||
const hasUnyohub = unyohubFormation !== null;
|
||||
const unyohubStale = hasUnyohub && isUnyohubStale(列番データ);
|
||||
if(hasUnyohub) {
|
||||
console.log('[UnyoHub] Badge shown for', 列番データ, ':', unyohubFormation);
|
||||
console.log('[UnyoHub] Badge shown for', 列番データ, ':', unyohubFormation, unyohubStale ? '(stale)' : '');
|
||||
}
|
||||
const elesiteFormation = getElesiteFormation(列番データ);
|
||||
const hasElesite = elesiteFormation !== null;
|
||||
@@ -769,7 +786,8 @@ export const injectJavascriptData = ({
|
||||
if(hasUnyohub) {
|
||||
const unyoOffsetPx = _blueOffset;
|
||||
const offsetStyle = badgeVerticalPos + ":" + unyoOffsetPx + "px;";
|
||||
badgeHtml += "<div style='position:absolute;" + badgePosition + ":0;" + offsetStyle + "background-color:#ffcc00;border-radius:50%;border:1px solid #000000;width:19px;height:19px;box-sizing:border-box;overflow:hidden;display:flex;align-items:center;justify-content:center;'><img src='https://fossil.2pd.jp/unyohub/raw/5cb01771a1ae8cb73b7bc2048b88f7878ab180aef46247c3901d7cba50d6b71f' style='width:24px;height:24px;margin-left:5px;'/></div>";
|
||||
const unyoOpacity = unyohubStale ? "opacity:0.35;" : "";
|
||||
badgeHtml += "<div style='position:absolute;" + badgePosition + ":0;" + offsetStyle + unyoOpacity + "background-color:#ffcc00;border-radius:50%;border:1px solid #000000;width:19px;height:19px;box-sizing:border-box;overflow:hidden;display:flex;align-items:center;justify-content:center;'><img src='https://fossil.2pd.jp/unyohub/raw/5cb01771a1ae8cb73b7bc2048b88f7878ab180aef46247c3901d7cba50d6b71f' style='width:24px;height:24px;margin-left:5px;'/></div>";
|
||||
}
|
||||
|
||||
// えれサイトバッジ(緑)
|
||||
|
||||
@@ -33,9 +33,11 @@ export type ElesiteTrain = {
|
||||
/** 鉄道運用Hub APIデータ型 */
|
||||
export type UnyohubData = {
|
||||
operation_id?: string;
|
||||
/** 運用グループ名 */
|
||||
operation_group_name: string;
|
||||
formations: string;
|
||||
posts_count: number;
|
||||
from_beginner: boolean;
|
||||
from_beginner?: boolean;
|
||||
trains: UnyohubTrain[];
|
||||
starting_location: string;
|
||||
starting_track: string;
|
||||
@@ -47,7 +49,17 @@ export type UnyohubData = {
|
||||
min_car_count: number;
|
||||
max_car_count: number;
|
||||
main_color: string;
|
||||
/** デフォルトアイコン識別子 */
|
||||
default_icon?: string;
|
||||
comment: string | null;
|
||||
/** コメントが存在するか */
|
||||
comment_exists?: boolean;
|
||||
/** 引用データか */
|
||||
is_quotation?: boolean;
|
||||
/** 最終投稿日時 */
|
||||
last_posted_datetime?: string;
|
||||
/** デフォルトで非表示か */
|
||||
hidden_by_default?: boolean;
|
||||
};
|
||||
|
||||
export type UnyohubResponse = UnyohubData[];
|
||||
|
||||
Reference in New Issue
Block a user