import { View, Text, StyleSheet, Pressable, Image, ImageSourcePropType, TouchableWithoutFeedback, Keyboard, ActivityIndicator } from 'react-native'; import React, { useState, useEffect, useRef, useMemo } from 'react'; import { SafeAreaView } from 'react-native-safe-area-context'; import MapView from 'react-native-maps'; import * as Location from 'expo-location'; import { router, useLocalSearchParams } from 'expo-router'; import { ArrowIconSvg, CheckMarkLogoSvg } from '../global/SVG'; import NormalInput from '../global/normal_input'; import BottomSheet, { BottomSheetScrollView } from '@gorhom/bottom-sheet'; import { chargeStationService } from '../../service/chargeStationService'; import { PROVIDER_GOOGLE, Marker, Region } from 'react-native-maps'; import { calculateDistance } from '../global/distanceCalculator'; interface TabItem { imgURL?: ImageSourcePropType | undefined; date: string; time: string; chargeStationName: string; chargeStationAddress: string; distance: string; stationID?: string; longitude?: number; latitude?: number; lat?: number; lng?: number; } const dummyTabItems: TabItem[] = [ { imgURL: require('../../assets/dummyStationPicture.png'), date: '今天', time: '16:30', chargeStationName: '觀塘偉業街充電站', chargeStationAddress: '九龍觀塘偉業街143號地下', distance: '400米', latitude: 22.31337, longitude: 114.21823 }, { imgURL: require('../../assets/dummyStationPicture5.jpeg'), date: '3月15', time: '17:45', chargeStationName: '香港沙頭角農莊', chargeStationAddress: '香港沙頭角農莊停車場', distance: '680米', latitude: 22.53898, longitude: 114.21319 }, { imgURL: require('../../assets/dummyStationPicture4.jpeg'), date: '3月15', time: '17:45', chargeStationName: '黃竹坑香葉道充電站', chargeStationAddress: '黃竹坑香葉道44號地下', distance: '680米', latitude: 22.24839, longitude: 114.16303 } ]; const SearchResultComponent = () => { const [region, setRegion] = useState({ latitude: 22.302711, // Default to Hong Kong coordinates longitude: 114.177216, latitudeDelta: 0.01, longitudeDelta: 0.01 }); const [errorMsg, setErrorMsg] = useState(null); const [searchInput, setSearchInput] = useState(''); const sheetRef = useRef(null); const snapPoints = useMemo(() => ['25%', '65%'], []); const mapRef = useRef(null); const params = useLocalSearchParams(); const [isLoading, setIsLoading] = useState(true); const [filteredItems, setFilteredItems] = useState([]); useEffect(() => { if (params.latitude && params.longitude) { setRegion({ latitude: parseFloat(params.latitude as string), longitude: parseFloat(params.longitude as string), latitudeDelta: 0.01, longitudeDelta: 0.01 }); } else { (async () => { let { status } = await Location.requestForegroundPermissionsAsync(); if (status !== 'granted') { setErrorMsg('Permission to access location was denied'); return; } let myLocation = await Location.getLastKnownPositionAsync({}); if (myLocation) { setRegion({ latitude: myLocation.coords.latitude, longitude: myLocation.coords.longitude, latitudeDelta: 0.01, longitudeDelta: 0.01 }); } })(); } }, []); useEffect(() => { if (mapRef.current && region) { mapRef.current.animateToRegion(region, 1000); } }, [region]); useEffect(() => { if (searchInput === '') { setFilteredItems([]); } else { const filteredData = dummyTabItems.filter((item) => item.chargeStationName.includes(searchInput.toLocaleUpperCase()) ); setFilteredItems(filteredData); } }, [searchInput]); if (errorMsg) { return ( {errorMsg} ); } const handleRegionChange = (newRegion: Region) => { if (mapRef.current) { mapRef.current.animateToRegion(newRegion, 1000); } setRegion(newRegion); sheetRef.current?.snapToIndex(0); }; // ************************************************************************************************ const [currentLocation, setCurrentLocation] = useState(null); const [stations, setStations] = useState([]); const [tabItems, setTabItems] = useState([]); 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); }; useEffect(() => { getCurrentLocation(); }, []); const fetchStations = async () => { setIsLoading(true); const fetchedStations = await chargeStationService.fetchChargeStations(); setStations(fetchedStations); if (currentLocation) { const TabItems = await Promise.all( fetchedStations.map(async (station) => { // const distance = await calculateDistance( // Number(station.StationLat), // Number(station.StationLng), // currentLocation // ); return { chargeStationAddress: station.Address, chargeStationName: station.StationName, lng: station.StationLng, lat: station.StationLat, date: '今天', stationID: station.StationID, imgURL: station.image }; }) ); setTabItems(TabItems); setIsLoading(false); } }; useEffect(() => { if (currentLocation) { fetchStations(); } }, [currentLocation]); const formatDistance = (distanceInMeters: number): string => { if (distanceInMeters < 1000) { return `${Math.round(distanceInMeters)}米`; } else { const distanceInKm = distanceInMeters / 1000; return `${distanceInKm.toFixed(1)}公里`; } }; const stationImages = { //沙頭角 '2501161430118231000': require('../../assets/dummyStationPicture5.jpeg'), //黃竹坑 '2411291610329331000': require('../../assets/dummyStationPicture4.jpeg'), //觀塘 '2405311022116801000': require('../../assets/dummyStationPicture.png') }; // const imageSource = stationImages[stationID] || require('../../assets/dummyStationPicture.png'); // ************************************************************************************************************************************************ return ( { if (router.canGoBack()) { router.back(); } else { router.replace('/(auth)/(tabs)/(home)'); } }} > { setSearchInput(text); }} extendedStyle={styles.textInput} /> {filteredItems.length > 0 && ( {filteredItems.map((item, index) => ( { setSearchInput(item.chargeStationName); setFilteredItems([]); handleRegionChange({ latitude: item.lat, longitude: item.lng, latitudeDelta: 0.01, longitudeDelta: 0.01 }); }} style={({ pressed }) => [ styles.dropdownItem, pressed && styles.dropdownItemPress ]} > {item.chargeStationName} ))} )} {tabItems.map((item, index) => ( ))} {isLoading ? ( ) : ( tabItems .filter((item) => item.chargeStationName.includes(searchInput.toUpperCase())) .map((item, index) => { return ( { handleRegionChange({ latitude: item.lat, longitude: item.lng, latitudeDelta: 0.01, longitudeDelta: 0.01 }); router.push({ pathname: '/resultDetailPage', params: { imageSource: item.imgURL as string, chargeStationAddress: item.chargeStationAddress, chargeStationID: item.stationID, chargeStationName: item.chargeStationName, stationLat: item.lat, stationLng: item.lng } }); }} style={({ pressed }) => [ styles.container, { backgroundColor: pressed ? '#e7f2f8' : '#ffffff' } ]} > {item.chargeStationName} {item.chargeStationAddress} Walk-in {/* {item.distance} */} ); }) )} ); }; export default SearchResultComponent; const styles = StyleSheet.create({ container: { flex: 1 }, map: { flex: 1, width: '100%', height: '100%' }, contentContainer: { backgroundColor: 'white' }, itemContainer: { padding: 6, margin: 6, backgroundColor: '#eee' }, image: { width: 100, height: 100, marginTop: 15, marginRight: 15, borderRadius: 10 }, textContainer: { flexDirection: 'column', gap: 8, marginTop: 22 }, rowContainer: { flexDirection: 'row' }, textInput: { width: '85%', maxWidth: '100%', fontSize: 16, padding: 20, paddingLeft: 0, borderLeftWidth: 0, borderTopWidth: 1, borderBottomWidth: 1, borderRightWidth: 1, borderBottomRightRadius: 12, borderTopRightRadius: 12, borderRadius: 0, borderColor: '#bbbbbb' }, leftArrowBackButton: { width: '15%', maxWidth: '100%', fontSize: 16, padding: 20, paddingLeft: 30, borderBottomLeftRadius: 12, borderTopLeftRadius: 12, borderColor: '#bbbbbb', borderTopWidth: 1, borderBottomWidth: 1, borderLeftWidth: 1, alignItems: 'center', justifyContent: 'center' }, dropdown: { backgroundColor: 'white', borderBottomLeftRadius: 12, borderBottomRightRadius: 12, borderLeftWidth: 1, borderRightWidth: 1, borderBottomWidth: 1, marginTop: 10, maxHeight: 200, width: '100%', position: 'absolute', top: 50, zIndex: 2, borderColor: '#bbbbbb' }, dropdownItem: { padding: 10, borderBottomWidth: 1, borderBottomColor: '#ddd' }, dropdownItemPress: { backgroundColor: '#e8f8fc' } });