import { View, Text, ScrollView, Image, useWindowDimensions, StyleSheet, Pressable, Platform, Linking, ActivityIndicator, Alert } from 'react-native'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { SceneMap, TabBar, TabView } from 'react-native-tab-view'; import NormalButton from '../global/normal_button'; import { router, useFocusEffect, useLocalSearchParams } from 'expo-router'; import { CheckMarkLogoSvg, DirectionLogoSvg, PreviousPageSvg } from '../global/SVG'; import { SafeAreaView } from 'react-native-safe-area-context'; import { chargeStationService } from '../../service/chargeStationService'; import * as Location from 'expo-location'; import { calculateDistance } from '../global/distanceCalculator'; import { ChargingDetails, Remark, PriceWeek, Special } from '../../service/type/chargeStationType'; interface ChargingStationTabViewProps { titles: string[]; pricemodel_id: string; } interface ChargingPeriod{ event_name: string; price: number; from: string; to: string; } const ChargingStationTabView: React.FC = ({ titles, pricemodel_id }) => { const layout = useWindowDimensions(); const [list, setList] = useState([]) const [strWeek, setStrWeek] = useState('') // 添加AM/PM标识但保持24小时制 const addPeriodToTime = (timeString: string): string => { // 假设输入格式为 HH.mm 或 HH:mm const [hours] = timeString.split(/[.:]/).map(Number); if (isNaN(hours)) return timeString; const period = hours >= 12 ? 'PM' : 'AM'; return `${timeString}${period}`; }; useEffect(() => { chargeStationService.fetchElectricityPrice(pricemodel_id || 'a').then(res => { const date = new Date(); const str = (date.toLocaleString('en-US', { weekday: 'short' })).toLowerCase(); setStrWeek(date.toLocaleString('zh', { weekday: 'long' })) const newList = [] as ChargingPeriod[] res?.forEach((item) => { const obj = item[str as keyof PriceWeek] newList.push({event_name: item.event_name, price: obj.price, from: addPeriodToTime(obj.from),to: addPeriodToTime(obj.to)}) setList(newList) }) }) }, [pricemodel_id]) //tab 1 const FirstRoute = () => ( 時段 價格(/度) { list.map((item, index) => ( {item.from} - {item.to} ${item.price} )) } ); //tab 2 const SecondRoute = () => ( ); const renderScene = SceneMap({ firstRoute: FirstRoute, secondRoute: SecondRoute }); const [routes] = React.useState([ { key: 'firstRoute', title: titles[0] }, { key: 'secondRoute', title: titles[1] } ]); const [index, setIndex] = React.useState(0); const renderTabBar = (props: any) => ( ); return ( ( {route.title} ) }} /> ); }; const ResultDetailPageComponent = () => { const params = useLocalSearchParams(); const chargeStationID = params.chargeStationID as string; const chargeStationName = params.chargeStationName as string; const chargeStationAddress = params.chargeStationAddress as string; const pricemodel_id = params.pricemodel_id as string; const imageSourceProps = params.imageSource; const stationLng = params.stationLng as string; const stationLat = params.stationLat as string; const [isLoading, setIsLoading] = useState(true); const [imageSource, setImageSource] = useState(); const [currentLocation, setCurrentLocation] = useState(null); const [price, setPrice] = useState(''); const [newAvailableConnectors, setNewAvailableConnectors] = useState([]); useEffect(() => { const imgObj = imageSourceProps? {uri: imageSourceProps} : require('../../assets/dummyStationPicture.png') setImageSource(imgObj); }, [imageSourceProps]) useEffect(() => { const fetchPrice = async () => { try { const price = await chargeStationService.fetchChargeStationPrice(chargeStationID); setPrice(price); } catch (error) { console.error('Error fetching price:', error); } }; const getCurrentLocation = async () => { let { status } = await Location.requestForegroundPermissionsAsync(); if (status !== 'granted') { console.error('Permission to access location was denied'); return; } let location = await Location.getLastKnownPositionAsync({}); setCurrentLocation(location); }; getCurrentLocation(); fetchPrice(); }, []); useFocusEffect( useCallback(() => { setIsLoading(true); let isMounted = true; // Simple cleanup flag const fetchAllConnectors = async () => { try { const newAvailableConnectors = await chargeStationService.NewfetchAvailableConnectors(); // Only update state if component is still mounted if (isMounted) { setNewAvailableConnectors(newAvailableConnectors); } } catch (error) { console.error('Fetch error:', error); } }; fetchAllConnectors(); setIsLoading(false); // Simple cleanup - prevents state updates if component unmounts return () => { isMounted = false; }; }, []) // Add any missing dependencies here if needed ); const handleNavigationPress = (StationLat: string, StationLng: string) => { console.log('starting navigation press in resultDetail', StationLat, StationLng); if (StationLat && StationLng) { const label = encodeURIComponent(chargeStationName); const googleMapsUrl = `https://www.google.com/maps/search/?api=1&query=${StationLat},${StationLng}`; // Fallback URL for web browser const webUrl = `https://www.google.com/maps/dir/?api=1&destination=${StationLat},${StationLng}`; Linking.canOpenURL(googleMapsUrl) .then((supported) => { if (supported) { Linking.openURL(googleMapsUrl); } else { Linking.openURL(webUrl).catch((err) => { console.error('An error occurred', err); Alert.alert( 'Error', "Unable to open Google Maps. Please make sure it's installed on your device.", [{ text: 'OK' }], { cancelable: false } ); }); } }) .catch((err) => console.error('An error occurred', err)); } }; return ( { if (router.canGoBack()) { router.back(); } else { router.replace('./'); } }} > {chargeStationName} {chargeStationAddress} 路線 } onPress={() => handleNavigationPress(stationLat, stationLng)} extendedStyle={{ backgroundColor: '#E3F2F8', borderRadius: 61, paddingHorizontal: 20, paddingVertical: 6 }} /> Walk-In {/* {distance} */} 收費 ${price} 每度電 現時可用充電槍數目 {isLoading ? ( Loading... ) : ( // { newAvailableConnectors.find( (station: any) => station.stationID === chargeStationID )?.availableConnectors } )} 充電站資訊 ); }; export default ResultDetailPageComponent; const styles = StyleSheet.create({ text: { fontWeight: 300, color: '#000000' }, leftLable: { width: '70%', fontSize: 17, color:'#000000', textAlign: 'center' }, rightLable: { fontSize: 17, width: '30%', textAlign: 'center', borderLeftWidth: 1, paddingLeft: 0, }, });