Ian Fung 1 năm trước cách đây
mục cha
commit
ba2d4d90c3

+ 126 - 182
app/(auth)/(tabs)/(home)/scanQrPage.tsx

@@ -17,7 +17,7 @@ import { router } from 'expo-router';
 import { chargeStationService } from '../../../../service/chargeStationService';
 import { authenticationService } from '../../../../service/authService';
 import { walletService } from '../../../../service/walletService';
-
+import useUserInfoStore from '../../../../providers/userinfo_store';
 const { width: screenWidth, height: screenHeight } = Dimensions.get('window');
 
 const ChooseCar = ({ carData, loading, selectedCar, setSelectedCar }) => {
@@ -55,7 +55,7 @@ const ChooseCar = ({ carData, loading, selectedCar, setSelectedCar }) => {
                             <ActivityIndicator color="#34657b" />
                         </View>
                     ) : (
-                        <View className="w-full bg-[#000000B3]">
+                        <View className="w-screen  bg-[#000000B3]">
                             <View className="flex-row items-center justify-between mx-[5%] ">
                                 <Pressable
                                     className="pt-4 "
@@ -107,16 +107,18 @@ const ChooseCar = ({ carData, loading, selectedCar, setSelectedCar }) => {
     );
 };
 const ScanQrPage = () => {
+    const { userID, setUserID } = useUserInfoStore();
     // State declarations
     const [permission, requestPermission] = useCameraPermissions();
     const [scanned, setScanned] = useState(false);
     const viewRef = useRef(null);
     const [scannedResult, setScannedResult] = useState('');
     const [selectedCar, setSelectedCar] = useState('');
-    const [userID, setUserID] = useState<string>('');
+
     const now = new Date();
-    const [loading, setLoading] = useState(false);
+    const [loading, setLoading] = useState(true);
     const [loading2, setLoading2] = useState(false);
+    const [loading3, setLoading3] = useState(false);
     const [carData, setCarData] = useState([]);
 
     // Effect for requesting camera permissions
@@ -132,7 +134,6 @@ const ScanQrPage = () => {
     // Effect for fetching user's cars
     useEffect(() => {
         const fetchAllCars = async () => {
-            setLoading(true);
             try {
                 const response = await chargeStationService.getUserCars();
                 if (response) {
@@ -142,6 +143,7 @@ const ScanQrPage = () => {
                         name: item.car_type.name,
                         image: item.car_type.type_image_url
                     }));
+                    console.log('carTypes', carTypes);
                     // console.log('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', carTypes);
                     let updatedCarTypes = [...carTypes];
                     for (let i = 0; i < carTypes.length; i++) {
@@ -153,6 +155,7 @@ const ScanQrPage = () => {
                         };
                     }
                     setCarData(updatedCarTypes);
+                    console.log('updatedCarTypes', updatedCarTypes);
                     return true;
                 }
             } catch (error) {
@@ -164,23 +167,6 @@ const ScanQrPage = () => {
         fetchAllCars();
     }, []);
 
-    // Effect for fetching user ID
-    useEffect(() => {
-        const fetchID = async () => {
-            try {
-                const response = await authenticationService.getUserInfo();
-                if (response) {
-                    setUserID(response.data.id);
-                } else {
-                    console.log('fail to set user ID');
-                }
-            } catch (error) {
-                console.log(error);
-            }
-        };
-        fetchID();
-    }, []);
-
     if (!permission) {
         return <View />;
     }
@@ -193,34 +179,8 @@ const ScanQrPage = () => {
         );
     }
 
-    // // Function to handle barcode scanning
-    // const handleBarCodeScanned = ({ bounds, data, type }: { bounds: any; data: any; type: any }) => {
-    //     const { origin, size } = bounds;
-    //     // Calculate the size of the square transparent area
-    //     const transparentAreaSize = Math.min(screenWidth * 0.6, screenHeight * 0.3);
-    //     const transparentAreaX = (screenWidth - transparentAreaSize) / 2;
-    //     const transparentAreaY = (screenHeight - transparentAreaSize) / 2;
-
-    //     // Check if the barcode is within the transparent area
-    //     if (
-    //         origin.x >= transparentAreaX &&
-    //         origin.y >= transparentAreaY &&
-    //         origin.x + size.width <= transparentAreaX + transparentAreaSize &&
-    //         origin.y + size.height <= transparentAreaY + transparentAreaSize
-    //     ) {
-    //         setScanned(true);
-    //         setScannedResult(data);
-    //         Vibration.vibrate(100);
-    //         console.log(` type: ${type}   data: ${data}  typeofData ${typeof data}`);
-    //         startCharging(data);
-    //         setTimeout(() => {
-    //             setScanned(false);
-    //         }, 2000);
-    //     }
-    // };
-
     // Function to handle barcode scanning
-    const handleBarCodeScanned = ({ bounds, data, type }: { bounds: any; data: any; type: any }) => {
+    const handleBarCodeScanned = async ({ bounds, data, type }: { bounds: any; data: any; type: any }) => {
         const { origin, size } = bounds;
         // Calculate the size of the square transparent area
         const transparentAreaSize = Math.min(screenWidth * 0.6, screenHeight * 0.3);
@@ -238,90 +198,126 @@ const ScanQrPage = () => {
             setScannedResult(data);
             Vibration.vibrate(100);
             console.log(` type: ${type}   data: ${data}  typeofData ${typeof data}`);
-            //HERE I will not be startCharging, I will call a function to check
-            startCharging(data);
-            setTimeout(() => {
-                setScanned(false);
-            }, 2000);
-        }
-    };
-    //WAIT FOR KUN TO CREATE ANOTHER API,
-    //USE THE NEW API FOR SCAN QR CODE FUNCTIONALITY
-    // ***********************************************************
-    // **************************************************************
-    // **************************************************************
-    // **************************************************************
-    // **************************************************************
-    // **************************************************************
-    // **************************************************************
-    // **************************************************************
-    const checkCurrentReservation = async () => {
-        const now = new Date();
-        try {
-            console.log('i am checking current reservation');
-            const response = await chargeStationService.fetchReservationHistories();
-            if (response) {
-                //check if any reservation is within 15 minutes
-                console.log('response of checkCurrentReservation', response);
-                const filteredResponse = response.filter((r) => {
-                    const bookTime = new Date(r.book_time);
-                    const fifteenMinutesAfterBookTime = new Date(bookTime.getTime() + 15 * 60 * 1000);
-                    const isWithin15MinutesAndStatus6 =
-                        now > bookTime && now <= fifteenMinutesAfterBookTime && r.status.id === '6';
-                    return isWithin15MinutesAndStatus6;
-                });
-                if (filteredResponse.length > 0) {
-                    console.log('there is a reservation within 15 minutes');
-                    return filteredResponse;
-                }
-            }
-            //meaning no reservation within 15 minutes
-            else {
-                console.log('no reservation within 15 minutes');
-                return false;
-            }
-        } catch (error) {
-            console.log(error);
-        }
-    };
 
-    const checkQrCode = async (data: string) => {
-        setLoading2(true);
-        const connectorID = data;
-        try {
-            const response = await checkCurrentReservation();
-            if (response) {
-                console.log('checking if scan code is for this reservation, from checkQrCode', response);
-                //if there is a reservation within 15 minutes
-                const checkIfScanCodeIsForThisReservation = response.connector.id === data;
-                if (checkIfScanCodeIsForThisReservation) {
-                    startCharging(data);
-                    return true;
-                } else {
-                    console.log(
-                        'The user indeed has a valid reservation, but the reservation is not for this charging machine.'
+            try {
+                const response = await chargeStationService.getTodayReservation();
+                if (response) {
+                    const now = new Date();
+
+                    const onlyThisConnector = response.filter(
+                        (reservation: any) => reservation.connector.ConnectorID === data
                     );
-                    Alert.alert('您預約了另一座充電座\n請前往正確的充電座進行充電。');
-                    return false;
+
+                    onlyThisConnector.sort((a: any, b: any) => {
+                        const timeA = new Date(a.book_time).getTime();
+                        const timeB = new Date(b.book_time).getTime();
+                        return timeA - timeB;
+                    });
+
+                    let previousReservation = null;
+                    let upcomingReservation = null;
+
+                    for (let i = 0; i < onlyThisConnector.length; i++) {
+                        const reservationTime = new Date(onlyThisConnector[i].book_time).getTime();
+                        if (reservationTime <= now.getTime()) {
+                            previousReservation = onlyThisConnector[i];
+                        } else {
+                            upcomingReservation = onlyThisConnector[i];
+                            break;
+                        }
+                    }
+
+                    const relevantReservations = [previousReservation || null, upcomingReservation || null];
+
+                    console.log('Relevant reservations:', relevantReservations);
+
+                    const getNearestSlot = (date: Date) => {
+                        const minutes = date.getMinutes();
+                        const nearestSlot = new Date(date);
+                        nearestSlot.setMinutes(minutes < 30 ? 0 : 30);
+                        nearestSlot.setSeconds(0);
+                        nearestSlot.setMilliseconds(0);
+                        return nearestSlot;
+                    };
+
+                    const currentSlot = getNearestSlot(now);
+                    const nextSlot = new Date(currentSlot.getTime() + 30 * 60 * 1000);
+
+                    const AreOrdersAdjacentToNow = relevantReservations.map((reservation, index) => {
+                        if (!reservation) return false;
+
+                        const reservationTime = new Date(reservation.book_time);
+                        return index === 0
+                            ? reservationTime.getTime() === currentSlot.getTime()
+                            : reservationTime.getTime() === nextSlot.getTime();
+                    });
+
+                    console.log('AreOrdersAdjacentToNow:', AreOrdersAdjacentToNow);
+
+                    if (!AreOrdersAdjacentToNow[0] && !AreOrdersAdjacentToNow[1]) {
+                        console.log('Charging machine is available. Starting charging process...');
+                        startCharging(data);
+                    } else if (AreOrdersAdjacentToNow[0]) {
+                        const previousReservation = relevantReservations[0];
+                        if (previousReservation && previousReservation.user.id === userID) {
+                            const reservationTime = new Date(previousReservation.book_time);
+                            const timeDifference = now.getTime() - reservationTime.getTime();
+                            const minutesDifference = timeDifference / (1000 * 60);
+
+                            if (minutesDifference <= 15) {
+                                console.log('User arrived within 15 minutes of their reservation.');
+                                startCharging(data);
+                            } else {
+                                console.log('User arrived more than 15 minutes late for their reservation.');
+                                if (!AreOrdersAdjacentToNow[1]) {
+                                    console.log('Next slot is available. Allowing charging despite late arrival.');
+                                    startCharging(data);
+                                } else {
+                                    Alert.alert(
+                                        '預約已過期',
+                                        '您的預約時間已經過期,且下一個時段已被預約。請重新預約。'
+                                    );
+                                    console.log('Next slot is not available. Charging not allowed.');
+                                }
+                            }
+                        } else {
+                            Alert.alert('無法使用', '此充電槍已經被預約,請選擇其他位置');
+                        }
+                    } else if (AreOrdersAdjacentToNow[1]) {
+                        const upcomingReservation = relevantReservations[1];
+                        if (upcomingReservation && upcomingReservation.user.id === userID) {
+                            const minutesUntilReservation =
+                                (new Date(upcomingReservation.book_time).getTime() - now.getTime()) / (1000 * 60);
+                            if (minutesUntilReservation <= 5) {
+                                console.log('User arrived slightly early for their upcoming reservation.');
+                                startCharging(data);
+                            } else {
+                                Alert.alert(
+                                    '預約時間未到',
+                                    `您的預約時間還有 ${Math.round(minutesUntilReservation)} 分鐘開始。請稍後再試。`
+                                );
+                            }
+                        } else {
+                            Alert.alert('已被預約', '此充電槍已被其他用戶預約。請選擇其他位置。');
+                        }
+                    } else {
+                        Alert.alert('無法使用', '此充電槍目前無法使用。請選擇其他位置或稍後再試。');
+                    }
+                } else {
+                    console.log('No response from getTodayReservation');
+                    Alert.alert('系統錯誤', '無法獲取預約信息。請稍後再試。');
                 }
-            } else {
-                //if there is no reservation within 15 minutes
-                //meaing these are walk in clients wanting to charge
-                //first, i have to check the current time,
-                //if the availability of current time slot is not available then i return alert
+            } catch (error) {
+                console.error("Error fetching today's reservations:", error);
+                Alert.alert('系統錯誤', '發生未知錯誤。請稍後再試。');
             }
-        } catch (error) {
-            console.log(error);
+
+            setTimeout(() => {
+                setScanned(false);
+            }, 2000);
         }
     };
 
-    // **************************************************************
-    // **************************************************************
-    // **************************************************************
-    // **************************************************************
-    // **************************************************************
-    // **************************************************************
-    // **************************************************************
     //prepare data for submission
     const dataForSubmission = {
         stationID: '2405311022116801000',
@@ -333,7 +329,8 @@ const ScanQrPage = () => {
         total_fee: 0,
         promotion_code: '',
         car: selectedCar,
-        type: 'walking'
+        type: 'walking',
+        is_ic_call: false
     };
 
     const startCharging = async (scanResult: string) => {
@@ -353,7 +350,8 @@ const ScanQrPage = () => {
                 dataForSubmission.total_fee,
                 dataForSubmission.promotion_code,
                 dataForSubmission.car,
-                dataForSubmission.type
+                dataForSubmission.type,
+                dataForSubmission.is_ic_call
             );
 
             if (response) {
@@ -367,60 +365,6 @@ const ScanQrPage = () => {
             console.log('Failed to start charging:', error);
         }
     };
-    const abc = new Date();
-
-    async function checkIfConnectorIsAvailable(stationID: string) {
-        try {
-            const apiResponse = await chargeStationService.fetchSpecificChargeStation(stationID);
-            if (apiResponse) {
-                console.log('apiResponse', apiResponse);
-                const inputDate = new Date();
-                const formattedDate =
-                    (inputDate.getMonth() + 1).toString().padStart(2, '0') +
-                    '/' +
-                    inputDate.getDate().toString().padStart(2, '0');
-
-                // Get the hours and minutes
-                const hours = inputDate.getHours();
-                const minutes = inputDate.getMinutes();
-
-                // Round down to the nearest 30-minute slot
-                const slotStart = `${hours.toString().padStart(2, '0')}:${minutes < 30 ? '00' : '30'}`;
-                console.log('slotStart', slotStart);
-
-                const findSlot = (date, start) => {
-                    const dayData = apiResponse.find((day) => day.date === date);
-                    if (!dayData) return null;
-
-                    return dayData.range.find((slot) => slot.start === start);
-                };
-
-                const currentSlot = findSlot(formattedDate, slotStart);
-                console.log('currentSlot', currentSlot);
-
-                let nextSlotStart;
-                if (slotStart.endsWith('30')) {
-                    nextSlotStart = `${(hours + 1).toString().padStart(2, '0')}:00`;
-                } else {
-                    nextSlotStart = `${hours.toString().padStart(2, '0')}:30`;
-                }
-                const nextSlot = findSlot(formattedDate, nextSlotStart);
-                console.log('nextSlot', nextSlot);
-                return {
-                    currentSlot,
-                    nextSlot
-                };
-            } else {
-                console.log('no response from fetchSpecificChargeStation in scanQRcode Page');
-                return false;
-            }
-        } catch (error) {
-            console.log(error);
-        }
-    }
-
-    const adbc = checkIfConnectorIsAvailable('2405311022116801000');
-    console.log(adbc);
 
     return (
         <View style={styles.container} ref={viewRef}>

+ 8 - 4
app/_layout.tsx

@@ -1,11 +1,15 @@
 import { Stack } from 'expo-router/stack';
-import AuthProvider from '../context/AuthProvider';
+import AuthProvider, { useAuth } from '../context/AuthProvider';
 import { EXPO_PUBLIC_NODE_ENV } from '@env';
+import * as SecureStore from 'expo-secure-store';
 import { GestureHandlerRootView } from 'react-native-gesture-handler';
-import { useEffect } from 'react';
-import * as Linking from 'expo-linking';
-import { Alert } from 'react-native';
+import { useEffect, useState } from 'react';
+import { ActivityIndicator, View } from 'react-native';
+
 export default function RootLayout() {
+    const [isLoading, setIsLoading] = useState(true);
+    const { user } = useAuth();
+
     return (
         <GestureHandlerRootView style={{ flex: 1 }}>
             <AuthProvider>

+ 5 - 6
component/accountPages/myVehiclePageComponent.tsx

@@ -27,9 +27,8 @@ const VehicleRow = ({ car, deviceWidth, deviceHeight, onPress }) => (
                     height: '100%'
                 }}
                 resizeMode="contain"
-                source={{
-                    uri: car.processedImageUrl || 'https://via.placeholder.com/150'
-                }}
+                // source={{  uri: car.processedImageUrl || 'https://via.placeholder.com/150'}}
+                source={require('../../assets/car.png')}
             />
             <View className="flex-row items-center">
                 <View className="flex-1 flex-col pl-2">
@@ -65,7 +64,7 @@ const MyVehiclePageComponent = () => {
             for (let i = 0; i < updatedVehicles.length; i++) {
                 const car = updatedVehicles[i];
                 const processedUrl = await chargeStationService.getProcessedImageUrl(car.car_type.type_image_url);
-
+                console.log('processedUrl', processedUrl);
                 updatedVehicles[i] = {
                     ...car,
                     processedImageUrl: processedUrl
@@ -122,8 +121,8 @@ const MyVehiclePageComponent = () => {
                     <>
                         <View className="items-center">
                             <Image
-                                // source={require('../../assets/car.png')}
-                                source={{ uri: defaultCar?.processedImageUrl }}
+                                source={require('../../assets/car.png')}
+                                // source={{ uri: defaultCar?.processedImageUrl }}
                                 resizeMode="contain"
                                 style={{ width: deviceWidth * 0.8, height: deviceHeight * 0.25 }}
                             />

+ 4 - 2
component/bookingMenuPage/makingBookingPageComponent.tsx

@@ -95,6 +95,7 @@ const MakingBookingPageComponent = () => {
 
         getCurrentLocation();
     }, []);
+
     const formatDistance = (distanceInMeters: number): string => {
         if (distanceInMeters < 1000) {
             return `${Math.round(distanceInMeters)}米`;
@@ -328,7 +329,7 @@ const MakingBookingPageComponent = () => {
                 }
 
                 const connectorIDs = rangeObject.connectors
-                    .filter((connector) => connector.Status === 2)
+                    .filter((connector) => connector.Status === '待机')
                     .map((connector) => connector.ConnectorID);
 
                 console.log('connectorIDs', connectorIDs);
@@ -755,7 +756,8 @@ const MakingBookingPageComponent = () => {
                                     }}
                                     extendedStyle={{
                                         borderColor: '#34667c',
-                                        marginTop: 4
+                                        marginTop: 4,
+                                        padding: 12
                                     }}
                                 />
 

+ 3 - 2
component/chargingPage/chargingHurryUpPageComponent.tsx

@@ -1,4 +1,4 @@
-import { View, Text, ScrollView, StyleSheet, ActivityIndicator } from 'react-native';
+import { View, Text, ScrollView, StyleSheet, ActivityIndicator, Alert } from 'react-native';
 import React, { useEffect, useState } from 'react';
 import { SafeAreaView } from 'react-native-safe-area-context';
 import NormalButton from '../global/normal_button';
@@ -51,9 +51,10 @@ const ChargingHurryUpPageComponent = ({ data = {} }) => {
             console.log('startPayload', startPayload);
             const response = await chargeStationService.startCharging(startPayload);
             if (response) {
-                console.log('handleStartCharge begins, response received', startPayload);
+                console.log('handleStartCharge begins, response received:', response);
                 router.push('chargingPage');
             } else {
+                Alert.alert('啟動失敗');
                 console.log('啟動失敗');
             }
         } catch (error) {

+ 23 - 8
component/chargingPage/chargingPageComponent.tsx

@@ -144,10 +144,12 @@ const ChargingPageComponent = ({ data }) => {
                                     <ActivityIndicator />
                                 ) : (
                                     <Text style={styles.greenColor} className="font-bold text-base">
-                                        {displayKW(onGoingChargingData.CurrentA, onGoingChargingData.VoltageA)}kW
+                                        {/* {displayKW(onGoingChargingData.CurrentA, onGoingChargingData.VoltageA)}kW */}
+                                        {reservationData.connector.Power / 1000}kW
                                     </Text>
                                 )}
                             </View>
+
                             <View className="flex-1 flex-column items-center space-y-2">
                                 <BatteryIconSvg />
                                 <Text style={styles.grayColor} className="text-base">
@@ -157,11 +159,24 @@ const ChargingPageComponent = ({ data }) => {
                                     <ActivityIndicator />
                                 ) : (
                                     <Text style={styles.greenColor} className="font-bold text-base">
-                                        {displayKW(onGoingChargingData.CurrentA, onGoingChargingData.VoltageA)}kW
+                                        {onGoingChargingData &&
+                                        onGoingChargingData.VoltageA &&
+                                        onGoingChargingData.VoltageB &&
+                                        onGoingChargingData.VoltageC &&
+                                        onGoingChargingData.CurrentA &&
+                                        onGoingChargingData.CurrentB &&
+                                        onGoingChargingData.CurrentC
+                                            ? (
+                                                  (onGoingChargingData.VoltageA * onGoingChargingData.CurrentA +
+                                                      onGoingChargingData.VoltageB * onGoingChargingData.CurrentB +
+                                                      onGoingChargingData.VoltageC * onGoingChargingData.CurrentC) /
+                                                  1000
+                                              ).toFixed(2) + ' kW'
+                                            : '請見充電顯示螢幕'}
                                     </Text>
                                 )}
                             </View>
-                            <View className="flex-1 flex-column items-center space-y-2">
+                            {/* <View className="flex-1 flex-column items-center space-y-2">
                                 <TemperatureIconSvg />
                                 <Text style={styles.grayColor} className="text-base">
                                     溫度
@@ -173,7 +188,7 @@ const ChargingPageComponent = ({ data }) => {
                                         36°c
                                     </Text>
                                 )}
-                            </View>
+                            </View> */}
                         </View>
                         <View className="mx-[5%]">
                             <View className="h-[1px] w-[100%] bg-[#CCCCCC]" />
@@ -226,16 +241,16 @@ const ChargingPageComponent = ({ data }) => {
                     <View>
                         <NormalButton
                             onPress={() => {
-                                router.push('chargingPage');
+                                router.push('mainPage');
                             }}
                             title={
                                 <Text className="text-xl text-white" style={{ fontWeight: 900 }}>
-                                    完成充電
+                                    返回主頁
                                 </Text>
                             }
                         />
                     </View>
-                    <View>
+                    {/* <View>
                         <NormalButton
                             onPress={() => {
                                 router.push('/chargingPenaltyPage');
@@ -246,7 +261,7 @@ const ChargingPageComponent = ({ data }) => {
                                 </Text>
                             }
                         />
-                    </View>
+                    </View> */}
                 </View>
             </ScrollView>
         </SafeAreaView>

+ 9 - 1
component/chargingPage/paymentSummaryPageComponent.tsx

@@ -1,5 +1,6 @@
 import { View, Text, ScrollView, StyleSheet, Pressable } from 'react-native';
 import { SafeAreaView } from 'react-native-safe-area-context';
+import { Alert } from 'react-native';
 
 import NormalButton from '../global/normal_button';
 import { router, useLocalSearchParams } from 'expo-router';
@@ -96,6 +97,9 @@ const PaymentSummaryPageComponent = () => {
 
     const handleSubmitPayment = async () => {
         let type = 'reservation';
+        let is_ic_call = false;
+        console.log('i am handleSubmitPayment, connectorID:', connectorID);
+
         try {
             const response = await walletService.submitPayment(
                 stationID,
@@ -107,11 +111,15 @@ const PaymentSummaryPageComponent = () => {
                 total_fee,
                 promotion_code,
                 carID,
-                type
+                type,
+                is_ic_call
             );
             if (response.status === 200 || response.status === 201) {
                 console.log('submit payment successful');
                 router.push('/paymentFinishPage');
+            } else if (response.status === 400) {
+                console.log('400 error in paymentSummaryPageComponent');
+                Alert.alert('餘額不足', '您的餘額不足,請充值後再試。');
             } else {
                 console.log('submit payment failed:', response.status);
             }

+ 9 - 1
component/global/bookingTabViewComponent.tsx

@@ -29,6 +29,13 @@ const fetchReservationsAndStations = async () => {
 
 const processReservations = (reservations, allStations, isFuture): TabItem[] => {
     const now = new Date();
+    const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
+    const todayReservations = reservations.filter((reservation) => {
+        const reservationDate = new Date(reservation.book_time);
+        return reservationDate >= today && reservationDate < new Date(today.getTime() + 24 * 60 * 60 * 1000);
+    });
+    console.log("Today's reservations:", todayReservations);
+
     return reservations
         .filter((reservation) =>
             isFuture ? new Date(reservation.end_time) > now : new Date(reservation.end_time) < now
@@ -101,7 +108,8 @@ const BookingTabViewComponentInner: React.FC<BookingTabViewComponentProps> = ({
     }
 
     const tabItems = processReservations(data.reservations, data.stations, true);
-    console.log(tabItems);
+    console.log('tabItem', tabItems);
+
     const completedReservationTabItems = processReservations(data.reservations, data.stations, false);
 
     return (

+ 1 - 4
component/global/chargingStationTabView.tsx

@@ -22,10 +22,7 @@ export const ChargingStationTabView: React.FC<ChargingStationTabViewProps> = ({
     //tab 2
     const SecondRoute = () => (
         <ScrollView style={{ flex: 1, marginHorizontal: '5%' }}>
-            <Text className="text-lg " style={styles.text}>
-                Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do Lorem ipsum dolor sit amet, consectetur
-                adipiscing elit, sed do Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
-            </Text>
+            <Text className="text-lg " style={styles.text}></Text>
         </ScrollView>
     );
 

+ 2 - 1
component/global/chooseCarForChargingRow.tsx

@@ -41,7 +41,8 @@ const ChooseCarForChargingRow = ({
                 </>
             )}
             <View className="items-center justify-center pt-4 space-y-2 ">
-                <Image source={{ uri: image }} style={{ height: carHeight, width: carWidth }} />
+                {/* <Image source={{ uri: image }} style={{ height: carHeight, width: carWidth }} /> */}
+                <Image source={require('../../assets/car.png')} style={{ height: carHeight, width: carWidth }} />
                 <Text
                     style={{
                         fontSize: height < 700 ? 14 : 16,

+ 107 - 149
component/global/recentlyBookedScrollView.tsx

@@ -91,183 +91,141 @@ const RecentBookedRowItems = ({
     </View>
 );
 
-const fetchRecentBookings = async () => {
-    // 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 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 [];
+        }
 
-        const station = allStations.find((station) => {
-            console.log(`Checking station ID: ${station.id}`);
+        // 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 [];
+        }
 
-            if (!station.snapshot || !station.snapshot.EquipmentInfos) {
-                console.log('Station snapshot or EquipmentInfos is missing, skipping...');
-                return false;
-            }
+        //helper method to fetch all station
+        const findStationByConnectorId = (allStations, targetConnectorId) => {
+            console.log('Searching for connector ID:', targetConnectorId);
 
-            return station.snapshot.EquipmentInfos.some((equipment) => {
-                console.log(`  Checking equipment ID: ${equipment.EquipmentID}`);
+            const station = allStations.find((station) => {
+                console.log(`Checking station ID: ${station.id}`);
 
-                if (!equipment.ConnectorInfos) {
-                    console.log('  ConnectorInfos is missing, skipping...');
+                if (!station.snapshot || !station.snapshot.EquipmentInfos) {
+                    console.log('Station snapshot or EquipmentInfos 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;
-                });
-            });
-        });
+                return station.snapshot.EquipmentInfos.some((equipment) => {
+                    console.log(`  Checking equipment ID: ${equipment.EquipmentID}`);
 
-        if (station) {
-            console.log('Matching station found:', station.id);
-        } else {
-            console.log('No matching station found');
-        }
+                    if (!equipment.ConnectorInfos) {
+                        console.log('  ConnectorInfos is missing, skipping...');
+                        return false;
+                    }
 
-        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 equipment.ConnectorInfos.some((connector) => {
+                        console.log(`    Checking connector ID: ${connector.ConnectorID}`);
+                        const isMatch = connector.ConnectorID === targetConnectorId;
+                        if (isMatch) console.log('    Match found!');
+                        return isMatch;
+                    });
+                });
+            });
 
-                    return station ? station.id : null;
-                }
-                return null;
-            } catch (error) {
-                console.error('Error processing reservation:', error);
-                return null;
+            if (station) {
+                console.log('Matching station found:', station.id);
+            } else {
+                console.log('No matching station found');
             }
-        })
-        .filter((id) => id !== null);
 
-    if (stationIds.length === 0) {
-        console.log('No valid station IDs found');
-        return [];
-    }
+            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);
 
-    // 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
-        }));
+        if (stationIds.length === 0) {
+            console.log('No valid station IDs found');
+            return [];
+        }
 
-    // Update the store with extracted information
-    extractedInfoStore.getState().setExtractedInfo(extractedInfo);
-    return extractedInfo;
+        // 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 fetchRecentBookings = async () => {
-//     //fetch user's all reservations
-//     const reservationResponse = await chargeStationService.fetchReservationHistories();
-//     if (!reservationResponse) {
-//         console.log('No reservation data returned');
-//         return [];
-//     }
-
-//     // Find the two closest reservations
-//     const now = new Date();
-
-//     // PLAN A: I filter out reservations that has no station ID in the snapshot.
-//     const closestReservations = reservationResponse
-//         .filter((reservation) => {
-//             const snapshot = JSON.parse(reservation.snapshot);
-//             return snapshot.stationID !== undefined && snapshot.stationID !== null;
-//         })
-//         .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);
-
-//     //and the two closest reservation's station ID
-//     const stationIds = closestReservations.map((reservation) => {
-//         const snapshot = JSON.parse(reservation.snapshot);
-
-//         return snapshot.stationID;
-//     });
-//     // .filter((id) => id !== undefined);
-
-//     if (stationIds.length === 0) {
-//         console.log('No valid station IDs found');
-//         return [];
-//     }
-
-//     const stationsResponse = await chargeStationService.fetchAllChargeStations();
-
-//     if (!stationsResponse) {
-//         console.log('No charge station data returned');
-//         return [];
-//     }
-
-//     if (stationIds === undefined || stationIds.length === 0) {
-//         return [];
-//     }
-
-//     const filteredStations = stationIds.map((id) => stationsResponse.find((station) => station.id === id));
-
-//     const extractedInfo = filteredStations.map((station) => ({
-//         stationID: station.id,
-//         address: station.snapshot.Address,
-//         stationName: station.snapshot.StationName
-//     }));
-
-//     extractedInfoStore.getState().setExtractedInfo(extractedInfo);
-
-//     return extractedInfo;
-// };
-
 const RecentlyBookedScrollView = () => {
     const {
         data: extractedInfo,
         isLoading,
         error
-    } = useQuery('recentBookings', fetchRecentBookings, {
+    } = useQuery('recentBookings', () => fetchRecentBookings(), {
         staleTime: 5 * 60 * 1000, // 5 minutes
-        cacheTime: 10 * 60 * 1000 // 10 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.error('Error fetching data:', error);
+        return <Text>Error loading recent bookings. Please try again later.</Text>;
     }
 
     return (

+ 20 - 1
component/homePage/homePage.tsx

@@ -16,12 +16,31 @@ import { useContext, useEffect, useState } from 'react';
 import { authenticationService } from '../../service/authService';
 import { chargeStationService } from '../../service/chargeStationService';
 import { walletService } from '../../service/walletService';
+import useUserInfoStore from '../../providers/userinfo_store';
 interface HomePageProps {}
 
 const HomePage: React.FC<HomePageProps> = () => {
     const now = new Date();
-    console.log(now);
+
     const { user } = useContext(AuthContext);
+    const { userID, setUserID } = useUserInfoStore();
+
+    // Effect for fetching user ID
+    useEffect(() => {
+        const fetchID = async () => {
+            try {
+                const response = await authenticationService.getUserInfo();
+                if (response) {
+                    setUserID(response.data.id);
+                } else {
+                    console.log('fail to set user ID');
+                }
+            } catch (error) {
+                console.log(error);
+            }
+        };
+        fetchID();
+    }, []);
 
     return (
         <SafeAreaView edges={['top', 'left', 'right']} className="flex-1 bg-white">

+ 5 - 4
component/registrationMultiStepForm/formComponent/formPages/createWallet.tsx

@@ -65,7 +65,7 @@ const CreateWallet: React.FC<CreateWalletProps> = ({ goToNextPage }) => {
             try {
                 const result = await authenticationService.signUp(customerData);
                 console.log('handleNext in CreateWallet Page, i am sending this customerData', customerData);
-                if (result === true) {
+                if (result) {
                     goToNextPage();
                 } else {
                     Alert.alert('註冊錯誤', '註冊過程中出現錯誤,請稍後再試');
@@ -100,7 +100,7 @@ const CreateWallet: React.FC<CreateWalletProps> = ({ goToNextPage }) => {
             gender: signUpFormData.gender,
             birthday: signUpFormData.birthDateDay + '/' + signUpFormData.birthDateMonth + '/11',
             address: signUpFormData.address,
-            phone: signUpFormData.phone,
+            phone: parseInt(signUpFormData.phone, 10),
             isUberDriver: signUpFormData.isUberDriver
         },
         customerCarInfo: {
@@ -145,12 +145,13 @@ const CreateWallet: React.FC<CreateWalletProps> = ({ goToNextPage }) => {
                         onPress={handleNext}
                         extendedStyle={{}}
                     />
-                    <NormalButton
+                    {/* 收起按鈕 */}
+                    {/* <NormalButton
                         title={isLoading2 ? <ActivityIndicator /> : <Text style={{ color: '#888888' }}>略過</Text>}
                         onPress={handleNextWithSkip}
                         extendedStyle={{ backgroundColor: 'transparent' }}
                         buttonPressedStyle={{ backgroundColor: 'transparent' }}
-                    />
+                    /> */}
                 </View>
             </View>
         </>

+ 11 - 14
component/resultDetailPage/resultDetailPageComponent.tsx

@@ -45,12 +45,7 @@ const ChargingStationTabView: React.FC<ChargingStationTabViewProps> = ({ titles
     //tab 2
     const SecondRoute = () => (
         <ScrollView style={{ flex: 1, marginHorizontal: '5%' }}>
-            <Text className="text-lg " style={styles.text}>
-                Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et
-                dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip
-                ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu
-                fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident
-            </Text>
+            <Text className="text-lg " style={styles.text}></Text>
         </ScrollView>
     );
 
@@ -386,24 +381,26 @@ const ResultDetailPageComponent = () => {
                     >
                         <View className="flex-1 m-4">
                             <View className="flex-1 flex-row ">
-                                <View className=" flex-1 flex-column  justify-between">
+                                <View className=" flex-1 flex-column  ustify-between">
                                     <Text className="text-xl " style={styles.text}>
                                         收費
                                     </Text>
 
                                     <View className="flex-row items-center space-x-2">
-                                        <Text className="text-3xl text-[#02677D]">$20</Text>
-                                        <Text style={styles.text}>每15分鐘</Text>
+                                        <Text className="text-3xl text-[#02677D]">${price}</Text>
+                                        <Text style={styles.text}>每度電</Text>
                                     </View>
                                 </View>
                                 <View className="items-center justify-center">
                                     <View className="w-[1px] h-[60%] bg-[#CCCCCC]" />
                                 </View>
-                                <View className="flex-1 flex-column ">
-                                    <View className="flex-1"></View>
-                                    <View className="flex-row items-center ml-4 space-x-2 ">
-                                        <Text className="text-3xl text-[#02677D]">${price}</Text>
-                                        <Text style={styles.text}>每度電</Text>
+                                <View className=" flex-1 pl-4 flex-column  justify-between">
+                                    <Text className="text-xl " style={styles.text}>
+                                        可用充電槍數目
+                                    </Text>
+
+                                    <View className="flex-row items-center space-x-2">
+                                        <Text className="text-3xl text-[#02677D]">6</Text>
                                     </View>
                                 </View>
                             </View>

+ 30 - 28
context/AuthProvider.tsx

@@ -7,7 +7,7 @@ import axios from 'axios';
 import { EXPO_PUBLIC_API_URL } from '@env';
 import { User } from '../types/user';
 
-import {  authenticationService } from '../service/authService';
+import { authenticationService } from '../service/authService';
 
 type AuthProvider = {
     user: User | null;
@@ -20,7 +20,10 @@ function useProtectedRoute(user: User | null) {
     const segments = useSegments();
 
     useEffect(() => {
+        if (!segments.length) return;
+
         const inAuthGroup = segments[0] === '(auth)';
+
         if (!user && inAuthGroup) {
             router.replace('/login');
         } else if (user && !inAuthGroup) {
@@ -47,24 +50,29 @@ export function useAuth() {
 export default function AuthProvider({ children }: { children: ReactNode }) {
     const [user, setUser] = useState<User | null>(null);
 
+    useEffect(() => {
+        const checkToken = async () => {
+            const token = await SecureStore.getItemAsync('accessToken');
+            if (token) {
+                const userInfo = await getUserFromAccessToken();
+                if (userInfo) {
+                    setUser(userInfo);
+                }
+            }
+        };
+        checkToken();
+    }, []);
+
     const login = async (username: string, password: string) => {
         try {
-            const loggedInUser = await authenticationService.login(
-                username,
-                password
-            );
+            const loggedInUser = await authenticationService.login(username, password);
             if (loggedInUser) {
-                const userInfo = await getUserFromAccessToken();
-                if (userInfo) {
-                    setUser((prevUser) => ({
-                        ...prevUser,
-                        address: userInfo.address,
-                        birthday: userInfo.birthday,
-                        email: userInfo.email,
-                        gender: userInfo.gender,
-                        nickname: userInfo.nickname,
-                        phone: userInfo.phone
-                    }));
+                const token = await SecureStore.getItemAsync('accessToken');
+                if (token) {
+                    const userInfo = await getUserFromAccessToken();
+                    if (userInfo) {
+                        setUser(userInfo);
+                    }
                 }
                 return true;
             } else {
@@ -79,14 +87,11 @@ export default function AuthProvider({ children }: { children: ReactNode }) {
     const getUserFromAccessToken = async () => {
         const token = await SecureStore.getItemAsync('accessToken');
         try {
-            const res = await axios.get(
-                `${EXPO_PUBLIC_API_URL}/clients/customer`,
-                {
-                    headers: {
-                        Authorization: `Bearer ${token}`
-                    }
+            const res = await axios.get(`${EXPO_PUBLIC_API_URL}/clients/customer`, {
+                headers: {
+                    Authorization: `Bearer ${token}`
                 }
-            );
+            });
             const items = {
                 address: res.data.address,
                 birthday: res.data.birthday,
@@ -104,6 +109,7 @@ export default function AuthProvider({ children }: { children: ReactNode }) {
     const logout = async () => {
         try {
             await authenticationService.logout();
+            await SecureStore.deleteItemAsync('accessToken');
             setUser(null);
             router.replace('/login');
         } catch (error) {
@@ -113,9 +119,5 @@ export default function AuthProvider({ children }: { children: ReactNode }) {
 
     useProtectedRoute(user);
 
-    return (
-        <AuthContext.Provider value={{ user, login, logout, setUser }}>
-            {children}
-        </AuthContext.Provider>
-    );
+    return <AuthContext.Provider value={{ user, login, logout, setUser }}>{children}</AuthContext.Provider>;
 }

+ 14 - 0
providers/userinfo_store.tsx

@@ -0,0 +1,14 @@
+import { create } from 'zustand';
+
+interface UserInfoState {
+    userID: string;
+    setUserID: (id: string) => void;
+}
+
+const useUserInfoStore = create<UserInfoState>((set) => ({
+    userID: '',
+
+    setUserID: (id: string) => set({ userID: id })
+}));
+
+export default useUserInfoStore;

+ 2 - 1
service/authService.tsx

@@ -176,7 +176,8 @@ class AuthenticationService {
                     Accept: 'application/json'
                 }
             });
-
+            console.log('Signup response.data:', response.data);
+            console.log('Signup response.status:', response.status);
             if (response.status === 200 || response.status === 201) {
                 console.log('Signup successful');
                 return true;

+ 18 - 0
service/chargeStationService.tsx

@@ -356,6 +356,24 @@ class ChargeStationService {
         }
     }
 
+    async getTodayReservation() {
+        try {
+            const response = await axios.get(`${this.apiUrl}/clients/reservation/today`, {
+                headers: {
+                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
+                }
+            });
+            if (response.status === 200 || response.status === 201) {
+                // console.log('getTodayReservation response.data: ', response.data);
+                return response.data;
+            } else {
+                console.log('invalid response');
+            }
+        } catch (error) {
+            console.log(error);
+        }
+    }
+
     async getProcessedImageUrl(filename: string) {
         try {
             const response = await axios.get(`${this.apiUrl}/public/image?filename=${filename}`, {

+ 22 - 21
service/walletService.tsx

@@ -143,29 +143,30 @@ class WalletService {
         total_fee: string,
         promotion_code: string,
         car: string,
-        type?: string
+        type?: string,
+        is_ic_call?: boolean
     ) {
         try {
-            const response = await axios.post(
-                `${this.apiUrl}/clients/pay`,
-                {
-                    stationID,
-                    connector,
-                    user,
-                    book_time,
-                    end_time,
-                    total_power,
-                    total_fee,
-                    promotion_code,
-                    car,
-                    type
-                },
-                {
-                    headers: {
-                        Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                    }
+            const payload = {
+                stationID,
+                connector,
+                user,
+                book_time,
+                end_time,
+                total_power,
+                total_fee,
+                promotion_code,
+                car,
+                type,
+                is_ic_call
+            };
+            console.log('Submitting payment with payload:', payload);
+
+            const response = await axios.post(`${this.apiUrl}/clients/pay`, payload, {
+                headers: {
+                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
                 }
-            );
+            });
             if (response.status === 200 || response.status === 201) {
                 console.log('submit payment successful:', response.data);
                 return response.data;
@@ -174,7 +175,7 @@ class WalletService {
                 return false;
             }
         } catch (error) {
-            console.log(error);
+            console.log('Error submitting payment:', error);
             return false;
         }
     }