Files
jrshikoku/components/OfficialPositionEditButton.tsx
harukin-expo-dev-env 1ecd026908 feat: Implement official position metadata handling and caching
- 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.
2026-09-15 13:48:21 +09:00

88 lines
2.3 KiB
TypeScript

import React, { FC } from "react";
import { Text, TouchableOpacity } from "react-native";
import { SheetManager } from "react-native-actions-sheet";
import { useThemeColors } from "@/lib/theme";
import {
buildOfficialPositionEditUrl,
type OfficialPositionEditFrom,
} from "@/lib/officialPositionEditUrl";
import { useNotification } from "@/stateBox/useNotifications";
import { useTrainMenu } from "@/stateBox/useTrainMenu";
import type { NavigateFunction } from "@/types";
type Props = {
positionId?: string | null;
navigate: NavigateFunction;
from?: OfficialPositionEditFrom;
closeEachTrainInfo?: boolean;
compact?: boolean;
};
/**
* Admin-only entry point to the canonical OfficialPosition Frontend page.
*
* The button is rendered only after Native permission and environment config
* are ready. The Frontend performs its own permission check again after the
* WebView opens the URL.
*/
export const OfficialPositionEditButton: FC<Props> = ({
positionId,
navigate,
from,
closeEachTrainInfo = false,
compact = false,
}) => {
const {
updatePermission,
officialPositionConfig,
officialPositionConfigReady,
} = useTrainMenu();
const { expoPushToken } = useNotification();
const { fixed, colors } = useThemeColors();
const uri = officialPositionConfigReady
? buildOfficialPositionEditUrl(
positionId,
expoPushToken,
officialPositionConfig,
from,
)
: undefined;
if (!updatePermission || !uri) return null;
return (
<TouchableOpacity
accessibilityRole="button"
accessibilityLabel="Official Positionを編集"
onPress={() => {
if (closeEachTrainInfo) SheetManager.hide("EachTrainInfo");
navigate("generalWebView", {
uri,
useExitButton: false,
});
}}
style={{
minHeight: compact ? 0 : 40,
minWidth: compact ? 0 : 68,
paddingHorizontal: compact ? 0 : 12,
marginHorizontal: 4,
borderRadius: 6,
alignItems: "center",
justifyContent: "center",
backgroundColor: compact ? "transparent" : fixed.primary,
}}
>
<Text
style={{
color: fixed.textOnPrimary,
fontSize: compact ? 12 : 14,
fontWeight: "bold",
}}
>
編集
</Text>
</TouchableOpacity>
);
};