浏览代码

Merge branch 'new/4' of kuns/crazycharge-app into main

kuns 1 月之前
父节点
当前提交
c402694c75

+ 1 - 1
.env.development

@@ -1,2 +1,2 @@
 EXPO_PUBLIC_NODE_ENV=development
-EXPO_PUBLIC_API_URL=http://192.168.1.42:12000/api/v1
+EXPO_PUBLIC_API_URL=http://47.115.173.98:12000/api/v1

+ 1 - 1
.env.preview

@@ -1,2 +1,2 @@
 EXPO_PUBLIC_NODE_ENV=perview
-EXPO_PUBLIC_API_URL=https://charging.ayftech.xyz/api/v1
+EXPO_PUBLIC_API_URL=http://47.115.173.98:12000/api/v1

+ 12 - 0
app/(auth)/(tabs)/(account)/chargingDetailsPage.tsx

@@ -0,0 +1,12 @@
+import { View, Text } from 'react-native';
+import ChargingDetailsPageComponent from '../../../../component/accountPages/chargingDetailsPageComponent';
+
+const ChargingDetailsPage = () => {
+    return (
+        <View className="flex-1">
+            <ChargingDetailsPageComponent />
+        </View>
+    );
+};
+
+export default ChargingDetailsPage;

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

@@ -210,7 +210,7 @@ const optionPage = () => {
                                         }
                                     );
                                 } else {
-                                    Alert.alert('提您', '使用優惠券的交易每度電以正價$3.5元計算!', [
+                                    Alert.alert('提您', '使用優惠券的交易每度電以正價$3.5元計算!', [
                                         { text: '我知道了', onPress: () => router.push('/selectCoupon') }
                                     ]);
                                 }

+ 259 - 0
component/accountPages/chargingDetailsPageComponent.tsx

@@ -0,0 +1,259 @@
+import { View, Text, Pressable, Dimensions,Image, StyleSheet } from 'react-native';
+import { SafeAreaView } from 'react-native-safe-area-context';
+import { router, useLocalSearchParams } from 'expo-router';
+import { CrossLogoSvg } from '../global/SVG';
+import { useEffect, useMemo, useState, useRef } from 'react';
+import { chargeStationService } from '../../service/chargeStationService';
+import { ChargingDetails, Remark, ElectricityPrice, Special } from '../../service/type/chargeStationType';
+import { format, parseISO } from 'date-fns';
+const ChargingDetailsPageComponent = () => {
+    const screenHeight = Dimensions.get('window').height;
+    const params = useLocalSearchParams();
+    const [list, setList] = useState<ChargingDetails>({} as ChargingDetails);
+    const [remark, setRemark] = useState<Remark>({} as Remark);
+    const [time, setTime] = useState<string>('');
+  useEffect(() => {
+    const fetchData = async () => {
+      const res = await chargeStationService.fetchChargingDetails(params.id.toString())
+      if (res) {
+        const firstItem = Array.isArray(res) && res.length > 0 ? res[0] : null;
+        // 设置充电详情
+        setList(firstItem || ({} as ChargingDetails));
+
+        // 安全地解析 remark 字段
+        let parsedRemark: Remark = {} as Remark;
+        if (firstItem?.remark) {
+          try {
+            parsedRemark = JSON.parse(firstItem.remark) as Remark;
+          } catch (e) {
+            console.warn('Failed to parse remark:', e);
+            parsedRemark = {} as Remark;
+          }
+        }
+        setRemark(parsedRemark);
+
+        // 解析并格式化日期
+        const startTime = res[0].actual_start_time? parseISO(res[0].actual_start_time): null
+        const endTime = res[0].actual_end_time?parseISO(res[0].actual_end_time): null
+        let formattedDate = '';
+        if (startTime && endTime) {
+          // 格式化为指定格式
+          formattedDate = `${format(startTime, 'yyyy/MM/dd HH:mm:ss')}-${format(endTime, 'HH:mm:ss')}`;
+        } else {
+          formattedDate = 'Invalid Time';
+        }
+        setTime(formattedDate)
+      }
+    };
+    fetchData();
+  }, [])
+  const totalPrice = useMemo(() => {
+    if (list.promotion_name) {
+      const price = list?.connector?.EquipmentID?.StationID?.price
+      if (price && remark.TotalPower) {
+        return `${(price * remark.TotalPower).toFixed(1)}`
+      }
+      return '0'
+    } else {
+      if (list.total_fee && list.withdraw_fee) {
+        let actual_fee = list.total_fee - list.withdraw_fee
+        const value = actual_fee <= 0? '0': actual_fee % 1 === 0? `${actual_fee}`: `${actual_fee.toFixed(1)}`
+        return value
+      }
+      return '0';
+    }
+  }, [list]);
+  const couponPrice = useMemo(() => {
+    if (list.promotion_name) {
+      let actual_fee = (list.total_fee - list.withdraw_fee) > 0 ? (list.total_fee - list.withdraw_fee) : 0;
+      return actual_fee.toFixed(1)
+    }
+  }, [list])
+    return (
+        <SafeAreaView className="flex-1 bg-white" edges={['top']}>
+            <View style={{ minHeight: screenHeight, flex: 1 }}>
+                <View className="mx-[5%]" style={{ marginTop: 25}}>
+                  <Pressable
+                      onPress={() => {
+                          if (router.canGoBack()) {
+                              router.back();
+                          } else {
+                              router.replace('/accountMainPage');
+                          }
+                      }}
+                  >
+                    <CrossLogoSvg />
+                  </Pressable>
+                  <View className="items-center px-3">
+                    <Image
+                        source={require('../../assets/ccLogo.png')}
+                        resizeMode="contain"
+                        style={{
+                            width: screenHeight > 750 ? 200 : 110,
+                            height: screenHeight > 750 ? 200 : 110
+                        }}
+                    />
+                    <Text style={styles.totalPrice}>{list.promotion_name? couponPrice:totalPrice}</Text>
+                    <View style={styles.viewLine}></View>
+                    <View className='w-full flex-row justify-between mt-6 pr-10'>
+                      <Text style={styles.leftLable}>訂單编號: </Text>
+                      <Text style={styles.rightLable}>{list.format_order_id}</Text>
+                    </View>
+                    <View className='w-full flex-row justify-between my-3 pr-10'>
+                      <Text style={styles.leftLable}>充電時間: </Text>
+                      <Text style={styles.rightLable}>{time}</Text>
+                    </View>
+                    <View className='w-full flex-row justify-between pr-10 mb-4'>
+                      <Text style={styles.leftLable}>充電站位置:</Text>
+                      <Text style={styles.rightLable}>{params.chargeStationName}</Text>
+                    </View>
+                    <View style={styles.viewLine}></View>
+                    <ChargingDataComponent list={list} remark={remark} totalPrice={totalPrice}/>
+                    <View style={styles.viewLine}></View>
+                    <View className='w-full flex-row justify-between mt-6 pr-10'>
+                      <View>
+                        <Text style={styles.leftLable}>實付:</Text>
+                        {list.promotion_name ? <Text style={{fontSize: 12, color:'#888888'}}>優惠券支付</Text>: null}
+                      </View>
+                      <Text style={styles.rightLable}>${list.promotion_name? couponPrice:totalPrice}</Text>
+                    </View>
+                  </View>
+                </View>
+                <View style={{ width: "100%",height: 130 }} />
+            </View>
+        </SafeAreaView>
+    );
+};
+interface ChargingDataComponentProps {
+    list: ChargingDetails;
+    totalPrice: string;
+    remark: Remark;
+}
+const ChargingDataComponent: React.FC<ChargingDataComponentProps> = ({
+    list,
+    totalPrice,
+    remark
+}) => {
+  const hasFetchedPrice = useRef(false); // 添加 ref 跟踪是否已获取过价格
+  const [rush, setRush] = useState<Special>({} as Special)
+  const [elses, setElses ] = useState<Special>({} as Special)
+  const [off, setOff] = useState<Special>({} as Special)
+  useEffect(() => {
+    if (!list.promotion_name && !hasFetchedPrice.current && list.actual_start_time) {
+      chargeStationService.fetchElectricityPrice(list.pricemodel_id || 'a').then(res => {
+        hasFetchedPrice.current = true; // 标记为已调用
+        const date = new Date(list.actual_start_time);
+        const str = (date.toLocaleString('en-US', { weekday: 'short' })).toLowerCase();
+        if (res && res.length > 0) {
+          if (remark.RushKwh) {
+            const obj = (res[1][str as keyof ElectricityPrice]) as Special
+            setRush(obj)
+          }
+          if (remark.ElseKwh) {
+            const obj = (res[2][str as keyof ElectricityPrice]) as Special
+            setElses(obj)
+          }
+          if (remark.OffKwh) {
+            const obj = (res[0][str as keyof ElectricityPrice]) as Special
+            setOff(obj)
+          }
+        }
+      })
+    }
+  }, [list.actual_start_time])
+  
+  if (!list.promotion_name) {
+    return (
+      <View>
+        {(remark.RushKwh) ? 
+        <View>
+          <View className='w-full flex-row justify-between mt-4 pr-10'>
+            <Text style={styles.leftLable}>峰時總電量: </Text>
+            <Text style={styles.rightLable}>{remark.RushKwh?.toFixed(1)}</Text>
+          </View>
+          <View className='w-full flex-row justify-between my-3 pr-10'>
+              <Text style={styles.leftLable}>峰時電價({rush.from}-{rush.to}):</Text>
+            <Text style={styles.rightLable}>${rush.price}</Text>
+          </View>
+          <View className='w-full flex-row justify-between pr-10 mb-3'>
+            <Text style={styles.leftLable}>峰時總電費:</Text>
+            
+            <Text style={styles.rightLable}>${remark.RushCharge?.toFixed(1)}</Text>
+          </View>
+        </View>: null }
+        {(remark.ElseKwh) ? 
+        <View>
+          <View className='w-full flex-row justify-between mt-4 pr-10'>
+            <Text style={styles.leftLable}>平時總電量: </Text>
+            <Text style={styles.rightLable}>{remark.ElseKwh?.toFixed(1)}</Text>
+          </View>
+          <View className='w-full flex-row justify-between my-3 pr-10'>
+            <Text style={styles.leftLable}>平時電價({elses.from}-{elses.to}):</Text>
+
+            <Text style={styles.rightLable}>${elses.price}</Text>
+          </View>
+          <View className='w-full flex-row justify-between pr-10 mb-3'>
+            <Text style={styles.leftLable}>平時總電費:</Text>
+            
+            <Text style={styles.rightLable}>${remark.ElseCharge?.toFixed(1)}</Text>
+          </View>
+        </View>: null }
+        {(remark.OffKwh) ? 
+        <View>
+          <View className='w-full flex-row justify-between mt-4 pr-10'>
+            <Text style={styles.leftLable}>穀時總電量: </Text>
+            <Text style={styles.rightLable}>{remark.OffKwh?.toFixed(1)}</Text>
+          </View>
+          <View className='w-full flex-row justify-between my-3 pr-10'>
+              <Text style={styles.leftLable}>穀時電價({off.from}-{off.to}): </Text>
+            <Text style={styles.rightLable}>${off.price}</Text>
+          </View>
+          <View className='w-full flex-row justify-between pr-10 mb-3'>
+            <Text style={styles.leftLable}>穀時總電費:</Text>
+            
+            <Text style={styles.rightLable}>${remark.OffCharge?.toFixed(1)}</Text>
+          </View>
+        </View>: null }
+      </View>
+    )
+  } else {
+    return (
+      <View>
+        <View className='w-full flex-row justify-between mt-4 pr-10'>
+            <Text style={styles.leftLable}>總電量: </Text>
+            <Text style={styles.rightLable}>{remark.TotalPower?.toFixed(1)}</Text>
+          </View>
+          <View className='w-full flex-row justify-between my-3 pr-10'>
+              <Text style={styles.leftLable}>電價: </Text>
+            <Text style={styles.rightLable}>${list?.connector?.EquipmentID?.StationID?.price}</Text>
+          </View>
+          <View className='w-full flex-row justify-between pr-10 mb-3'>
+            <Text style={styles.leftLable}>總電費: </Text>
+            
+            <Text style={styles.rightLable}>${totalPrice}</Text>
+          </View>
+      </View>
+    )
+  }
+
+}
+const styles = StyleSheet.create({
+  viewLine: {
+    width: '100%',
+    height: 1,
+    backgroundColor: '#E5E5E5',
+  },
+  totalPrice: {
+    fontSize: 26,
+    fontWeight: 'bold',
+    marginBottom: 25,
+  },
+  leftLable: {
+    fontSize: 18,
+    color:'#888888',
+  },
+  rightLable: {
+    fontSize: 17
+  },
+})
+export default ChargingDetailsPageComponent;

+ 30 - 31
component/accountPages/walletPageComponent.tsx

@@ -18,26 +18,28 @@ import {
 import { SafeAreaView } from 'react-native-safe-area-context';
 import { router } from 'expo-router';
 import { CrossLogoSvg } from '../global/SVG';
-import { useEffect, useRef, useState } from 'react';
+import { use, useEffect, useRef, useState } from 'react';
 import { walletService } from '../../service/walletService';
 import NormalButton from '../global/normal_button';
-import { formatCouponDate, formatDate } from '../../util/lib';
-import { set } from 'date-fns';
-import { reloadAppAsync } from 'expo';
 import sha256 from 'crypto-js/sha256';
-import { useCallback } from 'react';
-
 import { useChargingStore } from '../../providers/scan_qr_payload_store';
-
-const AmountInputModal = ({ visible, onClose, onConfirm }) => {
-    const amounts = [
-        // { amount: 1, percentage: 0 },
-        { amount: 200, percentage: 0 },
-        { amount: 500, percentage: 25 },
-        { amount: 1000, percentage: 100 },
-        { amount: 2000, percentage: 300 }
-    ];
-
+import { PaymentBonusList } from '../../service/type/walletServiceType';
+interface AmountInputModalProps {
+    visible: boolean;
+    onClose: () => void;
+    onConfirm: (amount: number) => void;
+}
+const AmountInputModal = ({ visible, onClose, onConfirm }: AmountInputModalProps) => {
+    const [amounts, setAmounts] = useState<Array<{amount: number, percentage: number}>>([]);
+    useEffect(() => {
+        const fetchData = async () => {
+            const res: PaymentBonusList[] = await walletService.getPaymentBonusList()
+            setAmounts(res.map(item => ({amount: item.base_amount, percentage: item.gift_amount})))
+        }
+        if (visible){
+            fetchData()
+        }
+    }, [visible])
     const getFontSize = () => {
         const { width } = Dimensions.get('window');
         if (width < 320) return 8;
@@ -110,7 +112,7 @@ export const IndividualCouponComponent = ({
     date,
     setOpacity,
     redeem_code,
-    onCouponClick,
+    onCouponClick = () => {}, // 添加默认空函数防止 undefined 报错
     noCircle
 }: {
     title: string;
@@ -135,10 +137,10 @@ export const IndividualCouponComponent = ({
             {/* largest container */}
             <Pressable
                 className="flex-row w-full h-full "
-                onPress={setOpacity ? () => {} : () => onCouponClick(redeem_code)}
+                onPress={setOpacity ? () => {} : () => onCouponClick(redeem_code as string, title)}
             >
                 {/* price column on the left */}
-                <View className="flex-row items-center w-[31%] items-center justify-center">
+                <View className="flex-row items-center w-[31%] justify-center">
                     <Text className="pl-1 lg:pl-2 text-[#02677D] text-base md:text-lg lg:text-xl">$</Text>
                     <Text className="text-3xl lg:text-4xl text-[#02677D] font-[600]">{price}</Text>
                 </View>
@@ -164,9 +166,9 @@ export const IndividualCouponComponent = ({
                                     justifyContent: 'center',
                                     alignItems: 'center'
                                 }}
-                                className={`${promotion_code?.includes(redeem_code) ? 'bg-[#02677D]' : 'bg-white'}`}
+                                className={`${promotion_code?.includes(redeem_code as string) ? 'bg-[#02677D]' : 'bg-white'}`}
                             >
-                                <Text className="text-white">{promotion_code?.indexOf(redeem_code) + 1}</Text>
+                                <Text className="text-white">{promotion_code?.indexOf(redeem_code as string) + 1}</Text>
                             </View>
                         )}
                     </View>
@@ -187,11 +189,9 @@ export const IndividualCouponComponent = ({
 const WalletPageComponent = () => {
     const [walletBalance, setWalletBalance] = useState<string | null>(null);
     const [loading, setLoading] = useState<boolean>(false);
-    const [modalVisible, setModalVisible] = useState(false);
     const [coupons, setCoupons] = useState([]);
     const [paymentType, setPaymentType] = useState({});
     const [userID, setUserID] = useState('');
-    const [selectedPaymentType, setSelectedPaymentType] = useState<string | null>(null);
     const [amount, setAmount] = useState<number>(0);
     const [amountModalVisible, setAmountModalVisible] = useState(false);
     const [outTradeNo, setOutTradeNo] = useState('');
@@ -199,7 +199,7 @@ const WalletPageComponent = () => {
     const [paymentStatus, setPaymentStatus] = useState(null);
     const [isExpectingPayment, setIsExpectingPayment] = useState(false);
     const appState = useRef(AppState.currentState);
-    const paymentInitiatedTime = useRef(null);
+    const paymentInitiatedTime = useRef<number>(null);
     // 优惠券注释
     useEffect(() => {
         const fetchData = async () => {
@@ -261,7 +261,7 @@ const WalletPageComponent = () => {
             const result = await walletService.checkPaymentStatus(outTradeNo);
             setPaymentStatus(result);
 
-            if (result && !result.some((item) => item.errmsg?.includes('處理中'))) {
+            if (result && !result.some((item: any) => item.errmsg?.includes('處理中'))) {
                 // Payment successful
 
                 Alert.alert('Success', 'Payment was successful!', [
@@ -323,11 +323,11 @@ const WalletPageComponent = () => {
             .replace(/\B(?=(\d{3})+(?!\d))/g, ',');
     };
 
-    const filterPaymentOptions = (options, allowedKeys) => {
+    const filterPaymentOptions = (options: Record<string, any>, allowedKeys: string[]) => {
         return Object.fromEntries(Object.entries(options).filter(([key]) => allowedKeys.includes(key)));
     };
 
-    function formatTime(utcTimeString) {
+    function formatTime(utcTimeString: string) {
         // Parse the UTC time string
         const date = new Date(utcTimeString);
 
@@ -356,7 +356,7 @@ const WalletPageComponent = () => {
         fetchPaymentType();
     }, []);
 
-    const handleAmountConfirm = async (inputAmount) => {
+    const handleAmountConfirm = async (inputAmount: number) => {
         setAmountModalVisible(false);
         try {
             const response = await walletService.getOutTradeNo();
@@ -365,8 +365,7 @@ const WalletPageComponent = () => {
                 setIsExpectingPayment(true);
                 paymentInitiatedTime.current = new Date().getTime();
                 const now = new Date();
-                const formattedTime = formatTime(now);
-                const out_trade_no = response;
+                const formattedTime = formatTime(now.toISOString());
 
                 let amount = inputAmount * 100;
                 const origin = 'https://openapi-hk.qfapi.com/checkstand/#/?';
@@ -385,7 +384,7 @@ const WalletPageComponent = () => {
                     txdtm: formattedTime
                 };
 
-                const paramStringify = (json, flag?) => {
+                const paramStringify = (json: Record<string, any>, flag?: boolean) => {
                     let str = '';
                     let keysArr = Object.keys(json);
                     keysArr.sort().forEach((val) => {

+ 5 - 5
component/chargingPage/noChargingOngoingPageComponent.tsx

@@ -10,20 +10,19 @@ import { chargeStationService } from '../../service/chargeStationService';
 // const MAX_RETRIES = 3; // Maximum number of retry attempts
 
 const NoChargingOngoingPageComponent = () => {
-    const [newAvailableConnectors, setNewAvailableConnectors] = useState([]);
+    const [newAvailableConnectors, setNewAvailableConnectors] = useState<any>([]);
     useFocusEffect(
         useCallback(() => {
             let isMounted = true; // Simple cleanup flag
             const fetchAllConnectors = async () => {
                 try {
                     const newAvailableConnectors = await chargeStationService.NewfetchAvailableConnectors();
-
                     // Only update state if component is still mounted
                     if (isMounted) {
                         // Sort the connectors based on stationID
                         const sortedConnectors = [...newAvailableConnectors].sort((a, b) => {
                             // Custom sorting order
-                            const order = {
+                            const order: Record<string, number> = {
                                 '2405311022116801000': 1, // 觀塘偉業街
                                 '2411291610329331000': 2, // 黃竹坑
                                 '2501161430118231000': 3 // 沙頭角
@@ -66,7 +65,8 @@ const NoChargingOngoingPageComponent = () => {
                             availableConnectors: item.availableConnectors,
                             imageSource: item.image,
                             stationLng: item.stationLng,
-                            stationLat: item.stationLat
+                            stationLat: item.stationLat,
+                            pricemodel_id: item.pricemodel_id
                         }
                     });
                 }}
@@ -120,7 +120,7 @@ const NoChargingOngoingPageComponent = () => {
                             <Text className="text-lg mx-[5%] mb-6">立刻前往Crazy Charge 充電站充電吧!</Text>
 
                             <View>
-                                {newAvailableConnectors?.map((item, index) => (
+                                {newAvailableConnectors?.map((item: any, index: number) => (
                                     <View key={index}>
                                         <View className="border-b border-gray-200" />
                                         <StationRow item={item} key={index} />

+ 13 - 10
component/chargingPage/penaltyPaymentPageComponent.tsx

@@ -2,7 +2,7 @@ import { View, Text, ScrollView, Pressable, StyleSheet, Alert } from 'react-nati
 import { SafeAreaView } from 'react-native-safe-area-context';
 import { router, useLocalSearchParams, useNavigation } from 'expo-router';
 import NormalButton from '../global/normal_button';
-import { useEffect } from 'react';
+import { useEffect, useState } from 'react';
 import { chargeStationService } from '../../service/chargeStationService';
 import useUserInfoStore from '../../providers/userinfo_store';
 import { PreviousPageBlackSvg } from '../global/SVG';
@@ -10,14 +10,21 @@ import { PreviousPageBlackSvg } from '../global/SVG';
 const PenaltyPaymentPageComponent = () => {
     const params = useLocalSearchParams();
     const { userID } = useUserInfoStore();
-    console.log('params in penaltyPaymentPageComponent', params);
     const navigation = useNavigation();
-
+    const [leaving_time, setLeavingTime] = useState<string | null>(null)
     useEffect(() => {
         navigation.setOptions({
             gestureEnabled: false
         });
     }, [navigation]);
+    useEffect(() => {
+        chargeStationService.fetchChargingDetails(params.id.toString()).then(res => {
+          if (res && res[0].charging.length > 0) {
+            const { date, time } = convertBookingDateTime(res[0].charging[0].leaving_time as string);
+            setLeavingTime(time);
+          }
+        })
+    }, [params]);
     const convertBookingDateTime = (isoDateString: string): { date: string; time: string } => {
         const bookingDate = new Date(isoDateString);
 
@@ -41,14 +48,13 @@ const PenaltyPaymentPageComponent = () => {
 
     const calculateUserEndTime = (actualEndTimeStr: string, penaltyFee: string): string => {
         const actualEndTime = new Date(actualEndTimeStr);
-        const penaltyMinutes = Math.floor(parseFloat(penaltyFee) / 3); // $3 per minute
+        const penaltyMinutes = Math.floor(parseFloat(penaltyFee) / 3) + 15 // $3 per minute
         const userEndTime = new Date(actualEndTime.getTime() + penaltyMinutes * 60000); // add minutes
 
         return userEndTime.toISOString();
     };
 
-    const { date, time } = convertBookingDateTime(params.book_time);
-    const { date: end_date, time: end_time } = convertBookingDateTime(params.end_time as string);
+    const { date, time } = convertBookingDateTime(params.book_time as string);
     const { date: actual_end_date, time: actual_end_time } = convertBookingDateTime(params.actual_end_time as string);
     const { time: user_end_time } = convertBookingDateTime(
         calculateUserEndTime(params.actual_end_time as string, params.penalty_fee as string)
@@ -96,9 +102,6 @@ const PenaltyPaymentPageComponent = () => {
                     </Pressable>
                     <Text className="text-3xl my-8 text-center">尚未繳付罰款的充電記錄</Text>
                 </View>
-                {/* <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">
@@ -115,7 +118,7 @@ const PenaltyPaymentPageComponent = () => {
                                 實際充電結束時間
                             </Text>
                             <Text style={styles.greenColor} className="text-4xl text-center pt-2">
-                                {user_end_time}
+                                {leaving_time || user_end_time}
                             </Text>
                         </View>
                     </View>

+ 9 - 6
component/global/bookingTabViewComponent.tsx

@@ -11,14 +11,14 @@ interface BookingTabViewComponentProps {
 }
 
 // 更新 findStationByConnectorId 函数以增加安全性
-const findStationByConnectorId = (allStations, targetConnectorId) => {
+const findStationByConnectorId = (allStations: any[], targetConnectorId: string) => {
     if (!Array.isArray(allStations) || !targetConnectorId) {
         return undefined;
     }
 
     return allStations.find((station) =>
-        station?.snapshot?.EquipmentInfos?.some((equipment) =>
-            equipment?.ConnectorInfos?.some((connector) => connector?.ConnectorID === targetConnectorId)
+        station?.snapshot?.EquipmentInfos?.some((equipment: any) =>
+            equipment?.ConnectorInfos?.some((connector: any) => connector?.ConnectorID === targetConnectorId)
         )
     );
 };
@@ -66,6 +66,7 @@ const processReservations = (reservations: any [], allStations: string [], isFut
         })
         .slice(0, 33)
         .map((reservation) => {
+
             // 添加对 reservation 的安全检查
             if (!reservation) {
                 return {} as TabItem; // 返回默认对象
@@ -81,7 +82,7 @@ const processReservations = (reservations: any [], allStations: string [], isFut
             }
             let stationInfo = null;
             if (snapshot?.StationID) {
-                stationInfo = validStations.find((station) => station?.id === snapshot.StationID);
+                stationInfo = validStations.find((station: any) => station?.id === snapshot.StationID);
             } else if (snapshot?.connector) {
                 stationInfo = findStationByConnectorId(validStations, snapshot.connector);
             }
@@ -112,7 +113,9 @@ const processReservations = (reservations: any [], allStations: string [], isFut
                 withdraw_fee: reservation.withdraw_fee || 0,
                 actual_fee: (reservation.total_fee || 0) - (reservation.withdraw_fee || 0),
                 current_price: snapshot_price?.current_price || 0,
-                total_power: reservation.total_power || 0
+                total_power: reservation.total_power || 0,
+                id: reservation.id || '',
+                status: reservation.status || {}
             } as TabItem;
         });
 };
@@ -150,7 +153,7 @@ const BookingTabViewComponentInner: React.FC<BookingTabViewComponentProps> = ({
     const completedReservations = processReservations(reservations, stations, false);
     const allReservationItems = [...futureReservations, ...completedReservations];
     // const allReservationItems = [...futureReservations];
-
+    console.log('All Reservation Items Processed:', allReservationItems);
     return (
         <TabViewComponent
             titles={titles}

+ 31 - 12
component/global/chargingRecord.tsx

@@ -13,7 +13,6 @@ import {
     ActivityIndicator,
     Pressable
 } from 'react-native';
-import { TabView, SceneMap, TabBar } from 'react-native-tab-view';
 import { FlashList } from '@shopify/flash-list';
 import { useEffect, useState } from 'react';
 import { calculateDistance } from './distanceCalculator';
@@ -33,6 +32,8 @@ export interface TabItem {
     actual_end_time?: string;
     actual_fee?: number;
     current_price?: number;
+    id?: string;
+    status?: any
 }
 
 interface TabViewComponentProps {
@@ -157,17 +158,6 @@ const TabItem = ({ item, currentLocation }: { item: TabItem; currentLocation: Lo
                                 : ''}
                         </Text>
                     </View>
-                    <View className="flex flex-row  space-x-2">
-                        <Text
-                            style={{
-                                fontWeight: '400',
-                                fontSize: 14,
-                                color: '#222222'
-                            }}
-                        >
-                            每度電金額: ${item.current_price}
-                        </Text>
-                    </View>
                     <Text
                         style={{
                             fontWeight: '400',
@@ -177,6 +167,35 @@ const TabItem = ({ item, currentLocation }: { item: TabItem; currentLocation: Lo
                     >
                         {item.chargeStationName}
                     </Text>
+                    <View className="flex flex-row space-x-2">
+                        {
+                            item.status.id === 7 || item.status.id === 13? 
+                                <Text
+                                    style={{
+                                        fontWeight: '400',
+                                        fontSize: 14,
+                                        color: '#02677D'
+                                    }}
+                                >
+                                    訂單進行中
+                                </Text>
+                                : 
+                                <Text
+                                    style={{
+                                        fontWeight: '400',
+                                        fontSize: 14,
+                                        color: '#02677D'
+                                    }}
+                                    onPress={() => {
+                                        router.push({ pathname: 'chargingDetailsPage', params: { id: item.id, chargeStationName: item.chargeStationName }})
+                                    }}
+                                >
+                                    訂單詳情 &gt;
+                                </Text>
+    
+                            }
+                        
+                    </View>
                 </View>
             </View>
         </Pressable>

+ 1 - 1
component/homePage/homePage.tsx

@@ -195,7 +195,7 @@ const HomePage: React.FC<HomePageProps> = () => {
                         const mostRecentUnpaidReservation = unpaidPenalties.reduce((mostRecent: any, current: any) => {
                             return new Date(mostRecent.created_at) > new Date(current.created_at) ? mostRecent : current;
                         }, unpaidPenalties[0]);
-
+                        console.log('mostRecentUnpaidReservation', mostRecentUnpaidReservation);
                         if (unpaidPenalties.length > 0) {
                             Alert.alert(
                                 '未付罰款',

+ 0 - 1
component/registrationMultiStepForm/formComponent/formPages/loginPage.tsx

@@ -97,7 +97,6 @@ const LoginPage: React.FC<LoginPageProps> = ({ goToNextPage, goToForgetPassWordP
         router.push('(public)/userTermsPage');
     };
     const insets = useSafeAreaInsets();
-    console.log(screenHeight);
     return (
         <ScrollView
             contentContainerStyle={{ flexGrow: 1, justifyContent: 'center' }}

+ 65 - 20
component/resultDetailPage/resultDetailPageComponent.tsx

@@ -20,25 +20,64 @@ import { SafeAreaView } from 'react-native-safe-area-context';
 import { chargeStationService } from '../../service/chargeStationService';
 import * as Location from 'expo-location';
 import { calculateDistance } from '../global/distanceCalculator';
+import { ChargingDetails, Remark, PriceWeek, Special } from '../../service/type/chargeStationType';
 
 interface ChargingStationTabViewProps {
     titles: string[];
+    pricemodel_id: string;
 }
-interface StationCoordinates {
-    StationLat: number;
-    StationLng: number;
+interface ChargingPeriod{
+    event_name: string;
+    price: number;
+    from: string;
+    to: string;
 }
-
-const ChargingStationTabView: React.FC<ChargingStationTabViewProps> = ({ titles }) => {
+const ChargingStationTabView: React.FC<ChargingStationTabViewProps> = ({ titles, pricemodel_id }) => {
     const layout = useWindowDimensions();
+    const [list, setList] = useState<ChargingPeriod []>([])
+    const [strWeek, setStrWeek] = useState<string>('')
+    // 添加AM/PM标识但保持24小时制
+    const addPeriodToTime = (timeString: string): string => {
+        // 假设输入格式为 HH.mm 或 HH:mm
+        const [hours] = timeString.split(/[.:]/).map(Number);
+        
+        if (isNaN(hours)) return timeString;
+        
+        const period = hours >= 12 ? 'PM' : 'AM';
+        
+        return `${timeString}${period}`;
+    };
+    useEffect(() => { 
+        chargeStationService.fetchElectricityPrice(pricemodel_id || 'a').then(res => {
+            const date = new Date();
+            const str = (date.toLocaleString('en-US', { weekday: 'short' })).toLowerCase();
+            setStrWeek(date.toLocaleString('zh', { weekday: 'long' }))
+            const newList = [] as ChargingPeriod[]
+            res?.forEach((item) => {
+                const obj = item[str as keyof PriceWeek]
+                newList.push({event_name: item.event_name, price: obj.price, from: addPeriodToTime(obj.from),to: addPeriodToTime(obj.to)})
+                setList(newList)
+            })
+        })
+    }, [pricemodel_id])
 
     //tab 1
     const FirstRoute = () => (
         <ScrollView style={{ flex: 1, marginHorizontal: '5%' }}>
-            <Text className="text-lg" style={styles.text}>
-                由於充電站車流眾多, 敬請客戶務必於預約時間的十五分鐘內到達充電站。
-                若客戶逾時超過15分鐘,系統將視作自動放棄預約,客戶需要重新預約一次。 本公司有權保留全數費用,恕不退還。
-            </Text>
+            <View>
+                <View className='w-full flex-row justify-between mt-4'>
+                    <Text style={styles.leftLable}>時段</Text>
+                    <Text style={styles.rightLable}>價格(/度)</Text>
+                </View>
+                {
+                    list.map((item, index) => (
+                        <View key={index} className='w-full flex-row justify-between mt-3'>
+                            <Text style={styles.leftLable}>{item.from} - {item.to}</Text>
+                            <Text style={styles.rightLable}>${item.price}</Text>
+                        </View>
+                    ))
+                }
+            </View>
         </ScrollView>
     );
 
@@ -104,22 +143,15 @@ const ResultDetailPageComponent = () => {
     const chargeStationID = params.chargeStationID as string;
     const chargeStationName = params.chargeStationName as string;
     const chargeStationAddress = params.chargeStationAddress as string;
-    const availableConnectorsFromParams = params.availableConnectors;
+    const pricemodel_id = params.pricemodel_id as string;
     const imageSourceProps = params.imageSource;
     const stationLng = params.stationLng as string;
     const stationLat = params.stationLat as string;
     const [isLoading, setIsLoading] = useState(true);
     const [imageSource, setImageSource] = useState();
-    // const chargeStationLat = params.chargeStationLat as string;
-    // const chargeStationLng = params.chargeStationLng as string;
     const [currentLocation, setCurrentLocation] = useState<Location.LocationObject | null>(null);
-    const [distance, setDistance] = useState<string | null>(null);
-    const [coordinates, setCoordinates] = useState<StationCoordinates | null>(null);
     const [price, setPrice] = useState('');
-    const [availableConnectors, setAvailableConnectors] = useState<number | null>(
-        availableConnectorsFromParams ? Number(availableConnectorsFromParams) : null
-    );
-    const [newAvailableConnectors, setNewAvailableConnectors] = useState([]);
+    const [newAvailableConnectors, setNewAvailableConnectors] = useState<any>([]);
     useEffect(() => {
         const imgObj = imageSourceProps? {uri: imageSourceProps} : require('../../assets/dummyStationPicture.png')
         setImageSource(imgObj);
@@ -304,7 +336,7 @@ const ResultDetailPageComponent = () => {
                     <Text className="text-xl pb-2 mx-[5%]" style={styles.text}>
                         充電站資訊
                     </Text>
-                    <ChargingStationTabView titles={['預約充電事項', '其他']} />
+                    <ChargingStationTabView titles={['收費詳情', '其他']} pricemodel_id={pricemodel_id} />
                 </View>
             </ScrollView>
         </SafeAreaView>
@@ -317,5 +349,18 @@ const styles = StyleSheet.create({
     text: {
         fontWeight: 300,
         color: '#000000'
-    }
+    },
+    leftLable: {
+        width: 160,
+        fontSize: 17,
+        color:'#000000',
+        textAlign: 'center'
+    },
+    rightLable: {
+        fontSize: 17,
+        width: 100,
+        textAlign: 'center',
+        borderLeftWidth: 1,
+        paddingLeft: 0,
+    },
 });

+ 7 - 23
component/searchPage/searchResultComponent.tsx

@@ -170,12 +170,7 @@ const SearchResultComponent = () => {
 
         if (currentLocation) {
             const TabItems = await Promise.all(
-                fetchedStations.map(async (station) => {
-                    // const distance = await calculateDistance(
-                    //     Number(station.StationLat),
-                    //     Number(station.StationLng),
-                    //     currentLocation
-                    // );
+                fetchedStations.map(async (station: any) => {
 
                     return {
                         chargeStationAddress: station.Address,
@@ -207,17 +202,6 @@ const SearchResultComponent = () => {
             return `${distanceInKm.toFixed(1)}公里`;
         }
     };
-    const stationImages = {
-        //沙頭角
-        '2501161430118231000': require('../../assets/dummyStationPicture5.jpeg'),
-        //黃竹坑
-        '2411291610329331000': require('../../assets/dummyStationPicture4.jpeg'),
-        //觀塘
-        '2405311022116801000': require('../../assets/dummyStationPicture.png')
-    };
-
-    // const imageSource = stationImages[stationID] || require('../../assets/dummyStationPicture.png');
-    // ************************************************************************************************************************************************
     return (
         <TouchableWithoutFeedback onPress={Keyboard.dismiss}>
             <SafeAreaView className="flex-1" edges={['top', 'left', 'right']}>
@@ -264,8 +248,8 @@ const SearchResultComponent = () => {
                                                 setSearchInput(item.chargeStationName);
                                                 setFilteredItems([]);
                                                 handleRegionChange({
-                                                    latitude: item.lat,
-                                                    longitude: item.lng,
+                                                    latitude: item.lat as number,
+                                                    longitude: item.lng as number,
                                                     latitudeDelta: 0.01,
                                                     longitudeDelta: 0.01
                                                 });
@@ -300,8 +284,8 @@ const SearchResultComponent = () => {
                             <Marker
                                 key={index}
                                 coordinate={{
-                                    latitude: item.lat,
-                                    longitude: item.lng
+                                    latitude: item.lat as number,
+                                    longitude: item.lng as number
                                 }}
                                 title={item.chargeStationName}
                                 description={item.chargeStationAddress}
@@ -324,8 +308,8 @@ const SearchResultComponent = () => {
                                                     key={index}
                                                     onPress={() => {
                                                         handleRegionChange({
-                                                            latitude: item.lat,
-                                                            longitude: item.lng,
+                                                            latitude: item.lat as number,
+                                                            longitude: item.lng as number,
                                                             latitudeDelta: 0.01,
                                                             longitudeDelta: 0.01
                                                         });

+ 2 - 12
context/AuthProvider.tsx

@@ -2,11 +2,10 @@ import { ReactNode, createContext, useEffect, useState } from 'react';
 import { useContext } from 'react';
 import { router, useSegments } from 'expo-router';
 import * as SecureStore from 'expo-secure-store';
-
-import axios from 'axios';
 import { User } from '../types/user';
 
 import { authenticationService } from '../service/authService';
+import {apiClient} from '../service/requets'
 
 type AuthProvider = {
     user: User | null;
@@ -98,17 +97,8 @@ export default function AuthProvider({ children }: { children: ReactNode }) {
     };
 
     const getUserFromAccessToken = async () => {
-        SecureStore.getItemAsync('accessToken').then((aa) => {
-            console.log('sssssss:', aa);
-        });
-
-        const token = await SecureStore.getItemAsync('accessToken');
         try {
-            const res = await axios.get(`${process.env.EXPO_PUBLIC_API_URL}/clients/customer`, {
-                headers: {
-                    Authorization: `Bearer ${token}`
-                }
-            });
+            const res = await apiClient.instance.get(`/clients/customer`);
 
             const items = {
                 address: res.data.address,

+ 61 - 167
service/authService.tsx

@@ -1,44 +1,29 @@
-import axios from 'axios';
+import axios, {isAxiosError} from 'axios';
 import { Alert } from 'react-native';
 import * as SecureStore from 'expo-secure-store';
 import { forgetPasswordFormData } from '../types/signup';
 import { CustomerData } from '../types/signUpFormData';
 import * as FileSystem from 'expo-file-system';
-
+import {apiClient} from './requets'
 class AuthenticationService {
-    private apiUrl: string;
-
-    constructor() {
-        this.apiUrl = process.env.EXPO_PUBLIC_API_URL;
-        if (!this.apiUrl) {
-            throw new Error('API URL is not defined in environment variables');
-        }
-    }
 
     async emailLogin(username: string, password: string, isBinding?: boolean) {
         try {
-            console.log('username in emailLogin auth service', username);
-            console.log('password in emailLogin auth service', password);
-            console.log('isBinding in emailLogin auth service', isBinding);
-            const response = await axios.post(
-                `${this.apiUrl}/public/client/customer/sign-in`,
+            const response = await apiClient.instance.post('/public/client/customer/sign-in',
                 {
                     email: username,
                     password: password,
-                    isBinding: isBinding
+                    isBinding: isBinding,
+                    
                 },
                 {
-                    headers: {
-                        'Content-Type': 'application/json',
-                        Accept: 'application/json'
-                    }
-                }
+                    customConfig: {needAuth: true}
+                },
             );
             if (response.status === 201) {
                 const token = response.data.accessToken;
                 await SecureStore.setItemAsync('accessToken', token);
                 console.log('AccessToken', token);
-                console.log('Login successful!');
                 return true;
             } else {
                 console.error('Login failed:', response.status);
@@ -46,7 +31,7 @@ class AuthenticationService {
                 return false;
             }
         } catch (error) {
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('Login error:', error.response?.data?.message || error.message);
             } else {
                 console.error('An unexpected error occurred:', error);
@@ -58,20 +43,17 @@ class AuthenticationService {
 
     async phoneLogin(username: string | null | undefined, password: string, isBinding?: boolean) {
         try {
-            const response = await axios.post(
-                // `${this.apiUrl}/public/client/customer/sign-in`,
-                // `${this.apiUrl}/public/client/customer/sign-in`,
-                `${this.apiUrl}/public/client/customer/phone/sign-in`,
+            const response = await apiClient.instance.post(
+                `/public/client/customer/phone/sign-in`,
                 {
                     phone: username,
                     password: password,
-                    isBinding: isBinding
+                    isBinding: isBinding,
+                    
                 },
                 {
-                    headers: {
-                        'Content-Type': 'application/json',
-                        Accept: '*/*'
-                    }
+                
+                    customConfig: {needAuth: true}
                 }
             );
             if (response.status === 201) {
@@ -97,19 +79,11 @@ class AuthenticationService {
         console.log('log out successfully, accessToken deleted');
     }
 
-    //BELOW CODES RELATE TO "SIGN UP"
-    //BELOW CODES RELATE TO "SIGN UP"
     async sendOtpToSignUpEmail(email: string) {
         try {
-            const response = await axios.post(
-                `${this.apiUrl}/public/client/customer/otp`,
+            const response = await apiClient.instance.post(
+                `/public/client/customer/otp`,
                 { email: email },
-                {
-                    headers: {
-                        'Content-Type': 'application/json',
-                        Accept: 'application/json'
-                    }
-                }
             );
             if (response.status === 200 || response.status === 201) {
                 return true;
@@ -118,7 +92,7 @@ class AuthenticationService {
                 return false;
             }
         } catch (error) {
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('Error sending OTP:', error.response?.data?.message || error.message);
             } else {
                 console.error('An unexpected error occurred while sending OTP:', error);
@@ -133,11 +107,11 @@ class AuthenticationService {
             if (!fileInfo.exists) {
                 throw new Error('File does not exist');
             }
-
-            const fileExtension = imageUri.split('.').pop().toLowerCase();
+            const fileExtension = imageUri ? imageUri.split('.').pop()?.toLowerCase() : undefined;
+            
             const allowedExtensions = ['jpg', 'jpeg', 'png'];
 
-            if (!allowedExtensions.includes(fileExtension)) {
+            if (fileExtension && !allowedExtensions.includes(fileExtension)) {
                 throw new Error('只接受jpg,jpeg,png格式的圖片');
             }
 
@@ -151,12 +125,10 @@ class AuthenticationService {
                 type: `image/${fileExtension}`
             } as any);
 
-            const accessToken = await SecureStore.getItemAsync('accessToken');
-            const response = await axios.post(`${this.apiUrl}/clients/customer/image?type=uber`, formData, {
+            const response = await apiClient.instance.post(`/clients/customer/image?type=uber`, formData, {
                 headers: {
                     accept: '*/*',
                     'Content-Type': 'multipart/form-data',
-                    Authorization: `Bearer ${accessToken}`
                 }
             });
             console.log('Upload response:', response.data);
@@ -174,15 +146,9 @@ class AuthenticationService {
         setError: React.Dispatch<React.SetStateAction<string>>
     ) {
         try {
-            const response = await axios.put(
-                `${this.apiUrl}/public/client/customer/otp`,
+            const response = await apiClient.instance.put(
+                `/public/client/customer/otp`,
                 { email, code },
-                {
-                    headers: {
-                        'Content-Type': 'application/json',
-                        Accept: 'application/json'
-                    }
-                }
             );
 
             if (response.status === 200) {
@@ -195,7 +161,7 @@ class AuthenticationService {
                 return false;
             }
         } catch (error) {
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('Error verifying OTP:', error.response?.data?.message || error.message);
                 setError('發生意外錯誤,請確保您輸入的電子郵件正確,並再次確認您的OTP驗證碼是否正確。');
             } else {
@@ -208,12 +174,7 @@ class AuthenticationService {
 
     async signUp(data: CustomerData) {
         try {
-            const response = await axios.post(`${this.apiUrl}/public/client/customer`, data, {
-                headers: {
-                    'Content-Type': 'application/json',
-                    Accept: 'application/json'
-                }
-            });
+            const response = await apiClient.instance.post(`/public/client/customer`, data);
             if (response.status === 200 || response.status === 201) {
                 return true;
             } else {
@@ -221,7 +182,7 @@ class AuthenticationService {
                 return false;
             }
         } catch (error) {
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('Error signing up:', error.response?.data?.message || error.message);
             } else {
                 console.error('An unexpected error occurred while signing up:', error);
@@ -230,19 +191,11 @@ class AuthenticationService {
         }
     }
 
-    //BELOW CODES RELATE TO "FORGET PASSWORD"
-    //BELOW CODES RELATE TO "FORGET PASSWORD"
     async sendForgetPasswordOtp(email: string) {
         try {
-            const response = await axios.post(
-                `${this.apiUrl}/public/client/customer/pw/otp`,
+            const response = await apiClient.instance.post(
+                `/public/client/customer/pw/otp`,
                 { email },
-                {
-                    headers: {
-                        'Content-Type': 'application/json',
-                        Accept: 'application/json'
-                    }
-                }
             );
 
             if (response.status === 200 || response.status === 201) {
@@ -253,7 +206,7 @@ class AuthenticationService {
                 return false;
             }
         } catch (error) {
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('Error sending forget password OTP:', error.response?.data?.message || error.message);
             } else {
                 console.error('An unexpected error occurred while sending forget password OTP:', error);
@@ -264,7 +217,7 @@ class AuthenticationService {
 
     async getVersion() {
         try {
-            const response = await axios.get(`${this.apiUrl}/public/client/app/version`);
+            const response = await apiClient.instance.get(`/public/client/app/version`);
             return response.data.data;
         } catch (error) {
             console.error('Error getting version:', error);
@@ -279,7 +232,7 @@ class AuthenticationService {
         setData: React.Dispatch<React.SetStateAction<string>>
     ) {
         try {
-            const res = await axios.put(`${this.apiUrl}/public/client/customer/pw/otp`, {
+            const res = await apiClient.instance.put(`/public/client/customer/pw/otp`, {
                 email: email,
                 code: otp
             });
@@ -299,18 +252,13 @@ class AuthenticationService {
 
     async changePassword(confirmedNewPassword: string, data: string) {
         try {
-            const res = await axios.put(
-                `${this.apiUrl}/clients/customer/pw/forget`,
+            const res = await apiClient.instance.put(
+                `/clients/customer/pw/forget`,
                 { newPassword: confirmedNewPassword },
-                {
-                    headers: {
-                        Authorization: `Bearer ${data}`
-                    }
-                }
             );
             return true;
         } catch (error) {
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('Error changing password:', error.response?.data?.message || error.message);
             } else {
                 console.error('An unexpected error occurred:', error);
@@ -320,19 +268,14 @@ class AuthenticationService {
 
     async changeEmail(email: string | null, token: string | null): Promise<boolean> {
         try {
-            const res = await axios.put(
-                `${this.apiUrl}/clients/customer`,
+            const res = await apiClient.instance.put(
+                `/clients/customer`,
                 { email: email },
-                {
-                    headers: {
-                        Authorization: `Bearer ${token}`
-                    }
-                }
             );
             console.log('Change Name Successfully!');
             return true;
         } catch (error) {
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('Error changing name:', error.response?.data?.message);
             } else {
                 console.error('An unexpected error occurred:', error);
@@ -343,19 +286,14 @@ class AuthenticationService {
     //BELOW CODES RELATE TO "changing account info (such as gender, name)"
     async changeName(name: string | null, token: string | null): Promise<boolean> {
         try {
-            const res = await axios.put(
-                `${this.apiUrl}/clients/customer`,
+            const res = await apiClient.instance.put(
+                `/clients/customer`,
                 { nickname: name },
-                {
-                    headers: {
-                        Authorization: `Bearer ${token}`
-                    }
-                }
             );
             console.log('Change Name Successfully!');
             return true;
         } catch (error) {
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('Error changing name:', error.response?.data?.message);
             } else {
                 console.error('An unexpected error occurred:', error);
@@ -365,14 +303,9 @@ class AuthenticationService {
     }
     async changeNotifySessionID(notifySessionID: string | null): Promise<boolean> {
         try {
-            const res = await axios.put(
-                `${this.apiUrl}/clients/customer`,
-                { notify_session_id: notifySessionID },
-                {
-                    headers: {
-                        Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                    }
-                }
+            const res = await apiClient.instance.put(
+                `/clients/customer`,
+                { notify_session_id: notifySessionID }
             );
             if (res.data.status == 200) {
                 console.log('Change notifySessionID Successfully!');
@@ -382,7 +315,7 @@ class AuthenticationService {
                 return false;
             }
         } catch (error) {
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('Error changing name:', error.response?.data?.message);
             } else {
                 console.error('An unexpected error occurred:', error);
@@ -394,18 +327,13 @@ class AuthenticationService {
     async changePhone(phone: string | null, token: string | null): Promise<boolean> {
         try {
             const convertPhoneStringToNumber = Number(phone);
-            const res = await axios.put(
-                `${this.apiUrl}/clients/customer`,
+            const res = await apiClient.instance.put(
+                `/clients/customer`,
                 { phone: convertPhoneStringToNumber },
-                {
-                    headers: {
-                        Authorization: `Bearer ${token}`
-                    }
-                }
             );
             return true;
         } catch (error) {
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('Error changing phone:', error.response?.data?.message);
             } else {
                 console.error('An unexpected error occurred:', error);
@@ -416,19 +344,14 @@ class AuthenticationService {
 
     async changeGender(gender: string | null, token: string | null): Promise<boolean> {
         try {
-            const res = await axios.put(
-                `${this.apiUrl}/clients/customer`,
+            const res = await apiClient.instance.put(
+                `/clients/customer`,
                 { gender: gender },
-                {
-                    headers: {
-                        Authorization: `Bearer ${token}`
-                    }
-                }
             );
             console.log('Change gender Successfully!');
             return true;
         } catch (error) {
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('Error changing gender:', error.response?.data?.message);
             } else {
                 console.error('An unexpected error occurred:', error);
@@ -438,11 +361,7 @@ class AuthenticationService {
     }
     async getUserInfo() {
         try {
-            const response = await axios.get(`${this.apiUrl}/clients/customer`, {
-                headers: {
-                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                }
-            });
+            const response = await apiClient.instance.get(`/clients/customer`);
             if (response.status === 200 || response.status === 201) {
                 return response;
             } else {
@@ -454,12 +373,7 @@ class AuthenticationService {
     }
     async deleteAccount(): Promise<boolean> {
         try {
-            const accessToken = await SecureStore.getItemAsync('accessToken');
-            const response = await axios.delete(`${this.apiUrl}/clients/customer`, {
-                headers: {
-                    Authorization: `Bearer ${accessToken}`
-                }
-            });
+            const response = await apiClient.instance.delete(`/clients/customer`);
 
             if (response.status === 200 || response.status === 201) {
                 console.log('Account deleted successfully');
@@ -470,7 +384,7 @@ class AuthenticationService {
                 return false;
             }
         } catch (error) {
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('Error deleting account:', error.response?.data?.message || error.message);
             } else {
                 console.error('An unexpected error occurred while deleting account:', error);
@@ -482,16 +396,11 @@ class AuthenticationService {
     async checkPhoneSame(phoneNumber: string) {
         try {
             console.log('being checkPhoneSame');
-            const response = await axios.post(
-                `${this.apiUrl}/clients/customer/binding/sms`,
+            const response = await apiClient.instance.post(
+                `/clients/customer/binding/sms`,
                 {
                     phone: phoneNumber,
                     type: 3
-                },
-                {
-                    headers: {
-                        Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                    }
                 }
             );
             const token = await SecureStore.getItemAsync('accessToken');
@@ -505,20 +414,14 @@ class AuthenticationService {
 
     async confirmBindingPhone(phoneNumber: string, otp: string, notify_session_id: string) {
         try {
-            const response = await axios.put(
-                `${this.apiUrl}/public/client/customer/phone/otp`,
+            const response = await apiClient.instance.put(
+                `/public/client/customer/phone/otp`,
                 {
                     phone: phoneNumber,
                     code: otp,
                     notify_session_id: notify_session_id,
                     type: 3
                 },
-                {
-                    headers: {
-                        'Content-Type': 'application/json',
-                        Accept: 'application/json'
-                    }
-                }
             );
             console.log('confirmBindingPhone response', response.data);
             return response.data;
@@ -529,24 +432,17 @@ class AuthenticationService {
 
     async verifyPhoneOtp(phoneNumber: string, otp: string, notify_session_id: string) {
         try {
-            const response = await axios.put(
-                `${this.apiUrl}/public/client/customer/phone/otp`,
+            const response = await apiClient.instance.put(
+                `/public/client/customer/phone/otp`,
                 {
                     phone: phoneNumber,
                     code: otp,
                     notify_session_id: notify_session_id
                 },
-                {
-                    headers: {
-                        'Content-Type': 'application/json',
-                        Accept: '*/*'
-                    }
-                }
             );
-            console.log('verifyPhoneOtp response:', response.data);
             return response.data;
         } catch (error) {
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('Error verifying phone OTP:', error.response?.data || error.message);
                 throw error;
             } else {
@@ -557,15 +453,13 @@ class AuthenticationService {
     }
     async sendOtpToSignUpPhone(phone: string) {
         try {
-            const response = await axios.post(`${this.apiUrl}/public/client/customer/phone/sms`, {
+            const response = await apiClient.instance.post(`/public/client/customer/phone/sms`, {
                 phone: phone,
                 type: 1
             });
             if (response.status === 200 || response.status === 201) {
-                console.log('OTP sent successfully -- from api sendOtpToSignUpPhone, response:', response);
                 return true;
             } else {
-                console.error('Failed to send OTP -- from api sendOtpToSignUpPhone.. response:', response);
                 return false;
             }
         } catch (error) {

+ 90 - 173
service/chargeStationService.tsx

@@ -1,22 +1,13 @@
-import axios from 'axios';
+import axios, { isAxiosError } from 'axios';
 import { Alert } from 'react-native';
 import * as SecureStore from 'expo-secure-store';
-import { forgetPasswordFormData } from '../types/signup';
-import { CustomerData } from '../types/signUpFormData';
-
+import {apiClient} from './requets'
+import { ChargingDetails, ElectricityPrice } from './type/chargeStationType';
 class ChargeStationService {
-    private apiUrl: string;
-
-    constructor() {
-        this.apiUrl = process.env.EXPO_PUBLIC_API_URL;
-        if (!this.apiUrl) {
-            throw new Error('API URL is not defined in environment variables');
-        }
-    }
 
     async fetchCarBrand() {
         try {
-            const response = await axios.get(`${this.apiUrl}/public/client/car/brand`);
+            const response = await apiClient.instance.get(`/public/client/car/brand`);
 
             if (response.status === 200 || response.status === 201) {
                 return response.data;
@@ -24,7 +15,7 @@ class ChargeStationService {
                 console.log('invalid response');
             }
         } catch (error) {
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('error:', error.response?.data?.message || error.message);
             } else {
                 console.error('An unexpected error occurred:', error);
@@ -35,7 +26,7 @@ class ChargeStationService {
 
     async getCarImage(filename: string) {
         try {
-            const response = await axios.get(`${this.apiUrl}/public/image?filename=${filename}`);
+            const response: any = await apiClient.instance.get(`/public/image?filename=${filename}`);
             if (response.status === 200 || response.status === 201) {
                 return response.url;
             } else {
@@ -45,11 +36,7 @@ class ChargeStationService {
 
     async getUserCars() {
         try {
-            const response = await axios.get(`${this.apiUrl}/clients/customer/car/all`, {
-                headers: {
-                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                }
-            });
+            const response = await apiClient.instance.get(`/clients/customer/car/all`);
             if (response.status === 200 || response.status === 201) {
                 return response.data;
             } else {
@@ -59,11 +46,7 @@ class ChargeStationService {
 
     async getUserDefaultCars() {
         try {
-            const response = await axios.get(`${this.apiUrl}/clients/customer/car/all?queryDefault=true`, {
-                headers: {
-                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                }
-            });
+            const response = await apiClient.instance.get(`/clients/customer/car/all?queryDefault=true`);
             if (response.status === 200 || response.status === 201) {
                 // console.log(response.data.data);
                 return response.data;
@@ -74,8 +57,8 @@ class ChargeStationService {
 
     async getReservationWithSize(size: number) {
         try {
-            const response = await axios.get(
-                `${this.apiUrl}/clients/reservation/connectors/2405311022116801000/${size}`,
+            const response = await apiClient.instance.get(
+                `/clients/reservation/connectors/2405311022116801000/${size}`,
                 {
                     headers: {
                         Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
@@ -91,8 +74,8 @@ class ChargeStationService {
 
     async addCar(licensePlate: string, carBrandFk: string, carTypeFk: string, isDefault: boolean) {
         try {
-            const response = await axios.post(
-                `${this.apiUrl}/clients/customer/car`,
+            const response = await apiClient.instance.post(
+                `/clients/customer/car`,
                 {
                     licensePlate: licensePlate,
                     carBrandFk: carBrandFk,
@@ -111,7 +94,7 @@ class ChargeStationService {
                 return false;
             }
         } catch (error) {
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('error:', error.response?.data?.message || error.message);
                 return false;
             } else {
@@ -121,29 +104,20 @@ class ChargeStationService {
         }
     }
 
-    async deleteCar(carID) {
+    async deleteCar(carID: string) {
         try {
-            const response = await axios.delete(`${this.apiUrl}/clients/customer/car?carId=${carID}`, {
-                headers: {
-                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                }
-            });
+            const response = await apiClient.instance.delete(`/clients/customer/car?carId=${carID}`);
             if (response.status === 200 || response.status === 201) {
                 return true;
             } else {
             }
         } catch (error) {}
     }
-    async setDefaultCar(carID) {
+    async setDefaultCar(carID: string) {
         try {
-            const response = await axios.put(
-                `${this.apiUrl}/clients/customer/car/default?carId=${carID}`,
+            const response = await apiClient.instance.put(
+                `/clients/customer/car/default?carId=${carID}`,
                 {},
-                {
-                    headers: {
-                        Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                    }
-                }
             );
             if (response.status === 200 || response.status === 201) {
                 return true;
@@ -154,11 +128,7 @@ class ChargeStationService {
 
     async fetchPriceForCharging() {
         try {
-            const response = await axios.get(`${this.apiUrl}/clients/chargestations/resources/info`, {
-                headers: {
-                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                }
-            });
+            const response = await apiClient.instance.get(`/clients/chargestations/resources/info`);
             if (response.status === 200 || response.status === 201) {
                 return response.data;
             }
@@ -167,7 +137,7 @@ class ChargeStationService {
 
     async getCurrentPrice() {
         try {
-            const response = await axios.get(`${this.apiUrl}/clients/promotion/price?id=2405311022116801000`);
+            const response = await apiClient.instance.get(`/clients/promotion/price?id=2405311022116801000`);
             if (response.status === 200 || response.status === 201) {
                 return response.data.price;
             } else {
@@ -175,7 +145,7 @@ class ChargeStationService {
             }
         } catch (error) {
             console.error('Error getting current price:', error);
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('Response data:', error.response?.data);
                 console.error('Response status:', error.response?.status);
             }
@@ -184,7 +154,7 @@ class ChargeStationService {
     }
     async getOriginalPrice() {
         try {
-            const response = await axios.get(`${this.apiUrl}/clients/promotion/price?id=2405311022116801000`);
+            const response = await apiClient.instance.get(`/clients/promotion/price?id=2405311022116801000`);
             if (response.status === 200 || response.status === 201) {
                 return response.data.originalPrice;
             } else {
@@ -192,7 +162,7 @@ class ChargeStationService {
             }
         } catch (error) {
             console.error('Error getting original price:', error);
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('Response data:', error.response?.data);
                 console.error('Response status:', error.response?.status);
             }
@@ -202,16 +172,11 @@ class ChargeStationService {
 
     async NewfetchAvailableConnectors() {
         try {
-            const response = await axios.get(`${this.apiUrl}/clients/chargestations/resources/local/info`, {
-                headers: {
-                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                }
-            });
+            const response = await apiClient.instance.get(`/clients/chargestations/resources/local/info`);
             if (response.status === 200 && response.data.code === 200) {
                 return response.data.data.map((station: any) => {
                     // const snapshotData = JSON.parse(station.snapshot);
                     const snapshotData = station.snapshot;
-
                     const availableConnectors = station?.Equipments?.reduce((count: number, equipment: any) => {
                         return (
                             count +
@@ -225,7 +190,8 @@ class ChargeStationService {
                         address: snapshotData.Address,
                         image: station?.image,
                         stationLng: snapshotData.StationLng,
-                        stationLat: snapshotData.StationLat
+                        stationLat: snapshotData.StationLat,
+                        pricemodel_id: station.pricemodel_id,
                     };
                 });
             }
@@ -238,19 +204,14 @@ class ChargeStationService {
 
     async fetchAvailableConnectors(stationID: string) {
         try {
-            const response = await axios.get(
-                `${this.apiUrl}/clients/chargestations/resources/status?StationIDs=${stationID}`,
-                {
-                    headers: {
-                        Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                    }
-                }
+            const response = await apiClient.instance.get(
+                `/clients/chargestations/resources/status?StationIDs=${stationID}`,
             );
             if (response.status === 200 || response.status === 201) {
                 const stationStatusInfos = response.data.data.StationStatusInfos;
                 if (stationStatusInfos && stationStatusInfos.length > 0) {
                     const availableConnectors = stationStatusInfos[0].ConnectorStatusInfos.filter(
-                        (connector) => connector.Status === 2
+                        (connector: any) => connector.Status === 2
                     ).length;
                     return availableConnectors;
                 }
@@ -262,14 +223,10 @@ class ChargeStationService {
     }
     async fetchChargeStations() {
         try {
-            const response = await axios.get(`${this.apiUrl}/clients/chargestations/resources/info`, {
-                headers: {
-                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                }
-            });
+            const response = await apiClient.instance.get(`/clients/chargestations/resources/info`);
 
             if (response.status === 200 || response.status === 201) {
-                return response.data.data.map((station, index) => {
+                return response.data.data.map((station: any) => {
                     const { Address, StationName, StationID, StationLng, StationLat } = station.snapshot;
                     const image = station.image;
 
@@ -285,7 +242,7 @@ class ChargeStationService {
             } else {
             }
         } catch (error) {
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('Login error:', error.response?.data?.message || error.message);
             } else {
                 console.error('An unexpected error occurred:', error);
@@ -296,11 +253,7 @@ class ChargeStationService {
 
     async fetchChargeStationIdByScannedConnectorId(scannedConnectorId: string) {
         try {
-            const response = await axios.get(`${this.apiUrl}/clients/chargestations/resources/info`, {
-                headers: {
-                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                }
-            });
+            const response = await apiClient.instance.get(`/clients/chargestations/resources/info`);
 
             if (response.status === 200 || response.status === 201) {
                 const station = response.data.data.find((station: any) =>
@@ -314,7 +267,7 @@ class ChargeStationService {
                 return false;
             }
         } catch (error) {
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('Login error:', error.response?.data?.message || error.message);
             } else {
                 console.error('An unexpected error occurred:', error);
@@ -325,11 +278,7 @@ class ChargeStationService {
 
     async noImagefetchChargeStationIdByScannedConnectorId(scannedConnectorId: string) {
         try {
-            const response = await axios.get(`${this.apiUrl}/clients/chargestations/resources/local/simple/info`, {
-                headers: {
-                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                }
-            });
+            const response = await apiClient.instance.get(`/clients/chargestations/resources/local/simple/info`);
 
             if (response.status === 200 || response.status === 201) {
                 const station = response.data.data.find((station: any) =>
@@ -343,7 +292,7 @@ class ChargeStationService {
                 return false;
             }
         } catch (error) {
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('Login error:', error.response?.data?.message || error.message);
             } else {
                 console.error('An unexpected error occurred:', error);
@@ -354,17 +303,13 @@ class ChargeStationService {
 
     async fetchAllChargeStations() {
         try {
-            const response = await axios.get(`${this.apiUrl}/clients/chargestations/resources/info`, {
-                headers: {
-                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                }
-            });
+            const response = await apiClient.instance.get(`/clients/chargestations/resources/info`);
             if (response.status === 200 || response.status === 201) {
                 return response.data.data;
             } else {
             }
         } catch (error) {
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('Login error:', error.response?.data?.message || error.message);
             } else {
                 console.error('An unexpected error occurred:', error);
@@ -375,14 +320,14 @@ class ChargeStationService {
 
     async fetchChargeStationPrice(stationID: string) {
         try {
-            const response = await axios.get(`${this.apiUrl}/clients/promotion/price?id=${stationID}`);
+            const response = await apiClient.instance.get(`/clients/promotion/price?id=${stationID}`);
             if (response.status === 200 || response.status === 201) {
                 return response.data.price;
             } else {
                 console.log('invalid response');
             }
         } catch (error) {
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('Login error:', error.response?.data?.message || error.message);
             } else {
                 console.error('An unexpected error occurred:', error);
@@ -393,19 +338,15 @@ class ChargeStationService {
 
     async fetchAvailableDates(stationID: string) {
         try {
-            const response = await axios.get(`${this.apiUrl}/clients/reservation/connectors/${stationID}`, {
-                headers: {
-                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                }
-            });
+            const response = await apiClient.instance.get(`/clients/reservation/connectors/${stationID}`);
             if (response.status === 200 || response.status === 201) {
-                const dates = response.data.map((i) => i.date);
+                const dates = response.data.map((i: any) => i.date);
                 return dates;
             } else {
                 console.log('invalid response');
             }
         } catch (error) {
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('Login error:', error.response?.data?.message || error.message);
             } else {
                 console.error('An unexpected error occurred:', error);
@@ -416,21 +357,17 @@ class ChargeStationService {
 
     async fetchAvailableTimeSlots(stationID: string, targetDate: string) {
         try {
-            const response = await axios.get(`${this.apiUrl}/clients/reservation/connectors/${stationID}`, {
-                headers: {
-                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                }
-            });
+            const response = await apiClient.instance.get(`/clients/reservation/connectors/${stationID}`);
             if (response.status === 200 || response.status === 201) {
-                const times = response.data.find((i) => i.date === targetDate);
+                const times = response.data.find((i: any) => i.date === targetDate);
                 if (times) {
-                    const availableTimeSlots = times.range.map((i) => i.start);
+                    const availableTimeSlots = times.range.map((i: any) => i.start);
                     return availableTimeSlots;
                 }
             } else {
             }
         } catch (error) {
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('Login error:', error.response?.data?.message || error.message);
             } else {
                 console.error('An unexpected error occurred:', error);
@@ -441,11 +378,7 @@ class ChargeStationService {
 
     async fetchSpecificChargeStation(stationID: string) {
         try {
-            const response = await axios.get(`${this.apiUrl}/clients/reservation/connectors/${stationID}`, {
-                headers: {
-                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                }
-            });
+            const response = await apiClient.instance.get(`/clients/reservation/connectors/${stationID}`);
             if (response.status === 200 || response.status === 201) {
                 return response.data;
             } else {
@@ -458,13 +391,8 @@ class ChargeStationService {
 
     async fetchOngoingChargingData(format_order_id: string) {
         try {
-            const response = await axios.get(
-                `${this.apiUrl}/clients/chargestations/resources/equip/status?StartChargeSeq=${format_order_id}`,
-                {
-                    headers: {
-                        Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                    }
-                }
+            const response = await apiClient.instance.get(
+                `/clients/chargestations/resources/equip/status?StartChargeSeq=${format_order_id}`,
             );
             if (response.status === 200 || response.status === 201) {
                 return response.data;
@@ -478,11 +406,7 @@ class ChargeStationService {
 
     async fetchReservationHistories() {
         try {
-            const response = await axios.get(`${this.apiUrl}/clients/reservation/all`, {
-                headers: {
-                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                }
-            });
+            const response = await apiClient.instance.get(`/clients/reservation/all`);
             if (response.status === 200 || response.status === 201) {
 
                 return response.data;
@@ -501,11 +425,7 @@ class ChargeStationService {
         StartBalance: number;
     }) {
         try {
-            const response = await axios.put(`${this.apiUrl}/clients/chargestations/resources/charge/start`, payload, {
-                headers: {
-                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                }
-            });
+            const response = await apiClient.instance.put(`/clients/chargestations/resources/charge/start`, payload);
             if (response.status === 200 || response.status === 201) {
                 return response.data;
             } else {
@@ -519,11 +439,7 @@ class ChargeStationService {
     async stopCharging(payload: { StartChargeSeq: string; ConnectorID: string }) {
         try {
             console.log('stpo charge initialized');
-            const response = await axios.put(`${this.apiUrl}/clients/chargestations/resources/charge/stop`, payload, {
-                headers: {
-                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                }
-            });
+            const response = await apiClient.instance.put(`/clients/chargestations/resources/charge/stop`, payload);
             if (response.status === 200 || response.status === 201) {
                 console.log('stopCharging success', response);
                 return response.data;
@@ -537,11 +453,7 @@ class ChargeStationService {
 
     async getTodayReservation() {
         try {
-            const response = await axios.get(`${this.apiUrl}/clients/reservation/today`, {
-                headers: {
-                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                }
-            });
+            const response = await apiClient.instance.get(`/clients/reservation/today`);
             if (response.status === 200 || response.status === 201) {
                 // console.log('getTodayReservation response.data: ', response.data);
                 return response.data;
@@ -555,15 +467,8 @@ class ChargeStationService {
 
     async getProcessedImageUrl(filename: string) {
         try {
-            const response = await axios.get(`${this.apiUrl}/public/image?filename=${filename}`, {
-                // const response = await axios.get(`${this.apiUrl}/public/image?filename=BENZ-EQA.png`, {
-                headers: {
-                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                }
-            });
+            const response = await apiClient.instance.get(`/public/image?filename=${filename}`)
             if (response.status === 200 || response.status === 201) {
-                // console.log('i am getProcessedImageUrl s resposne', response.data.url);
-
                 return response.data.url;
             }
         } catch (error) {
@@ -574,11 +479,7 @@ class ChargeStationService {
 
     async getProcessedCarImageUrl(filename: string) {
         try {
-            const response = await axios.get(`http://ftp.hkmgt.com/cdn/public/file/crazycharge/${filename}`, {
-                headers: {
-                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                }
-            });
+            const response = await apiClient.instance.get(`http://ftp.hkmgt.com/cdn/public/file/crazycharge/${filename}`);
             if (response.status === 200 || response.status === 201) {
                 return response.data.detail;
             }
@@ -590,11 +491,7 @@ class ChargeStationService {
 
     async payPenalty(penaltyData: any) {
         try {
-            const response = await axios.post(`${this.apiUrl}/clients/pay/penalty`, penaltyData, {
-                headers: {
-                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                }
-            });
+            const response = await apiClient.instance.post(`/clients/pay/penalty`, penaltyData);
             if (response.status === 200 || response.status === 201) {
                 return response.data;
             } else {
@@ -602,7 +499,7 @@ class ChargeStationService {
                 return null;
             }
         } catch (error) {
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('Penalty payment error:', error.response?.data?.message || error.message);
             } else {
                 console.error('An unexpected error occurred during penalty payment:', error);
@@ -613,7 +510,7 @@ class ChargeStationService {
 
     async getAdvertise() {
         try {
-            const response = await axios.get(`${this.apiUrl}/clients/advertise/advertise`);
+            const response = await apiClient.instance.get(`/clients/advertise/advertise`);
             if (response.status === 200 || response.status === 201) {
                 return response.data;
             } else {
@@ -626,7 +523,7 @@ class ChargeStationService {
 
     async getCurrentPriceInPay(stationID: string) {
         try {
-            const response = await axios.get(`${this.apiUrl}/clients/promotion/price?id=${stationID}`);
+            const response = await apiClient.instance.get(`/clients/promotion/price?id=${stationID}`);
             if (response.status === 200 || response.status === 201) {
                 return response.data.price;
             } else {
@@ -634,7 +531,7 @@ class ChargeStationService {
             }
         } catch (error) {
             console.error('Error getting current price:', error);
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('Response data:', error.response?.data);
                 console.error('Response status:', error.response?.status);
             }
@@ -643,7 +540,7 @@ class ChargeStationService {
     }
     async getOriginalPriceInPay(stationID: string) {
         try {
-            const response = await axios.get(`${this.apiUrl}/clients/promotion/price?id=${stationID}`);
+            const response = await apiClient.instance.get(`/clients/promotion/price?id=${stationID}`);
             if (response.status === 200 || response.status === 201) {
                 return response.data.originalPrice;
                 // throw new Error(`Unexpected response status: ${response.status}`);
@@ -652,7 +549,7 @@ class ChargeStationService {
             }
         } catch (error) {
             console.error('Error getting original price:', error);
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('Response data:', error.response?.data);
                 console.error('Response status:', error.response?.status);
             }
@@ -661,17 +558,12 @@ class ChargeStationService {
     }
     async validateCoupon(couponRecords: string[], orderAmount: number) {
         try {
-            const response = await axios.post(
-                `${this.apiUrl}/clients/coupon/valid`,
+            const response = await apiClient.instance.post(
+                `/clients/coupon/valid`,
                 {
                     couponRecords: couponRecords,
                     orderAmount: orderAmount
                 },
-                {
-                    headers: {
-                        Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                    }
-                }
             );
             if (response.data.is_valid === true) {
                 return true;
@@ -682,5 +574,30 @@ class ChargeStationService {
             return false;
         }
     }
+    async fetchChargingDetails(recordID: string) {
+        try {
+            const response = await apiClient.instance.get(`/clients/reservation/getRecordById/${recordID}`);
+            if (response.status === 200 || response.status === 201) {
+                return response.data as ChargingDetails [];
+            } else {
+                return []
+            }
+        } catch (error) {
+            console.log(error);
+        }
+    }
+    async fetchElectricityPrice(id: string) {
+        try {
+            const response = await apiClient.instance.get(`/clients/promotion/business_hourGroup?pricemodel_id=${id}`);
+            if (response.status === 200 || response.status === 201) {
+                return response.data as ElectricityPrice [];
+            } else {
+                return [] as ElectricityPrice []
+            }
+        } catch (error) {
+            console.log(error);
+        }
+
+    }
 }
 export const chargeStationService = new ChargeStationService();

+ 55 - 0
service/conf.ts

@@ -0,0 +1,55 @@
+import axios, { 
+  AxiosInstance, 
+  AxiosRequestConfig, 
+  AxiosResponse, 
+  AxiosError,
+  InternalAxiosRequestConfig 
+} from 'axios';
+// API 基础配置
+export const API_CONFIG = {
+  BASE_URL: process.env.EXPO_PUBLIC_API_URL,
+  // 超时时间
+  TIMEOUT: 15000,
+  
+  // 重试配置
+  RETRY: {
+    maxRetries: 3,
+    retryDelay: 1000,
+  },
+  
+  // 错误消息映射
+  ERROR_MESSAGES: {
+    NETWORK_ERROR: '网络连接失败,请检查网络设置',
+    TIMEOUT_ERROR: '请求超时,请重试',
+    SERVER_ERROR: '服务器错误,请稍后重试',
+    UNAUTHORIZED: '登录已过期,请重新登录',
+  } as const,
+} as const;
+
+// 基础响应结构
+export interface BaseResponse<T = any> {
+  code: number;
+  message: string;
+  data: T;
+  success: boolean;
+}
+
+// 错误响应结构
+export interface ErrorResponse {
+  code: number;
+  message: string;
+  timestamp?: string;
+  path?: string;
+}
+
+// 请求配置扩展
+export interface RequestConfig {
+  needAuth?: boolean; // 是否需要认证
+  showError?: boolean; // 是否显示错误提示
+  retryCount?: number; // 重试次数
+}
+
+// 扩展的 Axios 请求配置
+export interface ExtendedRequestConfig extends AxiosRequestConfig {
+  customConfig?: RequestConfig;
+}

+ 190 - 0
service/requets.ts

@@ -0,0 +1,190 @@
+import axios, { 
+  AxiosInstance, 
+  AxiosRequestConfig, 
+  AxiosResponse, 
+  AxiosError,
+  InternalAxiosRequestConfig 
+} from 'axios';
+import {API_CONFIG, BaseResponse, ErrorResponse, ExtendedRequestConfig, RequestConfig } from './conf';
+import * as SecureStore from 'expo-secure-store';
+
+declare module 'axios' {
+  interface AxiosRequestConfig {
+    customConfig?: RequestConfig;
+  }
+}
+
+// 创建 Axios 实例
+class ApiClient {
+  public instance: AxiosInstance;
+  private isRefreshing = false;
+  private failedQueue: Array<{ resolve: (value: any) => void; reject: (error: any) => void }> = [];
+  constructor() {
+    this.instance = axios.create({
+      baseURL: API_CONFIG.BASE_URL,
+      timeout: API_CONFIG.TIMEOUT,
+      headers: {
+        'Content-Type': 'application/json',
+      },
+    });
+
+    this.setupInterceptors();
+  }
+
+  // 设置拦截器
+  private setupInterceptors(): void {
+    // 请求拦截器
+    this.instance.interceptors.request.use(
+      async (config: InternalAxiosRequestConfig) => {
+        const extendedConfig = config as InternalAxiosRequestConfig & { customConfig?: RequestConfig };
+        const { needAuth = true } = extendedConfig.customConfig || {};
+
+        // 添加认证令牌
+        if (needAuth) {
+          const token = await SecureStore.getItemAsync('accessToken')
+          if (token) {
+            config.headers.Authorization = `Bearer ${token}`;
+          }
+        }
+        return config;
+      },
+      (error: AxiosError) => {
+        console.error('❌ 请求错误:', error);
+        return Promise.reject(error);
+      }
+    );
+
+    // 响应拦截器
+    this.instance.interceptors.response.use(
+      (response: AxiosResponse) => {
+        console.log(`✅ ${response.config.method?.toUpperCase()} ${response.config.url} 成功`);
+        return response;
+      },
+      async (error: AxiosError) => {
+        return this.handleError(error);
+      }
+    );
+  }
+
+  // 错误处理
+  private async handleError(error: AxiosError): Promise<never> {
+    const originalRequest = error.config as InternalAxiosRequestConfig & { 
+      _retry?: boolean;
+      customConfig?: RequestConfig;
+    };
+
+    // 网络错误
+    if (!error.response) {
+      const networkError: ErrorResponse = {
+        code: -1,
+        message: API_CONFIG.ERROR_MESSAGES.NETWORK_ERROR,
+      };
+      return Promise.reject(networkError);
+    }
+
+    const { status, data } = error.response;
+    const errorData = data as ErrorResponse;
+
+    // Token 过期,尝试刷新
+    if (status === 401 && !originalRequest._retry) {
+      if (this.isRefreshing) {
+        // 如果正在刷新,将请求加入队列
+        return new Promise((resolve, reject) => {
+          this.failedQueue.push({ resolve, reject });
+        });
+      }
+
+      originalRequest._retry = true;
+      this.isRefreshing = true;
+
+      try {
+        // // 刷新 Token 逻辑
+        // await this.refreshToken();
+        
+        // // 重试原始请求
+        // const retryResponse = await this.instance(originalRequest);
+        // this.isRefreshing = false;
+        // this.processQueue(null);
+        // return retryResponse;
+      } catch (refreshError) {
+        this.isRefreshing = false;
+        this.processQueue(refreshError);
+        
+        // 刷新失败,跳转到登录页
+        // await authManager.clearTokens();
+        // navigation.navigate('Login'); // 根据实际导航库调整
+        
+        return Promise.reject({
+          code: 401,
+          message: API_CONFIG.ERROR_MESSAGES.UNAUTHORIZED,
+        });
+      }
+    }
+
+    // 其他错误处理
+    const customError: ErrorResponse = {
+      code: status,
+      message: errorData?.message || this.getErrorMessageByStatus(status),
+    };
+
+    // 根据配置决定是否显示错误提示
+    const { showError = true } = originalRequest.customConfig || {};
+    if (showError) {
+      this.showErrorToast(customError.message);
+    }
+
+    return Promise.reject(customError);
+  }
+
+  // 处理请求队列
+  private processQueue(error: any): void {
+    this.failedQueue.forEach(promise => {
+      if (error) {
+        promise.reject(error);
+      } else {
+        promise.resolve(this.instance);
+      }
+    });
+    this.failedQueue = [];
+  }
+
+  // 刷新 Token
+  // private async refreshToken(): Promise<void> {
+  //   const refreshToken = await authManager.getRefreshToken();
+  //   if (!refreshToken) {
+  //     throw new Error('No refresh token');
+  //   }
+
+  //   // 调用刷新 Token 接口
+  //   const response = await axios.post(`${API_CONFIG.BASE_URL}/auth/refresh`, {
+  //     refreshToken,
+  //   });
+
+  //   const newTokens = response.data.data;
+  //   await authManager.setTokens(newTokens);
+  // }
+
+  // 根据状态码获取错误消息
+  private getErrorMessageByStatus(status: number): string {
+    const messages: { [key: number]: string } = {
+      400: '请求参数错误',
+      403: '没有权限访问',
+      404: '请求资源不存在',
+      500: API_CONFIG.ERROR_MESSAGES.SERVER_ERROR,
+      502: '网关错误',
+      503: '服务不可用',
+      504: '网关超时',
+    };
+
+    return messages[status] || `请求失败 (${status})`;
+  }
+
+  // 显示错误提示(可根据实际使用的 Toast 库调整)
+  private showErrorToast(message: string): void {
+    // 使用你喜欢的 Toast 库,例如 react-native-toast-message
+    // Toast.show({ type: 'error', text1: message });
+    console.error('Error:', message);
+  }
+
+}
+export const apiClient = new ApiClient();

+ 228 - 0
service/type/chargeStationType.ts

@@ -0,0 +1,228 @@
+export interface StationID {
+	createdAt: string;
+	updatedAt: string;
+	id: string;
+	snapshot: string;
+	self_active_status_fk: string;
+	business_hours_fk: string;
+	qr_code: string;
+	image: string;
+	price: number;
+	pricemodel_id: string;
+}
+
+export interface EquipmentID {
+	createdAt: string;
+	updatedAt: string;
+	id: string;
+	equipmentID: string;
+	equipmentLat: number;
+	equipmentLng: number;
+	equipmentType: number;
+	equipmentName: string;
+	equipmentModel: string;
+	power: number;
+	StationID: StationID;
+}
+
+export interface Connector {
+	createdAt: string;
+	updatedAt: string;
+	id: string;
+	connectorID: string;
+	voltageLowerLimits: number;
+	connectorType: number;
+	voltageUpperLimits: number;
+	nationalStandard: number;
+	connectorName: string;
+	current: number;
+	park: number;
+	power: number;
+	status: string;
+	Parkstatus: string;
+	Lockstatus: string;
+	EquipmentID: EquipmentID;
+}
+
+export interface User {
+	createdAt: string;
+	updatedAt: string;
+	id: string;
+	firstname?: any;
+	lastname?: any;
+	nickname: string;
+	email: string;
+	password: string;
+	phone: string;
+	ic_card: string;
+	wallet: number;
+	icon_url?: any;
+	remark?: any;
+	address?: any;
+	status_fk: string;
+	gender: string;
+	birthday: string;
+	ic_car_id?: any;
+	notify_session_id: string;
+}
+
+export interface Statu {
+	id: string;
+	createdAt: string;
+	updatedAt: string;
+	description: string;
+}
+
+export interface Car_brand {
+	createdAt: string;
+	updatedAt: string;
+	id: string;
+	name: string;
+	img_url: string;
+}
+
+export interface Car_type {
+	createdAt: string;
+	updatedAt: string;
+	id: string;
+	name: string;
+	capacitance: number;
+	capacitance_unit: string;
+	type_image_url?: any;
+}
+
+export interface Car {
+	createdAt: string;
+	updatedAt: string;
+	id: string;
+	license_plate: string;
+	car_brand: Car_brand;
+	car_type: Car_type;
+}
+export interface Charging {
+	createdAt: string;
+	updatedAt: string;
+	id: string;
+	penaltyTotalTime: string;
+	penaltyFee: string;
+	leaving_time: string;
+}
+export interface ChargingDetails {
+	createdAt: string;
+	updatedAt: string;
+	id: string;
+	book_time: string;
+	end_time: string;
+	actual_start_time: string;
+	actual_end_time: string;
+	actual_total_power: number;
+	total_power: number;
+	type: string;
+	penalty_fee: number;
+	total_fee: number;
+	snapshot: string;
+	remark: string;
+	pricemodel_id?: any;
+	promotion_name?: any;
+	promotion_msg?: any;
+	format_order_id: string;
+	soc: number;
+	paid_status: boolean;
+	penalty_paid_status: boolean;
+	withdraw_fee: number;
+	connector: Connector;
+	user: User;
+	status: Statu;
+	car: Car;
+	charging: Charging [];
+}
+export interface Remark {
+  EndTime: string;
+  OffService: number;
+  PeakCharge: number;
+  StartTime: string;
+  PeakKwh: number;
+  ElseService: number;
+  OffCharge: number;
+  RushKwh: number;
+  ElseCharge: number;
+  PeakService: number;
+  TotalPower: number;
+  StartChargeSeq: string;
+  RushCharge: number;
+  TotalElectMoney: number;
+  OffKwh: number;
+  TotalServiceMoney: number;
+  PriceModelID: number;
+  TotalMoney: number;
+  RushService: number;
+  StopReason: number;
+  ConnectorID: string;
+  ElseKwh: number;
+}
+export interface Mon {
+	from: string;
+	to: string;
+	price: number;
+}
+
+export interface Tue {
+	from: string;
+	to: string;
+	price: number;
+}
+
+export interface Wed {
+	from: string;
+	to: string;
+	price: number;
+}
+
+export interface Thu {
+	from: string;
+	to: string;
+	price: number;
+}
+
+export interface Fri {
+	from: string;
+	to: string;
+	price: number;
+}
+
+export interface Sat {
+	from: string;
+	to: string;
+	price: number;
+}
+
+export interface Sun {
+	from: string;
+	to: string;
+	price: number;
+}
+
+export interface Special {
+	from: string;
+	to: string;
+	price: number;
+}
+export interface PriceWeek {
+	mon: Mon;
+	tue: Tue;
+	wed: Wed;
+	thu: Thu;
+	fri: Fri;
+	sat: Sat;
+	sun: Sun;
+}
+export interface ElectricityPrice extends PriceWeek {
+	createdAt: string;
+	updatedAt: string;
+	id: string;
+	event_name: string;
+	special: Special;
+	is_active: boolean;
+	expire_date: string;
+	pricemodel_id: string;
+}

+ 8 - 0
service/type/walletServiceType.ts

@@ -0,0 +1,8 @@
+export interface PaymentBonusList {
+     bonus_id: number;
+     base_amount: number;
+     gift_amount: number;
+     is_active: boolean;
+     createdAt: Date;
+     updatedAt: Date;
+};

+ 42 - 73
service/walletService.tsx

@@ -1,23 +1,11 @@
-import axios from 'axios';
+import axios, { isAxiosError } from 'axios';
 import * as SecureStore from 'expo-secure-store';
-
+import {apiClient} from './requets'
+import {PaymentBonusList} from './type/walletServiceType';
 class WalletService {
-    private apiUrl: string;
-
-    constructor() {
-        this.apiUrl = process.env.EXPO_PUBLIC_API_URL;
-        if (!this.apiUrl) {
-            throw new Error('API URL is not defined in environment variables');
-        }
-    }
-
     async getCouponForSpecificUser(userID: string) {
         try {
-            const response = await axios.get(`${this.apiUrl}/clients/promotion/coupons/${userID}`, {
-                headers: {
-                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                }
-            });
+            const response = await apiClient.instance.get(`/clients/promotion/coupons/${userID}`);
             if (response.status === 200 || response.status === 201) {
                 return response.data;
             } else {
@@ -31,11 +19,7 @@ class WalletService {
 
     async getCustomerInfo() {
         try {
-            const response = await axios.get(`${this.apiUrl}/clients/customer`, {
-                headers: {
-                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                }
-            });
+            const response = await apiClient.instance.get(`/clients/customer`);
             if (response.status === 200 || response.status === 201) {
                 const info = response.data;
                 return info;
@@ -44,7 +28,7 @@ class WalletService {
                 return false;
             }
         } catch (error) {
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('get customer info error:', error.response?.data?.message || error.message);
             } else {
                 console.error('An unexpected error occurred:', error);
@@ -55,21 +39,16 @@ class WalletService {
 
     async getWalletBalance() {
         try {
-            const response = await axios.get(`${this.apiUrl}/clients/customer/wallet`, {
-                headers: {
-                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                }
-            });
+            const response = await apiClient.instance.get(`/clients/customer/wallet`);
             if (response.status === 200) {
                 const walletBalance = response.data.data;
-
                 return walletBalance;
             } else {
                 console.error('getWalletBalance failed:', response.status);
                 return false;
             }
         } catch (error) {
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('getWallet error:', error.response?.data?.message || error.message);
             } else {
                 console.error('An unexpected error occurred:', error);
@@ -80,11 +59,7 @@ class WalletService {
 
     async getOutTradeNo() {
         try {
-            const response = await axios.get(`${this.apiUrl}/clients/qfpay/out_trade_no`, {
-                headers: {
-                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                }
-            });
+            const response = await apiClient.instance.get(`/clients/qfpay/out_trade_no`);
             if (response.status === 200) {
                 const outTradeNo = response.data.out_trade_no;
 
@@ -94,7 +69,7 @@ class WalletService {
                 return false;
             }
         } catch (error) {
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('get outTradeNo error:', error.response?.data?.message || error.message);
             } else {
                 console.error('An unexpected error occurred:', error);
@@ -105,11 +80,7 @@ class WalletService {
 
     async getTransactionRecord() {
         try {
-            const response = await axios.get(`${this.apiUrl}/clients/wallet/transaction/record`, {
-                headers: {
-                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                }
-            });
+            const response = await apiClient.instance.get(`/clients/wallet/transaction/record`);
             if (response.status === 200) {
                 const walletBalance = response.data;
 
@@ -119,7 +90,7 @@ class WalletService {
                 return false;
             }
         } catch (error) {
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('getWallet error:', error.response?.data?.message || error.message);
             } else {
                 console.error('An unexpected error occurred:', error);
@@ -156,11 +127,7 @@ class WalletService {
                 is_ic_call
             };
 
-            const response = await axios.post(`${this.apiUrl}/clients/pay`, payload, {
-                headers: {
-                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                }
-            });
+            const response = await apiClient.instance.post(`/clients/pay`, payload);
             if (response.status === 200 || response.status === 201) {
                 return response.data;
             } else {
@@ -200,18 +167,14 @@ class WalletService {
                 is_ic_call
             };
 
-            const response = await axios.post(`${this.apiUrl}/clients/pay`, payload, {
-                headers: {
-                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                }
-            });
+            const response = await apiClient.instance.post(`/clients/pay`, payload);
             if (response.data.status === 200 || response.data.status === 201) {
                 return response.data.status;
             } else {
                 return response.data;
             }
         } catch (error) {
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 return {
                     error: true,
                     status: error.response?.status,
@@ -228,11 +191,7 @@ class WalletService {
 
     async selectPaymentType() {
         try {
-            const response = await axios.get(`${this.apiUrl}/clients/qfpay/type`, {
-                headers: {
-                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                }
-            });
+            const response = await apiClient.instance.get(`/clients/qfpay/type`);
             if (response.status === 200 || response.status === 201) {
                 const info = response.data;
                 return info;
@@ -241,7 +200,7 @@ class WalletService {
                 return false;
             }
         } catch (error) {
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('get customer info error:', error.response?.data?.message || error.message);
             } else {
                 console.error('An unexpected error occurred:', error);
@@ -252,24 +211,19 @@ class WalletService {
 
     async submitPaymentAfterSelectingType(amount: number, pay_type: string, return_url?: string) {
         try {
-            const response = await axios.get(
-                `${this.apiUrl}/clients/qfpay/session?amount=${amount}&pay_type=${pay_type}&return_url=${return_url}`,
-                {
-                    headers: {
-                        Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                    }
-                }
+            const response = await apiClient.instance.get(
+                `/clients/qfpay/session?amount=${amount}&pay_type=${pay_type}&return_url=${return_url}`
             );
             // if (response.status === 200 || response.status === 201) {
             if (response) {
                 const info = response.data;
                 return info;
             } else {
-                console.error('get customer info failed:', response.status);
+                console.error('get customer info failed:', response);
                 return false;
             }
         } catch (error) {
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('get customer info error:', error.response?.data?.message || error.message);
             } else {
                 console.error('An unexpected error occurred:', error);
@@ -279,11 +233,7 @@ class WalletService {
     }
     async checkPaymentStatus(out_trade_no: string) {
         try {
-            const response = await axios.get(`${this.apiUrl}/clients/qfpay/check/transaction/${out_trade_no}`, {
-                headers: {
-                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
-                }
-            });
+            const response = await apiClient.instance.get(`/clients/qfpay/check/transaction/${out_trade_no}`);
 
             if (Array.isArray(response.data.data) && response.data.data.length > 0) {
                 // If it's not empty, consider it a success and return the data
@@ -293,7 +243,7 @@ class WalletService {
                 return false;
             }
         } catch (error) {
-            if (axios.isAxiosError(error)) {
+            if (isAxiosError(error)) {
                 console.error('check payment status error:', error.response?.data?.message || error.message);
             } else {
                 console.error('An unexpected error occurred:', error);
@@ -301,5 +251,24 @@ class WalletService {
             return false;
         }
     }
+    async getPaymentBonusList() {
+         try {
+            const response = await apiClient.instance.get(`/clients/promotion/paymentBonus`);
+            if (response.status === 200 || response.status === 201) {
+                const list = response.data;
+                return list as PaymentBonusList[];
+            } else {
+                console.error('get customer info failed:', response.status);
+                return [] as PaymentBonusList[];
+            }
+        } catch (error) {
+            if (isAxiosError(error)) {
+                console.error('get customer info error:', error.response?.data?.message || error.message);
+            } else {
+                console.error('An unexpected error occurred:', error);
+            }
+            return [] as PaymentBonusList[];;
+        }
+    }
 }
 export const walletService = new WalletService();