| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267 |
- import { View, Text, ScrollView, Dimensions, ActivityIndicator } from 'react-native';
- import React, { useEffect, useMemo, useState } from 'react';
- import NormalButton from './normal_button';
- import Svg, { Path } from 'react-native-svg';
- import { BookingIconSvg } from './SVG';
- import { chargeStationService } from '../../service/chargeStationService';
- import extractedInfoStore from '../../providers/extractedReservationInfo_store';
- import { router } from 'expo-router';
- import { useQuery, QueryClient, QueryClientProvider } from '@tanstack/react-query';
- const queryClient = new QueryClient();
- const calculateResponsivePadding = () => {
- const screenHeight = Dimensions.get('window').height;
- return screenHeight * 0.01; // 3% of screen height, adjust as needed
- };
- const RecentBookedRowItems = ({
- chargingStationName,
- chargingStationAddress,
- chargeStationID
- }: {
- chargingStationName: string;
- chargingStationAddress: string;
- chargeStationID: string;
- }) => (
- <View
- style={{
- flexDirection: 'row',
- alignItems: 'center'
- }}
- >
- <BookingIconSvg />
- <View
- style={{
- flexDirection: 'row',
- justifyContent: 'space-between',
- flex: 1,
- borderBottomWidth: 0.5,
- paddingVertical: calculateResponsivePadding(),
- borderColor: '#ccc',
- borderRadius: 8
- }}
- >
- <View
- style={{
- marginLeft: 15,
- gap: 3
- }}
- >
- <Text
- style={{
- fontSize: 16,
- color: '#222222'
- }}
- >
- {chargingStationName}
- </Text>
- <Text
- style={{
- fontSize: 14,
- color: '#888888'
- }}
- >
- {chargingStationAddress}
- </Text>
- </View>
- <NormalButton
- title={<Text style={{ color: '#061E25' }}>重新預約</Text>}
- onPress={() =>
- router.push({
- pathname: '/resultDetailPage',
- params: {
- chargeStationAddress: chargingStationAddress,
- chargeStationID: chargeStationID,
- chargeStationName: chargingStationName
- }
- })
- }
- buttonPressedStyle={{
- backgroundColor: '#CFDEE4'
- }}
- extendedStyle={{
- backgroundColor: '#E3F2F8',
- paddingHorizontal: 16,
- paddingVertical: 1,
- borderRadius: 8
- }}
- />
- </View>
- </View>
- );
- const fetchRecentBookings = async (retryCount = 0) => {
- try {
- // Fetch user's all reservations
- const reservationResponse = await chargeStationService.fetchReservationHistories();
- if (!reservationResponse || reservationResponse.length === 0) {
- console.log('No reservation data returned');
- return [];
- }
- // Find the two closest reservations
- const now = new Date();
- const closestReservations = reservationResponse
- .sort((a, b) => {
- const diffA = Math.abs(new Date(a.end_time) - now);
- const diffB = Math.abs(new Date(b.end_time) - now);
- return diffA - diffB;
- })
- .slice(0, 2);
- // Fetch all charge station info
- const allStations = await chargeStationService.fetchAllChargeStations();
- if (!allStations) {
- console.log('No charge station data returned');
- return [];
- }
- //helper method to fetch all station
- const findStationByConnectorId = (allStations, targetConnectorId) => {
- console.log('Searching for connector ID:', targetConnectorId);
- const station = allStations.find((station) => {
- console.log(`Checking station ID: ${station.id}`);
- if (!station.snapshot || !station.snapshot.EquipmentInfos) {
- console.log('Station snapshot or EquipmentInfos is missing, skipping...');
- return false;
- }
- return station.snapshot.EquipmentInfos.some((equipment) => {
- console.log(` Checking equipment ID: ${equipment.EquipmentID}`);
- if (!equipment.ConnectorInfos) {
- console.log(' ConnectorInfos is missing, skipping...');
- return false;
- }
- return equipment.ConnectorInfos.some((connector) => {
- console.log(` Checking connector ID: ${connector.ConnectorID}`);
- const isMatch = connector.ConnectorID === targetConnectorId;
- if (isMatch) console.log(' Match found!');
- return isMatch;
- });
- });
- });
- if (station) {
- console.log('Matching station found:', station.id);
- } else {
- console.log('No matching station found');
- }
- return station;
- };
- // Extract station IDs from the closest reservations
- const stationIds = closestReservations
- .map((reservation) => {
- try {
- const snapshot = JSON.parse(reservation.snapshot);
- if (snapshot.stationID) {
- return snapshot.stationID;
- } else if (snapshot.connector) {
- const station = findStationByConnectorId(allStations, snapshot.connector);
- return station ? station.id : null;
- }
- return null;
- } catch (error) {
- console.error('Error processing reservation:', error);
- return null;
- }
- })
- .filter((id) => id !== null);
- if (stationIds.length === 0) {
- console.log('No valid station IDs found');
- return [];
- }
- // Filter and extract station information
- const extractedInfo = stationIds
- .map((id) => allStations.find((station) => station.id === id))
- .filter((station) => station !== undefined)
- .map((station) => ({
- stationID: station.id,
- address: station.snapshot.Address,
- stationName: station.snapshot.StationName
- }));
- // Update the store with extracted information
- extractedInfoStore.getState().setExtractedInfo(extractedInfo);
- return extractedInfo;
- } catch (error) {
- console.error(`Error in fetchRecentBookings (attempt ${retryCount + 1}):`, error);
- if (retryCount < 2) {
- // Retry up to 3 times (0, 1, 2)
- console.log(`Retrying... (attempt ${retryCount + 2})`);
- return fetchRecentBookings(retryCount + 1);
- } else {
- console.log('Max retries reached. Returning empty array.');
- return [];
- }
- }
- };
- const RecentlyBookedScrollView = () => {
- const {
- data: extractedInfo,
- isLoading,
- error
- } = useQuery('recentBookings', () => fetchRecentBookings(), {
- staleTime: 5 * 60 * 1000, // 5 minutes
- cacheTime: 10 * 60 * 1000, // 10 minutes
- retry: 3, // This will work alongside our custom retry logic
- retryDelay: 1000 // Wait 1 second between retries
- });
- const memoizedExtractedInfo = useMemo(() => extractedInfo || [], [extractedInfo]);
- if (isLoading) {
- return <ActivityIndicator color="#34657b" />;
- }
- if (error) {
- console.log('Error fetching data:', error);
- return <Text>Error loading recent bookings. Please try again later.</Text>;
- }
- return (
- <View className="py-6 flex-column">
- <Text
- style={{
- fontWeight: 400,
- fontSize: 16,
- color: '#222222',
- marginBottom: '5%'
- }}
- >
- 近期預約過
- </Text>
- {isLoading ? (
- <ActivityIndicator color="#34657b" />
- ) : (
- <View className="">
- {memoizedExtractedInfo.map((item, index) => (
- <RecentBookedRowItems
- key={`${item.stationName}+${index}`}
- chargingStationName={item.stationName}
- chargingStationAddress={item.address}
- chargeStationID={item.stationID}
- />
- ))}
- </View>
- )}
- </View>
- );
- };
- const RecentlyBookedScrollViewWithQueryClient = () => (
- <QueryClientProvider client={queryClient}>
- <RecentlyBookedScrollView />
- </QueryClientProvider>
- );
- export default RecentlyBookedScrollViewWithQueryClient;
|