Ian Fung 1 year ago
parent
commit
da69bf8c3f

+ 2 - 0
app/(auth)/(tabs)/(charging)/chargingPenaltyPage.tsx

@@ -11,3 +11,5 @@ const ChargingPenaltyPage = ({ data }: { data: any }) => {
 };
 
 export default ChargingPenaltyPage;
+
+

+ 14 - 0
app/(auth)/(tabs)/(charging)/penaltyPaymentPage.tsx

@@ -0,0 +1,14 @@
+import { View } from 'react-native';
+import React from 'react';
+
+import PenaltyPaymentPageComponent from '../../../../component/chargingPage/penaltyPaymentPageComponent';
+
+const PenaltyPaymentPage = ({ data }: { data: any }) => {
+    return (
+        <View className="flex-1">
+            <PenaltyPaymentPageComponent />
+        </View>
+    );
+};
+
+export default PenaltyPaymentPage;

+ 14 - 0
app/(auth)/(tabs)/(home)/penaltyPaymentPage.tsx

@@ -0,0 +1,14 @@
+import { View } from 'react-native';
+import React from 'react';
+
+import PenaltyPaymentPageComponent from '../../../../component/chargingPage/penaltyPaymentPageComponent';
+
+const PenaltyPaymentPage = ({ data }: { data: any }) => {
+    return (
+        <View className="flex-1">
+            <PenaltyPaymentPageComponent />
+        </View>
+    );
+};
+
+export default PenaltyPaymentPage;

+ 61 - 1
app/(auth)/(tabs)/(home)/scanQrPage.tsx

@@ -644,9 +644,68 @@ const ScanQrPage = () => {
 
     const startCharging = async (dataForSubmission) => {
         try {
+            //before i start below logic, i need to check if the user has penalty unpaid.
+            //i will call fetchReservationHistories. and the api will return an array of object, within the object there is a field called "penalty_fee".
+            //if any reservation has penalty_fee > 0, i will show an alert to the user, and once click the alert it will takes them to a page that show the detail of the reservation.
+
+            const reservationHistories = await chargeStationService.fetchReservationHistories();
+            const unpaidPenalties = reservationHistories.filter(
+                (reservation) => reservation.penalty_fee > 0 && reservation.penalty_paid_status === false
+            );
+            const mostRecentUnpaidReservation = unpaidPenalties.reduce((mostRecent, current) => {
+                return new Date(mostRecent.created_at) > new Date(current.created_at) ? mostRecent : current;
+            }, unpaidPenalties[0]);
+
+            if (unpaidPenalties.length > 0) {
+                Alert.alert(
+                    '未付罰款',
+                    '您有未支付的罰款。請先支付罰款後再開始充電。',
+                    [
+                        {
+                            text: '查看詳情',
+                            onPress: () => {
+                                // Navigate to a page showing penalty details
+                                setModalVisible(false);
+                                setLoading(false);
+                                router.push({
+                                    pathname: '(auth)/(tabs)/(home)/penaltyPaymentPage',
+                                    params: {
+                                        book_time: mostRecentUnpaidReservation.book_time,
+                                        end_time: mostRecentUnpaidReservation.end_time,
+                                        actual_end_time: mostRecentUnpaidReservation.actual_end_time,
+                                        penalty_fee: mostRecentUnpaidReservation.penalty_fee,
+                                        format_order_id: mostRecentUnpaidReservation.format_order_id,
+                                        id: mostRecentUnpaidReservation.id,
+                                        stationName:
+                                            mostRecentUnpaidReservation.connector.EquipmentID.StationID.snapshot
+                                                .StationName,
+                                        address:
+                                            mostRecentUnpaidReservation.connector.EquipmentID.StationID.snapshot.Address
+                                    }
+                                });
+                            }
+                        },
+                        {
+                            text: '返回',
+                            onPress: () => {
+                                setModalVisible(false);
+                                if (router.canGoBack()) {
+                                    router.back();
+                                } else {
+                                    router.push('/mainPage');
+                                }
+                            }
+                        }
+                    ],
+                    { cancelable: false }
+                );
+                return;
+            }
+
+            ////////
             const wallet = await walletService.getWalletBalance();
             console.log('wallet in startCharging in scanQrPage', wallet);
-            oneTimeCharging(dataForSubmission.total_fee);
+            // oneTimeCharging(dataForSubmission.total_fee);
 
             if (wallet < dataForSubmission.total_fee) {
                 oneTimeCharging(dataForSubmission.total_fee);
@@ -696,6 +755,7 @@ const ScanQrPage = () => {
                 // startNavigationAttempts();
             } else if (response.status === 400) {
                 console.log('400 error in paymentSummaryPageComponent');
+
                 Alert.alert('餘額不足', '您的餘額不足,請充值後再試。');
             } else {
                 console.log('Failed to start charging:', response);

+ 6 - 5
component/bookingMenuPage/bookingConfirmationPage.tsx

@@ -18,10 +18,10 @@ const BookingConfirmationPageComponent = () => {
         setSelectedCouponRedeemCode('');
     }, []);
 
-    const convertDate = (dateString) => {
-        const [month, day] = dateString.split('/');
+    const convertDate = (dateString: string) => {
+        const [year, month, day] = dateString.split('-');
         const monthNumber = parseInt(month, 10);
-        return `${monthNumber}月${day}`;
+        return `${monthNumber}月${parseInt(day, 10)}`;
     };
     const price = params.price;
 
@@ -68,7 +68,7 @@ const BookingConfirmationPageComponent = () => {
                                 <Text style={styles.grayColor} className="text-base">
                                     日期
                                 </Text>
-                                <Text style={styles.greenColor} className="text-6xl text-center  pt-2">
+                                <Text style={styles.greenColor} className="text-4xl text-center  pt-2">
                                     {convertDate(params.date)}
                                 </Text>
                             </View>
@@ -76,7 +76,7 @@ const BookingConfirmationPageComponent = () => {
                                 <Text style={styles.grayColor} className="text-base pl-7">
                                     時間
                                 </Text>
-                                <Text style={styles.greenColor} className="text-6xl text-center pt-2">
+                                <Text style={styles.greenColor} className="text-4xl text-center pt-2">
                                     {params.bookTime}
                                 </Text>
                             </View>
@@ -174,6 +174,7 @@ const BookingConfirmationPageComponent = () => {
                                         userID: params.userID,
                                         date: params.date,
                                         bookTime: params.bookTime,
+                                        endTime: params.endTime,
                                         price: params.price,
                                         chargingWatt: params.chargingWatt,
                                         carID: params.carID,

+ 65 - 1
component/bookingMenuPage/bookingMenuPage.tsx

@@ -1,4 +1,4 @@
-import { View, Text, StyleSheet, ScrollView, Dimensions, ActivityIndicator, RefreshControl } from 'react-native';
+import { View, Text, StyleSheet, ScrollView, Dimensions, ActivityIndicator, RefreshControl, Alert } from 'react-native';
 import TabViewComponent, { TabItem } from '../global/tabView';
 import NormalButton from '../global/normal_button';
 import { SafeAreaView } from 'react-native-safe-area-context';
@@ -12,6 +12,70 @@ import BookingTabViewComponent from '../global/bookingTabViewComponent';
 
 interface BookingMenuPageProps {}
 const BookingMenuPageComponent: React.FC<BookingMenuPageProps> = () => {
+    //check for unpaid penalties
+    useEffect(() => {
+        const checkUnpaidPenalties = async () => {
+            try {
+                const reservationHistories = await chargeStationService.fetchReservationHistories();
+                const unpaidPenalties = reservationHistories.filter(
+                    (reservation) => reservation.penalty_fee > 0 && reservation.penalty_paid_status === false
+                );
+
+                if (unpaidPenalties.length > 0) {
+                    const mostRecentUnpaidReservation = unpaidPenalties.reduce((mostRecent, current) => {
+                        return new Date(mostRecent.created_at) > new Date(current.created_at) ? mostRecent : current;
+                    }, unpaidPenalties[0]);
+
+                    Alert.alert(
+                        '未付罰款',
+                        '您有未支付的罰款。請先支付罰款後再開始充電。',
+                        [
+                            {
+                                text: '查看詳情',
+                                onPress: () => {
+                                    // Navigate to a page showing penalty details
+                                    router.push({
+                                        pathname: '(auth)/(tabs)/(home)/penaltyPaymentPage',
+                                        params: {
+                                            book_time: mostRecentUnpaidReservation.book_time,
+                                            end_time: mostRecentUnpaidReservation.end_time,
+                                            actual_end_time: mostRecentUnpaidReservation.actual_end_time,
+                                            penalty_fee: mostRecentUnpaidReservation.penalty_fee,
+                                            format_order_id: mostRecentUnpaidReservation.format_order_id,
+                                            id: mostRecentUnpaidReservation.id,
+                                            stationName:
+                                                mostRecentUnpaidReservation.connector.EquipmentID.StationID.snapshot
+                                                    .StationName,
+                                            address:
+                                                mostRecentUnpaidReservation.connector.EquipmentID.StationID.snapshot
+                                                    .Address
+                                        }
+                                    });
+                                }
+                            },
+                            {
+                                text: '返回',
+                                onPress: () => {
+                                    if (router.canGoBack()) {
+                                        router.back();
+                                    } else {
+                                        router.push('/mainPage');
+                                    }
+                                }
+                            }
+                        ],
+                        { cancelable: false }
+                    );
+                }
+            } catch (error) {
+                console.error('Error checking unpaid penalties:', error);
+                // Handle the error appropriately (e.g., show an error message to the user)
+            }
+        };
+
+        checkUnpaidPenalties();
+    }, []);
+
     // console.log('BookingMenuPageComponent rendering');
     const [refreshing, setRefreshing] = useState(false);
     const [refetchTrigger, setRefetchTrigger] = useState(0);

+ 530 - 272
component/bookingMenuPage/makingBookingPageComponent.tsx

@@ -16,11 +16,9 @@ import { router, useLocalSearchParams } from 'expo-router';
 import NormalButton from '../global/normal_button';
 import { CheckMarkLogoSvg, DirectionLogoSvg, PreviousPageBlackSvg } from '../global/SVG';
 import { ChargingStationTabView } from '../global/chargingStationTabView';
-import ChooseCarForChargingRow from '../global/chooseCarForChargingRow';
 import { useEffect, useState } from 'react';
 import DropdownSelect from '../global/dropdown_select';
 import { chargeStationService } from '../../service/chargeStationService';
-import { authenticationService } from '../../service/authService';
 import * as Location from 'expo-location';
 import { calculateDistance } from '../global/distanceCalculator';
 import Modal from 'react-native-modal';
@@ -73,7 +71,7 @@ const MakingBookingPageComponent = () => {
     const layoutWidth = screenWidth;
     const layoutHeight = screenHeight * 0.32;
     const { userID, setUserID } = useUserInfoStore();
-
+    const [formattedDates, setFormattedDates] = useState([]);
     const params = useLocalSearchParams();
     const chargeStationID = params.chargeStationID as string;
     const chargeStationName = params.chargeStationName as string;
@@ -87,8 +85,126 @@ const MakingBookingPageComponent = () => {
     const [distance, setDistance] = useState<string | null>(null);
     const [upcomingReservations, setUpcomingReservation] = useState([]);
     const [carLoadingState, setCarLoadingState] = useState(false);
-    const [isDateLoading, setIsDateLoading] = useState(true);
+    const [isDateLoading, setIsDateLoading] = useState(false);
+    const [dataResponse, setDataResponse] = useState([]);
 
+    //check for unpaid penalties
+    useEffect(() => {
+        const checkUnpaidPenalties = async () => {
+            try {
+                const reservationHistories = await chargeStationService.fetchReservationHistories();
+                const unpaidPenalties = reservationHistories.filter(
+                    (reservation) => reservation.penalty_fee > 0 && reservation.penalty_paid_status === false
+                );
+
+                if (unpaidPenalties.length > 0) {
+                    const mostRecentUnpaidReservation = unpaidPenalties.reduce((mostRecent, current) => {
+                        return new Date(mostRecent.created_at) > new Date(current.created_at) ? mostRecent : current;
+                    }, unpaidPenalties[0]);
+
+                    Alert.alert(
+                        '未付罰款',
+                        '您有未支付的罰款。請先支付罰款後再開始充電。',
+                        [
+                            {
+                                text: '查看詳情',
+                                onPress: () => {
+                                    // Navigate to a page showing penalty details
+                                    router.push({
+                                        pathname: '(auth)/(tabs)/(home)/penaltyPaymentPage',
+                                        params: {
+                                            book_time: mostRecentUnpaidReservation.book_time,
+                                            end_time: mostRecentUnpaidReservation.end_time,
+                                            actual_end_time: mostRecentUnpaidReservation.actual_end_time,
+                                            penalty_fee: mostRecentUnpaidReservation.penalty_fee,
+                                            format_order_id: mostRecentUnpaidReservation.format_order_id,
+                                            id: mostRecentUnpaidReservation.id,
+                                            stationName:
+                                                mostRecentUnpaidReservation.connector.EquipmentID.StationID.snapshot
+                                                    .StationName,
+                                            address:
+                                                mostRecentUnpaidReservation.connector.EquipmentID.StationID.snapshot
+                                                    .Address
+                                        }
+                                    });
+                                }
+                            },
+                            {
+                                text: '返回',
+                                onPress: () => {
+                                    if (router.canGoBack()) {
+                                        router.back();
+                                    } else {
+                                        router.push('/mainPage');
+                                    }
+                                }
+                            }
+                        ],
+                        { cancelable: false }
+                    );
+                }
+            } catch (error) {
+                console.error('Error checking unpaid penalties:', error);
+                // Handle the error appropriately (e.g., show an error message to the user)
+            }
+        };
+
+        checkUnpaidPenalties();
+    }, []);
+
+    const handleSendingSize = async (watt) => {
+        try {
+            setIsLoading(true);
+            const wattValue = parseInt(watt.split(' ')[0]);
+            console.log('wattValue', wattValue);
+            let size: number;
+            //make the duration based on watt
+            switch (wattValue) {
+                case 20:
+                    size = 25;
+                    break;
+                case 25:
+                    size = 30;
+                    break;
+                case 30:
+                    size = 40;
+                    break;
+                case 40:
+                    size = 45;
+                    break;
+                default:
+                    console.error('Invalid selectedWatt value');
+                    return; // Exit the function if selectedWatt is invalid
+            }
+
+            const response = await chargeStationService.getReservationWithSize(size);
+            if (response) {
+                setDataResponse(response);
+                // console.log('respoasdasdasdnse', response);
+
+                const uniqueDates = new Set();
+                response.forEach((item) => {
+                    item.timeSlot.forEach((slot) => {
+                        uniqueDates.add(slot.date);
+                    });
+                });
+
+                const availableDates = Array.from(uniqueDates).sort();
+
+                setAvailableDate(availableDates);
+                // console.log('formattedDates', formattedDates);
+            } else {
+                console.log('No response from getReservationWithSize');
+            }
+        } catch (error) {
+            console.error('Error in handleSendingSize:', error);
+            // Handle the error appropriately, maybe show an alert to the user
+        } finally {
+            setIsLoading(false);
+        }
+    };
+
+    //get location
     useEffect(() => {
         const getCurrentLocation = async () => {
             let { status } = await Location.requestForegroundPermissionsAsync();
@@ -104,117 +220,119 @@ const MakingBookingPageComponent = () => {
     }, []);
 
     //getDefaultCar
-    useEffect(() => {
-        const fetchDefaultCar = async () => {
-            setIsDefaultCarLoading(true);
-            try {
-                const response = await chargeStationService.getUserDefaultCars();
-                if (response && response.data) {
-                    setDefaultCar(response.data.id);
-                    setSelectedCarID(response.data.id);
-                    setCarCapacitance(response.data.car_type.capacitance);
-                    setSelectedCar(response.data.id);
-                    console.log('*******', response.data.car_type.capacitance);
-                }
-            } catch (error) {
-                console.log('Error fetching default car:', error);
-            } finally {
-                setIsDefaultCarLoading(false);
-            }
-        };
-        fetchDefaultCar();
-    }, []);
-    const formatDistance = (distanceInMeters: number): string => {
-        if (distanceInMeters < 1000) {
-            return `${Math.round(distanceInMeters)}米`;
-        } else {
-            const distanceInKm = distanceInMeters / 1000;
-            return `${distanceInKm.toFixed(1)}公里`;
-        }
-    };
-    const getUpcomingReservations = (reservations: any, daysAhead = 3) => {
-        const today = new Date();
-        const threeDaysLater = new Date(today);
-        threeDaysLater.setDate(today.getDate() + daysAhead);
-
-        return reservations
-            .filter((reservation) => {
-                const reservationDate = new Date(reservation.book_time);
-                return reservationDate >= today && reservationDate <= threeDaysLater;
-            })
-            .sort((a, b) => new Date(a.reservationDate) - new Date(b.reservationDate));
-    };
+    // useEffect(() => {
+    //     const fetchDefaultCar = async () => {
+    //         setIsDefaultCarLoading(true);
+    //         try {
+    //             const response = await chargeStationService.getUserDefaultCars();
+    //             if (response && response.data) {
+    //                 setDefaultCar(response.data.id);
+    //                 setSelectedCarID(response.data.id);
+    //                 setCarCapacitance(response.data.car_type.capacitance);
+    //                 setSelectedCar(response.data.id);
+    //                 console.log('*******', response.data.car_type.capacitance);
+    //             }
+    //         } catch (error) {
+    //             console.log('Error fetching default car:', error);
+    //         } finally {
+    //             setIsDefaultCarLoading(false);
+    //         }
+    //     };
+    //     fetchDefaultCar();
+    // }, []);
+    // const formatDistance = (distanceInMeters: number): string => {
+    //     if (distanceInMeters < 1000) {
+    //         return `${Math.round(distanceInMeters)}米`;
+    //     } else {
+    //         const distanceInKm = distanceInMeters / 1000;
+    //         return `${distanceInKm.toFixed(1)}公里`;
+    //     }
+    // };
+    // const getUpcomingReservations = (reservations: any, daysAhead = 3) => {
+    //     const today = new Date();
+    //     const threeDaysLater = new Date(today);
+    //     threeDaysLater.setDate(today.getDate() + daysAhead);
+
+    //     return reservations
+    //         .filter((reservation) => {
+    //             const reservationDate = new Date(reservation.book_time);
+    //             return reservationDate >= today && reservationDate <= threeDaysLater;
+    //         })
+    //         .sort((a, b) => new Date(a.reservationDate) - new Date(b.reservationDate));
+    // };
 
     //USE BELOW to find  upcoming reservations, then I filter availableDate and time based on the upcoming ones so user cannot book the same time twice.
-    const formatReservations = (reservations) => {
-        const formattedReservations = {};
+    // const formatReservations = (reservations) => {
+    //     const formattedReservations = {};
 
-        reservations.forEach((reservation) => {
-            const bookTime = new Date(reservation.book_time);
-            const date = formatDate(bookTime);
-            const time = formatTime(bookTime);
+    //     reservations.forEach((reservation) => {
+    //         const bookTime = new Date(reservation.book_time);
+    //         const date = formatDate(bookTime);
+    //         const time = formatTime(bookTime);
 
-            if (!formattedReservations[date]) {
-                formattedReservations[date] = [];
-            }
-            formattedReservations[date].push(time);
-        });
+    //         if (!formattedReservations[date]) {
+    //             formattedReservations[date] = [];
+    //         }
+    //         formattedReservations[date].push(time);
+    //     });
 
-        return Object.entries(formattedReservations).map(([date, times]) => ({
-            date,
-            times
-        }));
-    };
+    //     return Object.entries(formattedReservations).map(([date, times]) => ({
+    //         date,
+    //         times
+    //     }));
+    // };
 
-    const formatDate = (date) => {
-        const month = String(date.getMonth() + 1).padStart(2, '0');
-        const day = String(date.getDate()).padStart(2, '0');
-        return `${month}/${day}`;
-    };
+    // const formatDate = (date) => {
+    //     const month = String(date.getMonth() + 1).padStart(2, '0');
+    //     const day = String(date.getDate()).padStart(2, '0');
+    //     return `${month}/${day}`;
+    // };
+
+    // const formatTime = (date) => {
+    //     return date.toTimeString().slice(0, 5);
+    // };
+
+    // useEffect(() => {
+    //     const fetchReservationHistories = async () => {
+    //         try {
+    //             const response = await chargeStationService.fetchReservationHistories();
+    //             if (response) {
+    //                 // console.log('response', response);
+    //                 // console.log('Reservation histories:', response);
+    //                 const upcomingReservations = getUpcomingReservations(response);
+    //                 // console.log('upcomingReservations', upcomingReservations);
+    //                 const formattedReservations = formatReservations(upcomingReservations);
+    //                 // console.log('formattedReservations', formattedReservations);
+    //                 setUpcomingReservation(formattedReservations);
+    //             }
+    //             2;
+    //         } catch (error) {
+    //             console.log(error);
+    //         }
+    //     };
+    //     fetchReservationHistories();
+    // }, []);
 
-    const formatTime = (date) => {
-        return date.toTimeString().slice(0, 5);
-    };
-    useEffect(() => {
-        const fetchReservationHistories = async () => {
-            try {
-                const response = await chargeStationService.fetchReservationHistories();
-                if (response) {
-                    // console.log('response', response);
-                    // console.log('Reservation histories:', response);
-                    const upcomingReservations = getUpcomingReservations(response);
-                    // console.log('upcomingReservations', upcomingReservations);
-                    const formattedReservations = formatReservations(upcomingReservations);
-                    // console.log('formattedReservations', formattedReservations);
-                    setUpcomingReservation(formattedReservations);
-                }
-                2;
-            } catch (error) {
-                console.log(error);
-            }
-        };
-        fetchReservationHistories();
-    }, []);
     //USE ABOVE to find upcoming reservations, then I filter availableDate and time based on the upcoming ones so user cannot book the same time twice.
 
-    useEffect(() => {
-        const getDistance = async () => {
-            if (currentLocation) {
-                try {
-                    const distance = await calculateDistance(
-                        Number(params.chargeStationLat),
-                        Number(params.chargeStationLng),
-                        currentLocation
-                    );
-                    setDistance(formatDistance(distance));
-                } catch (error) {
-                    console.error('Error calculating distance:', error);
-                }
-            }
-        };
+    // useEffect(() => {
+    //     const getDistance = async () => {
+    //         if (currentLocation) {
+    //             try {
+    //                 const distance = await calculateDistance(
+    //                     Number(params.chargeStationLat),
+    //                     Number(params.chargeStationLng),
+    //                     currentLocation
+    //                 );
+    //                 setDistance(formatDistance(distance));
+    //             } catch (error) {
+    //                 console.error('Error calculating distance:', error);
+    //             }
+    //         }
+    //     };
 
-        getDistance();
-    }, [params.chargeStationLat, params.chargeStationLng, currentLocation]);
+    //     getDistance();
+    // }, [params.chargeStationLat, params.chargeStationLng, currentLocation]);
 
     useEffect(() => {
         const fetchPrice = async () => {
@@ -228,18 +346,18 @@ const MakingBookingPageComponent = () => {
         fetchPrice();
     }, []);
 
-    function appendImageUrlToCarResult(carData, updatedVehicles) {
-        return carData.map((car) => {
-            const matchingVehicle = updatedVehicles.find((vehicle) => vehicle.car_type.name === car.car_name);
-            if (matchingVehicle) {
-                return {
-                    ...car,
-                    type_image_url: matchingVehicle.car_type.type_image_url
-                };
-            }
-            return car;
-        });
-    }
+    // function appendImageUrlToCarResult(carData, updatedVehicles) {
+    //     return carData.map((car) => {
+    //         const matchingVehicle = updatedVehicles.find((vehicle) => vehicle.car_type.name === car.car_name);
+    //         if (matchingVehicle) {
+    //             return {
+    //                 ...car,
+    //                 type_image_url: matchingVehicle.car_type.type_image_url
+    //             };
+    //         }
+    //         return car;
+    //     });
+    // }
 
     // useEffect(() => {
     //     setCarLoadingState(true);
@@ -290,87 +408,87 @@ const MakingBookingPageComponent = () => {
     //     fetchUserInfoAndCarData();
     // }, []);
 
-    useEffect(() => {
-        const fetchingAvailableTimeSlots = async () => {
-            setIsLoading(true);
-            try {
-                const fetchedTimeSlots = await chargeStationService.fetchAvailableTimeSlots(
-                    chargeStationID,
-                    selectedDate
-                );
-                const now = new Date();
-                const today = `${String(now.getMonth() + 1).padStart(2, '0')}/${String(now.getDate()).padStart(
-                    2,
-                    '0'
-                )}`;
-
-                let filteredTimeSlots = fetchedTimeSlots;
-
-                //filter out today's time slots that have already passed
-                if (selectedDate === today) {
-                    const currentHours = now.getHours();
-                    const currentMinutes = now.getMinutes();
-
-                    filteredTimeSlots = fetchedTimeSlots.filter((time) => {
-                        const [hours, minutes] = time.split(':').map(Number);
-                        if (hours > currentHours) return true;
-                        if (hours === currentHours && minutes > currentMinutes) return true;
-                        return false;
-                    });
-                }
-                //filter out time slots that are already fully booked
-                const reservedSlotsForDate = upcomingReservations.find((res) => res.date === selectedDate);
+    // useEffect(() => {
+    //     const fetchingAvailableTimeSlots = async () => {
+    //         setIsLoading(true);
+    //         try {
+    //             const fetchedTimeSlots = await chargeStationService.fetchAvailableTimeSlots(
+    //                 chargeStationID,
+    //                 selectedDate
+    //             );
+    //             const now = new Date();
+    //             const today = `${String(now.getMonth() + 1).padStart(2, '0')}/${String(now.getDate()).padStart(
+    //                 2,
+    //                 '0'
+    //             )}`;
 
-                if (reservedSlotsForDate) {
-                    filteredTimeSlots = filteredTimeSlots.filter((time) => !reservedSlotsForDate.times.includes(time));
-                }
-                setAvailableTimeSlots(filteredTimeSlots);
-            } catch (error) {
-                console.error('Error fetching time slots:', error);
-            } finally {
-                setIsLoading(false);
-            }
-        };
+    //             let filteredTimeSlots = fetchedTimeSlots;
 
-        if (selectedDate) {
-            fetchingAvailableTimeSlots();
-        }
-    }, [selectedDate]);
+    //             //filter out today's time slots that have already passed
+    //             if (selectedDate === today) {
+    //                 const currentHours = now.getHours();
+    //                 const currentMinutes = now.getMinutes();
 
-    useEffect(() => {
-        const fetchConnectorOptions = async () => {
-            try {
-                const fetchedData = await chargeStationService.fetchSpecificChargeStation(chargeStationID);
-                console.log('fetchedDate', fetchedData);
-                const dateObject = fetchedData.find((item) => item.date === selectedDate);
-                console.log('dateObject', dateObject);
-                if (!dateObject) {
-                    setAvailableConnectorDropdownOptions([]);
-                    return;
-                }
+    //                 filteredTimeSlots = fetchedTimeSlots.filter((time) => {
+    //                     const [hours, minutes] = time.split(':').map(Number);
+    //                     if (hours > currentHours) return true;
+    //                     if (hours === currentHours && minutes > currentMinutes) return true;
+    //                     return false;
+    //                 });
+    //             }
+    //             //filter out time slots that are already fully booked
+    //             const reservedSlotsForDate = upcomingReservations.find((res) => res.date === selectedDate);
 
-                const rangeObject = dateObject.range.find((range) => range.start === selectedTime);
-                console.log('rangeObject', rangeObject);
-                if (!rangeObject) {
-                    setAvailableConnectorDropdownOptions([]);
-                    return;
-                }
+    //             if (reservedSlotsForDate) {
+    //                 filteredTimeSlots = filteredTimeSlots.filter((time) => !reservedSlotsForDate.times.includes(time));
+    //             }
+    //             setAvailableTimeSlots(filteredTimeSlots);
+    //         } catch (error) {
+    //             console.error('Error fetching time slots:', error);
+    //         } finally {
+    //             setIsLoading(false);
+    //         }
+    //     };
 
-                const connectorIDs = rangeObject.connectors
-                    .filter((connector) => connector.Status === '待机')
-                    .map((connector) => connector.ConnectorID);
+    //     if (selectedDate) {
+    //         fetchingAvailableTimeSlots();
+    //     }
+    // }, [selectedDate]);
 
-                console.log('connectorIDs', connectorIDs);
+    // useEffect(() => {
+    //     const fetchConnectorOptions = async () => {
+    //         try {
+    //             const fetchedData = await chargeStationService.fetchSpecificChargeStation(chargeStationID);
+    //             console.log('fetchedDate', fetchedData);
+    //             const dateObject = fetchedData.find((item) => item.date === selectedDate);
+    //             console.log('dateObject', dateObject);
+    //             if (!dateObject) {
+    //                 setAvailableConnectorDropdownOptions([]);
+    //                 return;
+    //             }
 
-                setAvailableConnectorDropdownOptions(connectorIDs);
-            } catch (error) {
-                console.error('Error fetching charge station data:', error);
-                setAvailableConnectorDropdownOptions([]);
-            }
-        };
+    //             const rangeObject = dateObject.range.find((range) => range.start === selectedTime);
+    //             console.log('rangeObject', rangeObject);
+    //             if (!rangeObject) {
+    //                 setAvailableConnectorDropdownOptions([]);
+    //                 return;
+    //             }
+
+    //             const connectorIDs = rangeObject.connectors
+    //                 .filter((connector) => connector.Status === '待机')
+    //                 .map((connector) => connector.ConnectorID);
 
-        fetchConnectorOptions();
-    }, [chargeStationID, selectedDate, selectedTime]);
+    //             console.log('connectorIDs', connectorIDs);
+
+    //             setAvailableConnectorDropdownOptions(connectorIDs);
+    //         } catch (error) {
+    //             console.error('Error fetching charge station data:', error);
+    //             setAvailableConnectorDropdownOptions([]);
+    //         }
+    //     };
+
+    //     fetchConnectorOptions();
+    // }, [chargeStationID, selectedDate, selectedTime]);
 
     // old
     // const formattedConnectorDropdownOptions = availableConnectorDropdownOptions.map((id, index) => ({
@@ -386,34 +504,37 @@ const MakingBookingPageComponent = () => {
         '101708240502474002': '6'
     };
 
-    console.log('availableConnectorDropdownOptions', availableConnectorDropdownOptions);
-    const formattedConnectorDropdownOptions = availableConnectorDropdownOptions
-        .map((id) => ({
-            label: connectorIDToLabelMap[id] || '',
-            value: id
-        }))
-        .filter((option) => option.label !== '')
-        .sort((a, b) => parseInt(a.label) - parseInt(b.label));
-    console.log('formattedConnectorDropdownOptions', formattedConnectorDropdownOptions);
+    const connectorIDToLabelMapArray = [
+        { value: '101708240502475001', label: '1' },
+        { value: '101708240502476001', label: '2' },
+        { value: '101708240502477001', label: '3' },
+        { value: '101708240502478001', label: '4' },
+        { value: '101708240502474001', label: '5' },
+        { value: '101708240502474002', label: '6' }
+    ];
+    const formatDateString = (dateString: string) => {
+        const [year, month, day] = dateString.split('-');
+        return `${month}/${day}`;
+    };
 
-    useEffect(() => {
-        const fetchingAvailableDates = async () => {
-            setIsDateLoading(true);
-            try {
-                const fetchedDates = await chargeStationService.fetchAvailableDates(chargeStationID);
-                console.log('fetchedDates', fetchedDates);
-                setAvailableDate(fetchedDates);
+    // useEffect(() => {
+    //     const fetchingAvailableDates = async () => {
+    //         setIsDateLoading(true);
+    //         try {
+    //             const fetchedDates = await chargeStationService.fetchAvailableDates(chargeStationID);
+    //             console.log('fetchedDates', fetchedDates);
+    //             setAvailableDate(fetchedDates);
 
-                console.log(fetchedDates.slice(0, 3));
-            } catch (error) {
-                console.error('Error fetching available dates:', error);
-            } finally {
-                setIsDateLoading(false);
-            }
-        };
+    //             console.log(fetchedDates.slice(0, 3));
+    //         } catch (error) {
+    //             console.error('Error fetching available dates:', error);
+    //         } finally {
+    //             setIsDateLoading(false);
+    //         }
+    //     };
 
-        fetchingAvailableDates();
-    }, [chargeStationID]);
+    //     fetchingAvailableDates();
+    // }, [chargeStationID]);
 
     const handleNavigationPress = () => {
         const latitude = chargeStationLat;
@@ -447,6 +568,44 @@ const MakingBookingPageComponent = () => {
             .catch((err) => console.error('An error occurred', err));
     };
 
+    const handleDateToTimeSlot = (date: string, connectorId: string) => {
+        // Find the correct connector object
+        const connectorData = dataResponse.find((item) => item.connector === connectorId);
+
+        if (!connectorData) {
+            console.error(`No data found for connector ${connectorId}`);
+            setAvailableTimeSlots([]);
+            return;
+        }
+
+        // Find the timeSlot object for the selected date
+        const selectedTimeSlot = connectorData.timeSlot.find((slot) => slot.date === date);
+
+        if (!selectedTimeSlot) {
+            console.error(`No time slots found for date ${date}`);
+            setAvailableTimeSlots([]);
+            return;
+        }
+
+        const now = new Date();
+        const selectedDateObj = new Date(date);
+        const isToday = selectedDateObj.toDateString() === now.toDateString();
+
+        let filteredSlots = selectedTimeSlot.availableTime;
+
+        if (isToday) {
+            filteredSlots = filteredSlots.filter((slot) => {
+                const [hours, minutes] = slot.startTime.split(':').map(Number);
+                const slotTime = new Date(selectedDateObj);
+                slotTime.setHours(hours, minutes, 0, 0);
+                return slotTime > now;
+            });
+        }
+
+        console.log('Available Time Slots:', filteredSlots);
+        setAvailableTimeSlots(filteredSlots);
+    };
+
     const handleConfirmation = (value: any) => {
         setModalVisible(true);
         const selectedOption = formattedConnectorDropdownOptions.find((option) => option.value === value);
@@ -473,11 +632,10 @@ const MakingBookingPageComponent = () => {
     };
 
     const handleModalConfirm = () => {
-        // Alert.alert('提示', '此功能正在準備中,敬請期待', [{ text: '確定', onPress: () => router.push('/mainPage') }], {
-        //     cancelable: false
-        // });
         setModalVisible(false);
+
         if (routerParams) {
+            console.log('routerParams', routerParams);
             router.push(routerParams);
         }
     };
@@ -616,6 +774,7 @@ const MakingBookingPageComponent = () => {
                                 setSelectedWatt('');
                                 setOpenDrawer(1);
                                 setSelectedDrawer(1);
+                                setSelectedChargingGun('');
                             }}
                         >
                             <View className="mx-[5%] ">
@@ -687,6 +846,9 @@ const MakingBookingPageComponent = () => {
                                                     setSelectedWatt(watt);
                                                     setOpenDrawer(2);
                                                     setSelectedDrawer(2);
+                                                    handleSendingSize(watt);
+                                                    console.log('selectedWatt', selectedWatt);
+                                                    console.log('watt', watt);
                                                 }}
                                             >
                                                 <Text
@@ -706,35 +868,126 @@ const MakingBookingPageComponent = () => {
                             )}
                         </AccordionItem>
                     )}
-                    {selectedTime !== '' ? (
-                        <Pressable
-                            onPress={() => {
-                                setOpenDrawer(2);
-                                setSelectedDrawer(2);
-                                setSelectedDate('');
-                                setSelectedTime('');
-                            }}
-                        >
-                            <View className="mx-[5%] ">
-                                <View className="flex-row items-center pt-4">
-                                    <Text className="text-lg pr-2 text-[#34667c]">選擇日期</Text>
-                                    <CheckMarkLogoSvg />
+                    {/* select gun */}
+                    {/* select gun */}
+                    <View className="">
+                        {selectedChargingGun !== '' ? (
+                            <Pressable
+                                onPress={() => {
+                                    setSelectedChargingGun('');
+                                    setOpenDrawer(2);
+                                    setSelectedDrawer(2);
+                                }}
+                            >
+                                <View className="mx-[5%]">
+                                    <View className="flex-row items-center pt-4">
+                                        <Text className="text-lg pr-2 text-[#34667c]">選擇充電座</Text>
+                                        <CheckMarkLogoSvg />
+                                    </View>
+                                    <View className="text-lg pb-4 flex flex-row items-center">
+                                        <Text className="text-[#34667c] font-[600] text-2xl pr-2">
+                                            {connectorIDToLabelMap[selectedChargingGun]}
+                                        </Text>
+                                        <Text className="text-lg">號充電座</Text>
+                                    </View>
                                 </View>
-                                <Text className="text-lg pb-4">
-                                    {selectedDate} - {selectedTime}
-                                </Text>
-                            </View>
-                        </Pressable>
+                            </Pressable>
+                        ) : (
+                            <AccordionItem
+                                title="選擇充電座"
+                                isOpen={openDrawer === 2}
+                                onToggle={() => {
+                                    if (selectedWatt) {
+                                        toggleDrawer(2);
+                                    }
+                                }}
+                                isSelected={selectedDrawer === 2}
+                            >
+                                {selectedWatt !== '' ? (
+                                    <View className="">
+                                        <DropdownSelect
+                                            dropdownOptions={connectorIDToLabelMapArray}
+                                            placeholder={'選擇充電座號碼'}
+                                            onSelect={(value) => {
+                                                setSelectedChargingGun(value);
+                                                setSelectedDrawer(3);
+                                                setOpenDrawer(3);
+                                            }}
+                                            extendedStyle={{
+                                                borderColor: '#34667c',
+                                                marginTop: 4,
+                                                padding: 12
+                                            }}
+                                        />
+
+                                        <Image
+                                            style={{
+                                                width: layoutWidth * 0.9,
+                                                height: layoutHeight
+                                            }}
+                                            resizeMode="contain"
+                                            source={require('../../assets/floorPlan1.png')}
+                                        />
+                                    </View>
+                                ) : (
+                                    <Text className="text-base text-gray-500 py-2">請先選擇充電方案</Text>
+                                )}
+                            </AccordionItem>
+                        )}
+                    </View>
+                    <Modal
+                        isVisible={isModalVisible}
+                        // onBackdropPress={() => setModalVisible(false)}
+                        backdropOpacity={0.5}
+                        animationIn="fadeIn"
+                        animationOut="fadeOut"
+                    >
+                        <View style={styles.modalContent}>
+                            <Text className="text-2xl font-[500] text-[#34667c] mb-6">
+                                已選擇日期時間: {formatDateString(selectedDate)} - {selectedTime}
+                            </Text>
+                            <Text style={styles.modalText} className="text-[#34667c]">
+                                若客戶逾時超過15分鐘,系統將視作自動放棄預約,客戶需要重新預約一次。
+                                本公司有權保留全數費用,恕不退還。按下確認代表您已閱讀並同意上述條款。
+                            </Text>
+                            <NormalButton
+                                title={<Text className="text-white">我確認</Text>}
+                                onPress={handleModalConfirm}
+                                extendedStyle={styles.confirmButton}
+                            />
+                        </View>
+                    </Modal>
+                    {selectedDate !== '' && selectedTime !== '' ? (
+                        <>
+                            <Pressable
+                                onPress={() => {
+                                    setOpenDrawer(3);
+                                    setSelectedDrawer(3);
+                                    setSelectedDate('');
+                                    setSelectedTime('');
+                                }}
+                            >
+                                <View className="mx-[5%] ">
+                                    <View className="flex-row items-center pt-4">
+                                        <Text className="text-lg pr-2 text-[#34667c]">選擇日期</Text>
+                                        <CheckMarkLogoSvg />
+                                    </View>
+                                    <Text className="text-lg pb-4">
+                                        {formatDateString(selectedDate)} - {selectedTime}
+                                    </Text>
+                                </View>
+                            </Pressable>
+                        </>
                     ) : (
                         <AccordionItem
                             title="選擇日期 (月/日)"
-                            isOpen={openDrawer === 2}
+                            isOpen={openDrawer === 3}
                             onToggle={() => {
                                 if (stopChargingUponBatteryFull !== false || selectedDuration !== '') {
-                                    toggleDrawer(2);
+                                    toggleDrawer(3);
                                 }
                             }}
-                            isSelected={selectedDrawer === 2}
+                            isSelected={selectedDrawer === 3}
                         >
                             {isDateLoading ? (
                                 <View className="flex-1 items-center justify-center py-4">
@@ -742,7 +995,7 @@ const MakingBookingPageComponent = () => {
                                 </View>
                             ) : (
                                 <View className="flex-row w-full flex-wrap mb-1 ">
-                                    {availableDate.slice(0, 3).map((date) => (
+                                    {availableDate.map((date) => (
                                         <Pressable
                                             key={date}
                                             className={`${
@@ -750,6 +1003,7 @@ const MakingBookingPageComponent = () => {
                                             } border border-[#34667c]  rounded-lg w-[22%] items-center mt-1 mr-1 mb-1`}
                                             onPress={() => {
                                                 setSelectedDate(date);
+                                                handleDateToTimeSlot(date, selectedChargingGun);
                                             }}
                                         >
                                             <Text
@@ -757,7 +1011,7 @@ const MakingBookingPageComponent = () => {
                                                     selectedDate === date ? 'text-white' : 'text-[#34667c]'
                                                 } `}
                                             >
-                                                {date}
+                                                {formatDateString(date)}
                                             </Text>
                                         </Pressable>
                                     ))}
@@ -772,24 +1026,48 @@ const MakingBookingPageComponent = () => {
                                         </View>
                                     ) : (
                                         <View className="flex-row w-full mb-3 flex-wrap my-2 ">
-                                            {availableTimeSlots.map((time) => (
+                                            {availableTimeSlots.map((slot, index) => (
                                                 <Pressable
-                                                    key={time}
+                                                    key={index}
                                                     className={`${
-                                                        selectedTime === time ? 'bg-[#34667c] ' : 'bg-white'
+                                                        selectedTime === slot.startTime ? 'bg-[#34667c] ' : 'bg-white'
                                                     } border border-[#34667c]  mr-2 rounded-lg w-[22%] items-center mb-2`}
                                                     onPress={() => {
-                                                        setSelectedTime(time);
-                                                        setOpenDrawer(3);
-                                                        setSelectedDrawer(3);
+                                                        setSelectedTime(slot.startTime);
+                                                        setRouterParams({
+                                                            pathname: '/bookingConfirmationPage',
+                                                            params: {
+                                                                chargeStationName,
+                                                                chargeStationAddress,
+                                                                chargeStationID,
+                                                                connectorID: selectedChargingGun,
+                                                                connectorLabel:
+                                                                    connectorIDToLabelMap[selectedChargingGun],
+                                                                userID,
+                                                                carCapacitance: carCapacitance,
+                                                                carID: selectedCarID,
+                                                                carName: selectedCar,
+                                                                date: selectedDate,
+                                                                bookTime: slot.startTime,
+                                                                endTime: slot.endTime,
+                                                                chargingMethod: stopChargingUponBatteryFull
+                                                                    ? 'stopChargingUponBatteryFull'
+                                                                    : 'chargingBasedOnWatt',
+                                                                chargingWatt: selectedWatt || '',
+                                                                price: price
+                                                            }
+                                                        });
+                                                        setModalVisible(true);
                                                     }}
                                                 >
                                                     <Text
                                                         className={`text-base p-2  ${
-                                                            selectedTime === time ? 'text-white' : 'text-[#34667c]'
+                                                            selectedTime === slot.startTime
+                                                                ? 'text-white'
+                                                                : 'text-[#34667c]'
                                                         } `}
                                                     >
-                                                        {time}
+                                                        {slot.startTime}
                                                     </Text>
                                                 </Pressable>
                                             ))}
@@ -799,7 +1077,8 @@ const MakingBookingPageComponent = () => {
                             )}
                         </AccordionItem>
                     )}
-                    <View className="">
+
+                    {/* <View className="">
                         <AccordionItem
                             title="選擇充電座"
                             isOpen={openDrawer === 3}
@@ -855,30 +1134,9 @@ const MakingBookingPageComponent = () => {
                                 </Modal>
                             </View>
                         </AccordionItem>
-                    </View>
+                    </View> */}
                 </View>
 
-                {/* {routerParams ? (
-                    <View className="mx-[5%] my-4">
-                        <NormalButton
-                            title={
-                                <Text
-                                    style={{
-                                        fontWeight: '700',
-                                        fontSize: 20,
-                                        color: '#fff'
-                                    }}
-                                >
-                                    新增
-                                </Text>
-                            }
-                            onPress={() => handleConfirmation(selectedChargingGun)}
-                        />
-                    </View>
-                ) : (
-                    ''
-                )} */}
-
                 <View className="mx-[5%] flex-1">
                     <Text className="text-xl pb-2 mt-6" style={styles.text}>
                         充電站資訊

+ 91 - 52
component/chargingPage/paymentSummaryPageComponent.tsx

@@ -9,6 +9,8 @@ import { useEffect, useRef, useState } from 'react';
 import useBookingStore from '../../providers/booking_store';
 import useCouponStore from '../../providers/coupon_store';
 import { walletService } from '../../service/walletService';
+import { parseISO, subHours, format } from 'date-fns';
+import { chargeStationService } from '../../service/chargeStationService';
 
 const PaymentSummaryPageComponent = () => {
     const selectedCouponName = useCouponStore((state) => state.selectedCouponName);
@@ -17,12 +19,14 @@ const PaymentSummaryPageComponent = () => {
     const params = useLocalSearchParams();
     const setBookingInfo = useBookingStore((state) => state.setBookingInfo);
     const initialSetupDone = useRef(false);
+    const [selectedCar, setSelectedCar] = useState('');
     const [formatOrderId, setFormatOrderId] = useState('');
     useEffect(() => {
         if (!initialSetupDone.current && Object.keys(params).length > 0) {
             const bookingInfo = {
-                bookTime: params.bookTime,
-                date: params.date,
+                bookTime: params.bookTime as string,
+                endTime: params.endTime as string,
+                date: params.date as string,
                 carID: params.carID as string,
                 chargingWatt: params.chargingWatt as string,
                 connectorID: params.connectorID as string,
@@ -38,6 +42,21 @@ const PaymentSummaryPageComponent = () => {
         }
     }, [params, setBookingInfo]);
 
+    useEffect(() => {
+        const fetchDefaultCar = async () => {
+            try {
+                const response = await chargeStationService.getUserDefaultCars();
+                if (response) {
+                    console.log('default car', response.data.id);
+                    setSelectedCar(response.data.id);
+                }
+            } catch (error) {
+                console.log(error);
+            }
+        };
+        fetchDefaultCar();
+    }, []);
+
     const { bookTime, date, carID, chargingWatt, connectorID, price, stationID, user, paymentFee, carCapacitance } =
         useBookingStore();
 
@@ -56,60 +75,94 @@ const PaymentSummaryPageComponent = () => {
 
     const promotion_code = selectedCouponRedeemCode || '';
 
-    const convertEndTime = (num1: number) => {
-        switch (num1) {
-            case 20:
-                return 25;
-            case 25:
-                return 30;
-            case 30:
-                return 40;
-            case 40:
-                return 45;
+    // const convertEndTime = (num1: number) => {
+    //     switch (num1) {
+    //         case 20:
+    //             return 25;
+    //         case 25:
+    //             return 30;
+    //         case 30:
+    //             return 40;
+    //         case 40:
+    //             return 45;
+    //     }
+    // };
+
+    // function convertToUTC(date, bookTime) {
+    //     const currentYear = new Date().getFullYear();
+    //     const [month, day] = date.split('/');
+    //     const fullDate = new Date(`${currentYear}-${month}-${day}T${bookTime}:00`);
+    //     fullDate.setHours(fullDate.getHours());
+    //     return fullDate;
+    // }
+
+    // const book_time = convertToUTC(date, bookTime);
+    // const timeRequiredInMinute = convertEndTime(Number(chargingWatt.split(' ')[0]));
+
+    // function findEndTime(num1, book_time) {
+    //     const date = new Date(book_time);
+    //     date.setMinutes(date.getMinutes() + num1);
+    //     return date;
+    // }
+
+    // let end_time;
+    // if (chargingWatt === '') {
+    //     end_time = book_time;
+    // } else {
+    //     const endingTime = findEndTime(timeRequiredInMinute, book_time);
+    //     end_time = endingTime;
+    // }
+
+    const total_fee = parseInt(finalFee, 10);
+
+    function convertToUTC(date: string, time: string): Date {
+        const [year, month, day] = date.split('-').map(Number);
+
+        if (isNaN(year) || isNaN(month) || isNaN(day)) {
+            console.error('Invalid date format:', date);
+            return new Date(NaN); // Return invalid date
         }
-    };
 
-    function convertToUTC(date, bookTime) {
-        const currentYear = new Date().getFullYear();
-        const [month, day] = date.split('/');
-        const fullDate = new Date(`${currentYear}-${month}-${day}T${bookTime}:00`);
-        fullDate.setHours(fullDate.getHours());
-        return fullDate;
-    }
+        const [hours, minutes] = time.split(':').map(Number);
 
-    const book_time = convertToUTC(date, bookTime);
-    const timeRequiredInMinute = convertEndTime(Number(chargingWatt.split(' ')[0]));
+        if (isNaN(hours) || isNaN(minutes)) {
+            console.error('Invalid time format:', time);
+            return new Date(NaN); // Return invalid date
+        }
 
-    function findEndTime(num1, book_time) {
-        const date = new Date(book_time);
-        date.setMinutes(date.getMinutes() + num1);
-        return date;
-    }
+        // Create a date in local time
+        const localDate = new Date(year, month - 1, day, hours, minutes);
 
-    let end_time;
-    if (chargingWatt === '') {
-        end_time = book_time;
-    } else {
-        const endingTime = findEndTime(timeRequiredInMinute, book_time);
-        end_time = endingTime;
+        // Convert to UTC
+        const utcDate = new Date(localDate.toUTCString());
+        return utcDate;
     }
 
     const handleSubmitPayment = async () => {
+        console.log('hi');
         let type = 'reservation';
         let is_ic_call = false;
-        console.log('i am handleSubmitPayment, connectorID:', connectorID);
+
+        const utcBookTime = convertToUTC(params.date as string, params.bookTime as string);
+        const utcEndTime = convertToUTC(params.date as string, params.endTime as string);
+
+        if (isNaN(utcBookTime.getTime()) || isNaN(utcEndTime.getTime())) {
+            console.error('Invalid date or time');
+            // Handle the error appropriately, maybe show an alert to the user
+            return;
+        }
 
         try {
             const response = await walletService.submitPayment(
                 stationID,
                 connectorID,
                 user,
-                book_time,
-                end_time,
+                utcBookTime,
+                utcEndTime,
                 total_power,
                 total_fee,
                 promotion_code,
-                carID,
+                selectedCar,
                 type,
                 is_ic_call
             );
@@ -125,27 +178,13 @@ const PaymentSummaryPageComponent = () => {
                 console.log('400 error in paymentSummaryPageComponent');
                 Alert.alert('餘額不足', '您的餘額不足,請充值後再試。');
             } else {
-                console.log('submit payment failed:', response.status);
+                console.log('submit payment failed:', response);
             }
         } catch (error) {
             console.log('submit payment error:', error);
         }
     };
 
-    const total_fee = parseInt(finalFee, 10);
-
-    // console.log(' i am only console.log all variables for clarity:', {
-    //     stationID,
-    //     connectorID,
-    //     user,
-    //     book_time,
-    //     end_time,
-    //     total_power,
-    //     total_fee,
-    //     promotion_code,
-    //     carID
-    // });
-
     return (
         <SafeAreaView className="flex-1 bg-white" edges={['top', 'left', 'right']}>
             <ScrollView className="flex-1 mx-[5%]" showsVerticalScrollIndicator={false}>

+ 164 - 0
component/chargingPage/penaltyPaymentPageComponent.tsx

@@ -0,0 +1,164 @@
+import { View, Text, ScrollView, Pressable, StyleSheet, Alert } from 'react-native';
+import { SafeAreaView } from 'react-native-safe-area-context';
+import { router, useLocalSearchParams, useNavigation } from 'expo-router';
+import NormalButton from '../global/normal_button';
+import { PreviousPageBlackSvg, PreviousPageSvg } from '../global/SVG';
+import useCouponStore from '../../providers/coupon_store';
+import { useEffect } from 'react';
+import useBookingStore from '../../providers/booking_store';
+import { chargeStationService } from '../../service/chargeStationService';
+import useUserInfoStore from '../../providers/userinfo_store';
+
+const PenaltyPaymentPageComponent = () => {
+    const params = useLocalSearchParams();
+    const { userID } = useUserInfoStore();
+    console.log('params in penaltyPaymentPageComponent', params);
+    const navigation = useNavigation();
+
+    useEffect(() => {
+        navigation.setOptions({
+            gestureEnabled: false
+        });
+    }, [navigation]);
+    const convertBookingDateTime = (isoDateString: string): { date: string; time: string } => {
+        const bookingDate = new Date(isoDateString);
+
+        // Adjust to local time (+8 hours)
+        bookingDate.setHours(bookingDate.getHours() + 8);
+
+        // Format date as "MM-DD"
+        const date = `${(bookingDate.getMonth() + 1).toString().padStart(2, '0')}-${bookingDate
+            .getDate()
+            .toString()
+            .padStart(2, '0')}`;
+
+        // Format time as "HH:mm"
+        const time = `${bookingDate.getHours().toString().padStart(2, '0')}:${bookingDate
+            .getMinutes()
+            .toString()
+            .padStart(2, '0')}`;
+
+        return { date, time };
+    };
+
+    const { date, time } = convertBookingDateTime(params.book_time);
+    const { date: end_date, time: end_time } = convertBookingDateTime(params.end_time as string);
+    const { date: actual_end_date, time: actual_end_time } = convertBookingDateTime(params.actual_end_time as string);
+
+    const payload = {
+        userId: userID,
+        amount: parseFloat(params.penalty_fee as string),
+        reservationId: params.id
+    };
+
+    const handlePayment = async () => {
+        try {
+            const result = await chargeStationService.payPenalty(payload);
+            if (result) {
+                Alert.alert('支付成功', '罰款已成功支付', [{ text: '確認', onPress: () => router.replace('/') }]);
+            } else {
+                Alert.alert('支付失敗', '請稍後再試');
+            }
+        } catch (error) {
+            console.error('Payment error:', error);
+            Alert.alert('支付錯誤', '發生錯誤,請稍後再試');
+        }
+    };
+
+    return (
+        <SafeAreaView style={{ flex: 1, backgroundColor: 'white' }} edges={['top', 'left', 'right']}>
+            <ScrollView className="flex-1" showsVerticalScrollIndicator={false}>
+                <View className="flex-1">
+                    <View className="pl-8 pt-8">
+                        <Text className="text-3xl mt-8">尚未繳付罰款的充電記錄</Text>
+                    </View>
+
+                    <View className="flex-1 mt-4 mx-[5%]">
+                        <View className="flex-1 flex-row items-center pb-3">
+                            <View className="flex-1 flex-column">
+                                <Text style={styles.grayColor} className="text-base">
+                                    充電到期時間
+                                </Text>
+                                <Text style={styles.greenColor} className="text-4xl text-center  pt-2">
+                                    {end_time}
+                                </Text>
+                            </View>
+                            <View className="flex-1 flex-column">
+                                <Text style={styles.grayColor} className="text-base pl-7">
+                                    實際充電結束時間
+                                </Text>
+                                <Text style={styles.greenColor} className="text-4xl text-center pt-2">
+                                    {actual_end_time}
+                                </Text>
+                            </View>
+                        </View>
+                        <View className="flex-1 flex-column justify-center space-y-1 pb-3">
+                            <Text style={styles.grayColor} className="text-base">
+                                充電日期
+                            </Text>
+                            <Text style={styles.greenColor} className="text-base">
+                                {date}
+                            </Text>
+                        </View>
+                        <View className="flex-1 flex-column justify-center space-y-1 pb-3">
+                            <Text style={styles.grayColor} className="text-base">
+                                充電地點
+                            </Text>
+                            <Text style={styles.greenColor} className="text-base ">
+                                Crazy Charge(偉業街)
+                            </Text>
+                        </View>
+                        <View className="flex-1 flex-column justify-center space-y-1 pb-3">
+                            <Text style={styles.grayColor} className="text-base">
+                                罰款金額
+                            </Text>
+                            <Text style={styles.greenColor} className="text-lg ">
+                                {params.penalty_fee}
+                            </Text>
+                        </View>
+                        <View className="flex-1 flex-column justify-center space-y-1 pb-3">
+                            <Text style={styles.grayColor} className="text-base">
+                                訂單編號
+                            </Text>
+                            <Text style={styles.greenColor} className=" ">
+                                {params.format_order_id}
+                            </Text>
+                        </View>
+                    </View>
+                </View>
+
+                <View className="border-t mx-4 border-[#CCCCCC]"></View>
+                <View className="flex-1 mx-[5%] mt-4 space-y-1">
+                    <View className="mt-4">
+                        <NormalButton
+                            title={
+                                <Text
+                                    style={{
+                                        color: 'white',
+                                        fontSize: 16,
+                                        fontWeight: '800'
+                                    }}
+                                >
+                                    支付罰款
+                                </Text>
+                            }
+                            onPress={handlePayment}
+                            extendedStyle={{ padding: 24, marginTop: 24 }}
+                        />
+                    </View>
+                </View>
+            </ScrollView>
+        </SafeAreaView>
+    );
+};
+
+export default PenaltyPaymentPageComponent;
+
+const styles = StyleSheet.create({
+    grayColor: {
+        color: '#888888'
+    },
+    greenColor: {
+        color: '#02677D'
+    }
+});

+ 2 - 0
providers/booking_store.tsx

@@ -2,6 +2,7 @@ import { create } from 'zustand';
 
 interface BookingInfo {
     bookTime: string;
+    endTime: string;
     carID: string;
     date: string;
     chargingWatt: string;
@@ -25,6 +26,7 @@ interface BookingStore extends BookingInfo {
 
 const initialState: BookingInfo = {
     bookTime: '',
+    endTime: '',
     carID: '',
     date: '',
     chargingWatt: '',

+ 45 - 0
service/chargeStationService.tsx

@@ -84,6 +84,27 @@ class ChargeStationService {
         }
     }
 
+    async getReservationWithSize(size: number) {
+        try {
+            console.log('i am in getReservationWithSize');
+            const response = await axios.get(
+                `${this.apiUrl}/clients/reservation/connectors/2405311022116801000/${size}`,
+                {
+                    headers: {
+                        Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
+                    }
+                }
+            );
+            if (response.status === 200 || response.status === 201) {
+                return response.data;
+            } else {
+                console.log('invalid response in getReservationWithSize', response);
+            }
+        } catch (error) {
+            console.log('error in getReservationWithSize', error);
+        }
+    }
+
     async addCar(licensePlate: string, carBrandFk: string, carTypeFk: string, isDefault: boolean) {
         try {
             const response = await axios.post(
@@ -488,5 +509,29 @@ class ChargeStationService {
             return null;
         }
     }
+
+    async payPenalty(penaltyData: any) {
+        try {
+            const response = await axios.post(`${this.apiUrl}/clients/pay/penalty`, penaltyData, {
+                headers: {
+                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
+                }
+            });
+            if (response.status === 200 || response.status === 201) {
+                console.log('Penalty payment successful');
+                return response.data;
+            } else {
+                console.log('Invalid response for penalty payment');
+                return null;
+            }
+        } catch (error) {
+            if (axios.isAxiosError(error)) {
+                console.error('Penalty payment error:', error.response?.data?.message || error.message);
+            } else {
+                console.error('An unexpected error occurred during penalty payment:', error);
+            }
+            return null;
+        }
+    }
 }
 export const chargeStationService = new ChargeStationService();