Ian Fung hace 1 año
padre
commit
babb801490

+ 67 - 15
app/(public)/test.tsx

@@ -1,30 +1,82 @@
 import React from 'react';
-import { View, Image, Linking, Button, StyleSheet, Text } from 'react-native';
-import { WebView } from 'react-native-webview';
-import SetVehiclePageComponent from '../../component/global/setVehiclePageComponent';
-import SetVehiclesOne from '../(auth)/(tabs)/(home)/(vehicle)/setVehiclesOne';
+import { View, Image, Linking, Button, Alert, StyleSheet, Text } from 'react-native';
+import axios from 'axios';
+import sha256 from 'crypto-js/sha256';
 
 export default function Test() {
-    const handleRedirect = async () => {
-        const wechatPayUrl =
-            'https://cashiermd.95516.com/b2c/api/unifiedOrder.action?tn=560492826346743689323&sign=87d11db496ba7631e44863b49490657b2968af15021d4812b5bde9ca9eb78df4&__log_id_=ACP0240827121309434f0050468870';
+    const handleSubmitPayment = async () => {
+        const origin = 'https://openapi-hk.qfapi.com/checkstand/#/?';
+        const obj = {
+            // appcode: 'F8A0AC83C61A40D3840CA9FA930C5D66',
+            appcode: process.env.QFPAY_CODE,
+            goods_name: 'Crazy Charge 錢包增值',
+            out_trade_no: '13422916216626244614',
+            paysource: 'crazycharge_checkout',
+            return_url: 'https://www.google.com',
+            failed_url: 'https://www.google.com',
+            notify_url: 'https://api.crazycharge.com.hk/api/v1/clients/qfpay/webhook',
+            sign_type: 'sha256',
+            txamt: '100',
+            txcurrcd: 'HKD',
+            txdtm: '2020-06-28 18:33:20'
+        };
+
+        const paramStringify = (json, flag?) => {
+            let str = '';
+            let keysArr = Object.keys(json);
+            keysArr.sort().forEach((val) => {
+                if (!json[val]) return;
+                str += `${val}=${flag ? encodeURIComponent(json[val]) : json[val]}&`;
+            });
+            return str.slice(0, -1);
+        };
+
+        // const api_key = '5BA7EC74416D4146B9C4E9D71A84D930';
+        const api_key = process.env.QFPAY_KEY;
+        const params = paramStringify(obj);
+        const sign = sha256(`${params}${api_key}`).toString();
+        const url = `${origin}${paramStringify(obj, true)}&sign=${sign}`;
+
         try {
-            const supported = await Linking.canOpenURL(wechatPayUrl);
+            const supported = await Linking.canOpenURL(url);
             if (supported) {
-                await Linking.openURL(wechatPayUrl);
+                await Linking.openURL(url);
             } else {
-                console.log("Don't know how to open URI: " + wechatPayUrl);
-                alert('WeChat Pay is not available on this device.');
+                Alert.alert('錯誤', '請稍後再試');
             }
-        } catch (err) {
-            console.error('An error occurred', err);
-            alert('An error occurred while trying to open WeChat Pay.');
+        } catch (error) {
+            console.error('Payment error:', error);
+            Alert.alert('Error', 'Failed to submit payment');
         }
     };
 
     return (
         <View style={{ flex: 1 }} className="items-center justify-center bg-gray-50">
-            <Button title="abc" onPress={handleRedirect} />
+            <Button
+                title="abc"
+                onPress={() => {
+                    console.log('pressed');
+                    handleSubmitPayment();
+                }}
+            />
+            <Text>{process.env.QFPAY_KEY}</Text>
         </View>
     );
 }
+
+// const handleRedirect = async () => {
+//     const wechatPayUrl =
+//         'https://cashiermd.95516.com/b2c/api/unifiedOrder.action?tn=560492826346743689323&sign=87d11db496ba7631e44863b49490657b2968af15021d4812b5bde9ca9eb78df4&__log_id_=ACP0240827121309434f0050468870';
+//     try {
+//         const supported = await Linking.canOpenURL(wechatPayUrl);
+//         if (supported) {
+//             await Linking.openURL(wechatPayUrl);
+//         } else {
+//             console.log("Don't know how to open URI: " + wechatPayUrl);
+//             alert('WeChat Pay is not available on this device.');
+//         }
+//     } catch (err) {
+//         console.error('An error occurred', err);
+//         alert('An error occurred while trying to open WeChat Pay.');
+//     }
+// };

+ 902 - 845
component/accountPages/walletPageComponent.tsx

@@ -1,901 +1,958 @@
-// import {
-//     View,
-//     Text,
-//     ScrollView,
-//     Pressable,
-//     ImageBackground,
-//     ActivityIndicator,
-//     Modal,
-//     Alert,
-//     TextInput,
-//     Linking
-// } from 'react-native';
-// import { SafeAreaView } from 'react-native-safe-area-context';
-// import { router } from 'expo-router';
-// import { CrossLogoSvg } from '../global/SVG';
-// import { useEffect, useState } from 'react';
-// import { walletService } from '../../service/walletService';
-
-// import { formatCouponDate, formatDate } from '../../util/lib';
-// import { set } from 'date-fns';
-
-// const TopUpModal = ({ visible, onClose, onSelect, paymentOptions }) => {
-//     return (
-//         <Modal animationType="fade" transparent={true} visible={visible} onRequestClose={onClose}>
-//             <View
-//                 style={{
-//                     flex: 1,
-//                     justifyContent: 'center',
-//                     alignItems: 'center',
-//                     backgroundColor: 'rgba(0,0,0,0.5)'
-//                 }}
-//             >
-//                 <View
-//                     style={{
-//                         backgroundColor: 'white',
-//                         padding: 20,
-//                         borderRadius: 10,
-//                         width: '80%',
-//                         maxHeight: '80%'
-//                     }}
-//                 >
-//                     <Text style={{ fontSize: 20, marginBottom: 20 }}>選擇支付方式</Text>
-//                     <ScrollView>
-//                         {Object.entries(paymentOptions).map(([key, value]) => (
-//                             <Pressable
-//                                 key={key}
-//                                 onPress={() => onSelect(value)}
-//                                 style={{
-//                                     padding: 10,
-//                                     marginBottom: 10,
-//                                     borderBottomWidth: 1,
-//                                     borderBottomColor: '#eee'
-//                                 }}
-//                             >
-//                                 <Text>{key}</Text>
-//                             </Pressable>
-//                         ))}
-//                     </ScrollView>
-//                     <Pressable onPress={onClose} style={{ padding: 10, alignItems: 'center', marginTop: 10 }}>
-//                         <Text style={{ color: 'red' }}>關閉</Text>
-//                     </Pressable>
-//                 </View>
-//             </View>
-//         </Modal>
-//     );
-// };
+import {
+    View,
+    Image,
+    Text,
+    ScrollView,
+    AppState,
+    Pressable,
+    ImageBackground,
+    ActivityIndicator,
+    Modal,
+    Alert,
+    TextInput,
+    Linking
+} from 'react-native';
+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 { walletService } from '../../service/walletService';
+import UnionPayImage from '../../assets/unionpay.png';
+import PayMeImage from '../../assets/payme.png';
+import { formatCouponDate, formatDate } from '../../util/lib';
+import { set } from 'date-fns';
+import { reloadAppAsync } from 'expo';
 
-// const AmountInputModal = ({ visible, onClose, onConfirm }) => {
-//     const [inputAmount, setInputAmount] = useState('');
+const TopUpModal = ({ visible, onClose, onSelect, paymentOptions }) => {
+    const getPaymentImage = (key) => {
+        switch (key) {
+            case 'union_pay_wap_payment':
+                return UnionPayImage;
+            case 'payme_wap_payment':
+                return PayMeImage;
+            default:
+                return null;
+        }
+    };
+    return (
+        <Modal animationType="fade" transparent={true} visible={visible} onRequestClose={onClose}>
+            <View
+                style={{
+                    flex: 1,
+                    justifyContent: 'center',
+                    alignItems: 'center',
+                    backgroundColor: 'rgba(0,0,0,0.5)'
+                }}
+            >
+                <View
+                    style={{
+                        backgroundColor: 'white',
+                        padding: 20,
+                        borderRadius: 10,
+                        width: '80%',
+                        maxHeight: '80%'
+                    }}
+                >
+                    <Text style={{ fontSize: 20, marginBottom: 20 }}>選擇支付方式</Text>
+                    <ScrollView>
+                        {Object.entries(paymentOptions).map(([key, value]) => (
+                            <Pressable
+                                key={key}
+                                onPress={() => onSelect(value)}
+                                style={{
+                                    padding: 10,
+                                    marginBottom: 10,
+                                    borderBottomWidth: 1,
+                                    borderBottomColor: '#eee'
+                                }}
+                            >
+                                <View className="flex flex-row items-center space-x-2">
+                                    <Image
+                                        source={getPaymentImage(key)}
+                                        style={{ width: 40, height: 40, marginRight: 10 }}
+                                        resizeMode="contain"
+                                    />
+                                    <Text className="tracking-wider">
+                                        {key === 'union_pay_wap_payment' ? 'UnionPay' : 'PayMe'}
+                                    </Text>
+                                </View>
+                            </Pressable>
+                        ))}
+                    </ScrollView>
+                    <Pressable onPress={onClose} style={{ padding: 10, alignItems: 'center', marginTop: 10 }}>
+                        <Text style={{ color: 'red' }}>關閉</Text>
+                    </Pressable>
+                </View>
+            </View>
+        </Modal>
+    );
+};
+const AmountInputModal = ({ visible, onClose, onConfirm }) => {
+    const [inputAmount, setInputAmount] = useState('');
 
-//     return (
-//         <Modal animationType="fade" transparent={true} visible={visible} onRequestClose={onClose}>
-//             <View
-//                 style={{
-//                     flex: 1,
-//                     justifyContent: 'center',
-//                     alignItems: 'center',
-//                     backgroundColor: 'rgba(0,0,0,0.5)'
-//                 }}
-//             >
-//                 <View
-//                     style={{
-//                         backgroundColor: 'white',
-//                         padding: 20,
-//                         borderRadius: 10,
-//                         width: '80%'
-//                     }}
-//                 >
-//                     <Text style={{ fontSize: 20, marginBottom: 20 }}>輸入增值金額</Text>
-//                     <TextInput
-//                         style={{
-//                             borderWidth: 1,
-//                             borderColor: '#ccc',
-//                             borderRadius: 5,
-//                             padding: 10,
-//                             marginBottom: 20,
-//                             fontSize: 18
-//                         }}
-//                         keyboardType="numeric"
-//                         placeholder="輸入金額"
-//                         value={inputAmount}
-//                         onChangeText={setInputAmount}
-//                     />
-//                     <Pressable
-//                         onPress={() => onConfirm(inputAmount)}
-//                         style={{
-//                             backgroundColor: '#02677D',
-//                             padding: 10,
-//                             borderRadius: 5,
-//                             alignItems: 'center'
-//                         }}
-//                     >
-//                         <Text style={{ color: 'white', fontSize: 18 }}>確認</Text>
-//                     </Pressable>
-//                     <Pressable onPress={onClose} style={{ padding: 10, alignItems: 'center', marginTop: 10 }}>
-//                         <Text style={{ color: 'red' }}>取消</Text>
-//                     </Pressable>
-//                 </View>
-//             </View>
-//         </Modal>
-//     );
-// };
+    return (
+        <Modal animationType="fade" transparent={true} visible={visible} onRequestClose={onClose}>
+            <View
+                style={{
+                    flex: 1,
+                    justifyContent: 'center',
+                    alignItems: 'center',
+                    backgroundColor: 'rgba(0,0,0,0.5)'
+                }}
+            >
+                <View
+                    style={{
+                        backgroundColor: 'white',
+                        padding: 20,
+                        borderRadius: 10,
+                        width: '80%'
+                    }}
+                >
+                    <Text style={{ fontSize: 20, marginBottom: 20 }}>輸入增值金額</Text>
+                    <TextInput
+                        style={{
+                            borderWidth: 1,
+                            borderColor: '#ccc',
+                            borderRadius: 5,
+                            padding: 10,
+                            marginBottom: 20,
+                            fontSize: 18
+                        }}
+                        keyboardType="numeric"
+                        placeholder="輸入金額"
+                        value={inputAmount}
+                        onChangeText={setInputAmount}
+                    />
+                    <Pressable
+                        onPress={() => onConfirm(inputAmount)}
+                        style={{
+                            backgroundColor: '#02677D',
+                            padding: 10,
+                            borderRadius: 5,
+                            alignItems: 'center'
+                        }}
+                    >
+                        <Text style={{ color: 'white', fontSize: 18 }}>確認</Text>
+                    </Pressable>
+                    <Pressable onPress={onClose} style={{ padding: 10, alignItems: 'center', marginTop: 10 }}>
+                        <Text style={{ color: 'red' }}>取消</Text>
+                    </Pressable>
+                </View>
+            </View>
+        </Modal>
+    );
+};
 
-// export const IndividualCouponComponent = ({
-//     title,
-//     price,
-//     detail,
-//     date
-// }: {
-//     title: string;
-//     price: string;
-//     detail: string;
-//     date: string;
-// }) => {
-//     return (
-//         <Pressable onPress={() => console.log('abc')}>
-//             <View className="bg-[#e7f2f8] h-[124px]  rounded-xl flex-row mb-3">
-//                 <View className="bg-white mx-3 my-3 w-[28%] rounded-xl">
-//                     <View className="flex-row justify-center items-center pr-4 pt-4 ">
-//                         <Text className="color-[#02677d] text-2xl pl-2 pr-1">$</Text>
-//                         <Text className="color-[#02677d] text-3xl font-bold" adjustsFontSizeToFit={true}>
-//                             {price}
-//                         </Text>
-//                     </View>
-//                     <View className="items-center justify-center">
-//                         <Text className="text-base mt-1">{title}</Text>
-//                     </View>
-//                 </View>
+export const IndividualCouponComponent = ({
+    title,
+    price,
+    detail,
+    date
+}: {
+    title: string;
+    price: string;
+    detail: string;
+    date: string;
+}) => {
+    return (
+        <Pressable onPress={() => console.log('abc')}>
+            <View className="bg-[#e7f2f8] h-[124px]  rounded-xl flex-row mb-3">
+                <View className="bg-white mx-3 my-3 w-[28%] rounded-xl">
+                    <View className="flex-row justify-center items-center pr-4 pt-4 ">
+                        <Text className="color-[#02677d] text-2xl pl-2 pr-1">$</Text>
+                        <Text className="color-[#02677d] text-3xl font-bold" adjustsFontSizeToFit={true}>
+                            {price}
+                        </Text>
+                    </View>
+                    <View className="items-center justify-center">
+                        <Text className="text-base mt-1">{title}</Text>
+                    </View>
+                </View>
 
-//                 {/* //dash line */}
-//                 <View style={{ overflow: 'hidden' }}>
-//                     <View
-//                         style={{
-//                             borderStyle: 'dashed',
-//                             borderWidth: 1,
-//                             borderColor: '#CCCCCC',
-//                             margin: -1,
-//                             width: 0,
-//                             marginRight: 0,
-//                             height: '100%'
-//                         }}
-//                     >
-//                         <View style={{ height: 60 }}></View>
-//                     </View>
-//                 </View>
+                {/* //dash line */}
+                <View style={{ overflow: 'hidden' }}>
+                    <View
+                        style={{
+                            borderStyle: 'dashed',
+                            borderWidth: 1,
+                            borderColor: '#CCCCCC',
+                            margin: -1,
+                            width: 0,
+                            marginRight: 0,
+                            height: '100%'
+                        }}
+                    >
+                        <View style={{ height: 60 }}></View>
+                    </View>
+                </View>
 
-//                 <View className="flex-col flex-1  m-[5%] justify-center ">
-//                     <Text className="text-lg">{title}</Text>
-//                     <Text className="color-[#888888] text-sm">{detail}</Text>
-//                     <View className="flex-row items-center ">
-//                         <Text className="text-base">有效期 </Text>
-//                         <Text className="text-base font-bold text-[#02677d]">{date}</Text>
-//                     </View>
-//                 </View>
-//             </View>
-//         </Pressable>
-//     );
-// };
+                <View className="flex-col flex-1  m-[5%] justify-center ">
+                    <Text className="text-lg">{title}</Text>
+                    <Text className="color-[#888888] text-sm">{detail}</Text>
+                    <View className="flex-row items-center ">
+                        <Text className="text-base">有效期 </Text>
+                        <Text className="text-base font-bold text-[#02677d]">{date}</Text>
+                    </View>
+                </View>
+            </View>
+        </Pressable>
+    );
+};
 
-// 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('');
-//     useEffect(() => {
-//         const fetchData = async () => {
-//             try {
-//                 setLoading(true);
-//                 const info = await walletService.getCustomerInfo();
-//                 // const coupon = await walletService.getCouponForSpecificUser(info.id);
-//                 const wallet = await walletService.getWalletBalance();
-//                 console.log(wallet);
-//                 setUserID(info.id);
-//                 setWalletBalance(wallet);
-//                 setCoupons(coupon);
-//             } catch (error) {
-//                 console.log(error);
-//             } finally {
-//                 setLoading(false);
-//             }
-//         };
+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('');
+    const PAYMENT_CHECK_TIMEOUT = 5 * 60 * 1000; // 5 minutes in milliseconds
+    const [paymentStatus, setPaymentStatus] = useState(null);
+    const [isExpectingPayment, setIsExpectingPayment] = useState(false);
+    const appState = useRef(AppState.currentState);
+    const paymentInitiatedTime = useRef(null);
 
-//         fetchData();
-//     }, []);
+    useEffect(() => {
+        const subscription = AppState.addEventListener('change', (nextAppState) => {
+            if (
+                appState.current.match(/inactive|background/) &&
+                nextAppState === 'active' &&
+                isExpectingPayment &&
+                outTradeNo &&
+                paymentInitiatedTime.current
+            ) {
+                const currentTime = new Date().getTime();
+                if (currentTime - paymentInitiatedTime.current < PAYMENT_CHECK_TIMEOUT) {
+                    checkPaymentStatus();
+                } else {
+                    // Payment check timeout reached
+                    setIsExpectingPayment(false);
+                    setOutTradeNo('');
+                    paymentInitiatedTime.current = null;
+                    Alert.alert(
+                        'Payment Timeout',
+                        'The payment status check has timed out. Please check your payment history.'
+                    );
+                }
+            }
+            appState.current = nextAppState;
+        });
 
-//     const formatMoney = (amount: any) => {
-//         if (typeof amount !== 'number') {
-//             amount = Number(amount);
-//         }
-//         return amount.toLocaleString('en-US');
-//     };
+        return () => {
+            subscription.remove();
+        };
+    }, [outTradeNo, isExpectingPayment]);
 
-//     useEffect(() => {
-//         const fetchPaymentType = async () => {
-//             const response = await walletService.selectPaymentType();
-//             console.log('response', response);
-//             setPaymentType(response);
-//         };
-//         fetchPaymentType();
-//     }, []);
+    const checkPaymentStatus = async () => {
+        try {
+            const result = await walletService.checkPaymentStatus(outTradeNo);
+            setPaymentStatus(result);
+            console.log('checkPaymentStatus from walletPageComponent', result);
+            if (result) {
+                // Payment successful
+                Alert.alert('Success', 'Payment was successful!', [
+                    {
+                        text: 'OK',
+                        onPress: async () => {
+                            const wallet = await walletService.getWalletBalance();
+                            setWalletBalance(wallet);
+                            console.log('new wallet:', wallet);
+                        }
+                    }
+                ]);
+            } else {
+                Alert.alert('Payment Failed', 'Payment was not successful. Please try again.');
+            }
+            setIsExpectingPayment(false);
+            setOutTradeNo('');
+            paymentInitiatedTime.current = null;
+        } catch (error) {
+            console.error('Failed to check payment status:', error);
+            Alert.alert('Error', 'Failed to check payment status. Please check your payment history.');
+        }
+    };
 
-//     const handleRedirect = async () => {
-//         const payUrl = response.pay_url;
+    // useEffect(() => {
+    //     const handleAppStateChange = (nextAppState) => {
+    //         if (appState.match(/inactive|background/) && nextAppState === 'active') {
+    //             console.log('App has come to the foreground!');
+    //             // Check payment status or update UI here
+    //             console.log('outTradeNo', outTradeNo);
+    //         }
+    //         setAppState(nextAppState);
+    //     };
 
-//         try {
-//             const supported = await Linking.canOpenURL(payUrl);
-//             if (supported) {
-//                 await Linking.openURL(payUrl);
-//             } else {
-//                 console.log("Don't know how to open URI: " + payUrl);
-//                 alert('WeChat Pay is not available on this device.');
-//             }
-//         } catch (err) {
-//             console.error('An error occurred', err);
-//             alert('An error occurred while trying to open WeChat Pay.');
-//         }
-//     };
+    //     AppState.addEventListener('change', handleAppStateChange);
+    // }, [appState]);
 
-//     const handleTopUp = (selectedValue) => {
-//         setSelectedPaymentType(selectedValue);
-//         setModalVisible(false);
-//         setAmountModalVisible(true);
-//     };
+    useEffect(() => {
+        const fetchData = async () => {
+            try {
+                setLoading(true);
+                const info = await walletService.getCustomerInfo();
+                // const coupon = await walletService.getCouponForSpecificUser(info.id);
+                const wallet = await walletService.getWalletBalance();
+                console.log(wallet);
+                setUserID(info.id);
+                setWalletBalance(wallet);
+                setCoupons(coupon);
+            } catch (error) {
+                console.log(error);
+            } finally {
+                setLoading(false);
+            }
+        };
 
-//     const handleAmountConfirm = async (inputAmount) => {
-//         setAmount(inputAmount);
-//         setAmountModalVisible(false);
+        fetchData();
+    }, []);
 
-//         try {
-//             if (amount) {
-//                 const response = await walletService.submitPaymentAfterSelectingType(
-//                     amount,
-//                     selectedPaymentType,
-//                     'test'
-//                 );
-//                 const handleRedirect = async () => {
-//                     const payUrl = response.pay_url;
-//                     setOutTradeNo(response.out_trade_no);
-//                     try {
-//                         const supported = await Linking.canOpenURL(payUrl);
-//                         if (supported) {
-//                             await Linking.openURL(payUrl);
-//                         } else {
-//                             console.log("Don't know how to open URI: " + payUrl);
-//                         }
-//                     } catch (err) {
-//                         console.error('An error occurred', err);
-//                         alert('An error occurred while trying to open WeChat Pay.');
-//                     }
-//                 };
-//                 handleRedirect();
-//             }
-//             // Placeholder for API call
-//             console.log('Top-up Initiated', `Payment Type: ${selectedPaymentType}\nAmount: $${inputAmount}`);
-//         } catch (error) {
-//             console.error('Top-up failed:', error);
-//             Alert.alert('Error', 'Failed to process top-up. Please try again.');
-//         }
-//     };
+    const formatMoney = (amount: any) => {
+        if (typeof amount !== 'number') {
+            amount = Number(amount);
+        }
+        return amount.toLocaleString('en-US');
+    };
+    const filterPaymentOptions = (options, allowedKeys) => {
+        return Object.fromEntries(Object.entries(options).filter(([key]) => allowedKeys.includes(key)));
+    };
+    useEffect(() => {
+        const fetchPaymentType = async () => {
+            const response = await walletService.selectPaymentType();
+            console.log('response', response);
+            const filteredPaymentTypes = filterPaymentOptions(response, ['union_pay_wap_payment', 'payme_wap_payment']);
+            setPaymentType(filteredPaymentTypes);
+        };
+        fetchPaymentType();
+    }, []);
 
-//     return (
-//         <SafeAreaView className="flex-1 bg-white" edges={['top', 'right', 'left']}>
-//             <ScrollView className="flex-1 ">
-//                 <View className="flex-1 mx-[5%]">
-//                     <View style={{ marginTop: 25 }}>
-//                         <Pressable
-//                             onPress={() => {
-//                                 if (router.canGoBack()) {
-//                                     router.back();
-//                                 } else {
-//                                     router.replace('/accountMainPage');
-//                                 }
-//                             }}
-//                         >
-//                             <CrossLogoSvg />
-//                         </Pressable>
-//                         <Text style={{ fontSize: 45, marginVertical: 25 }}>錢包</Text>
-//                     </View>
-//                     <View>
-//                         <ImageBackground
-//                             className="flex-col-reverse shadow-lg"
-//                             style={{ height: 200 }}
-//                             source={require('../../assets/walletCard1.png')}
-//                             resizeMode="contain"
-//                         >
-//                             <View className="mx-[5%] pb-6">
-//                                 <Text className="text-white text-xl">餘額 (HKD)</Text>
-//                                 <View className="flex-row  items-center justify-between ">
-//                                     <Text style={{ fontSize: 52 }} className=" text-white font-bold">
-//                                         {loading ? (
-//                                             <View className="items-center justify-center">
-//                                                 <ActivityIndicator />
-//                                             </View>
-//                                         ) : (
-//                                             <>
-//                                                 <Text>$</Text>
-//                                                 {formatMoney(walletBalance)}
-//                                             </>
-//                                         )}
-//                                     </Text>
-//                                     <Pressable
-//                                         className="rounded-2xl items-center justify-center p-3 px-5 pr-6 "
-//                                         style={{
-//                                             backgroundColor: 'rgba(231, 242, 248, 0.2)'
-//                                         }}
-//                                         onPress={() => {
-//                                             console.log('增值');
-//                                             setModalVisible(true);
-//                                         }}
-//                                     >
-//                                         <Text className="text-white font-bold">+ 增值</Text>
-//                                     </Pressable>
-//                                 </View>
-//                             </View>
-//                         </ImageBackground>
-//                     </View>
-//                     <View className="flex-row-reverse mt-2 mb-6">
-//                         <Pressable
-//                             onPress={() => {
-//                                 router.push({
-//                                     pathname: '/paymentRecord',
-//                                     params: { walletBalance: formatMoney(walletBalance) }
-//                                 });
-//                             }}
-//                         >
-//                             <Text className="text-[#02677D] text-lg underline">付款記錄</Text>
-//                         </Pressable>
-//                     </View>
-//                 </View>
+    const handleTopUp = (selectedValue) => {
+        setSelectedPaymentType(selectedValue);
+        setModalVisible(false);
+        setAmountModalVisible(true);
+    };
 
-//                 <View className="w-full h-1 bg-[#DBE4E8]" />
+    const handleAmountConfirm = async (inputAmount) => {
+        setAmountModalVisible(false);
 
-//                 <View className="flex-row justify-between mx-[5%] pt-6 pb-3">
-//                     <Text className="text-xl">優惠券</Text>
-//                     <Pressable onPress={() => router.push('couponPage')}>
-//                         <Text className="text-xl text-[#888888]">顯示所有</Text>
-//                     </Pressable>
-//                 </View>
+        try {
+            const numericAmount = parseFloat(inputAmount);
+            if (isNaN(numericAmount) || numericAmount <= 0) {
+                throw new Error('Invalid amount');
+            }
 
-//                 <View className="flex-1 flex-col mx-[5%]">
-//                     {loading ? (
-//                         <View className="items-center justify-center">
-//                             <ActivityIndicator />
-//                         </View>
-//                     ) : (
-//                         <View>
-//                             {coupons
-//                                 .filter(
-//                                     (coupon) =>
-//                                         coupon.is_consumed === false && new Date(coupon.expire_date) > new Date()
-//                                 )
-//                                 .slice(0, 2)
-//                                 .map((coupon, index) => (
-//                                     <IndividualCouponComponent
-//                                         key={index}
-//                                         title={coupon.name}
-//                                         price={coupon.amount}
-//                                         detail={coupon.description}
-//                                         date={formatCouponDate(coupon.expire_date)}
-//                                     />
-//                                 ))}
-//                         </View>
-//                     )}
-//                 </View>
-//             </ScrollView>
-//             <TopUpModal
-//                 visible={modalVisible}
-//                 onClose={() => setModalVisible(false)}
-//                 onSelect={handleTopUp}
-//                 paymentOptions={paymentType}
-//             />
-//             <AmountInputModal
-//                 visible={amountModalVisible}
-//                 onClose={() => setAmountModalVisible(false)}
-//                 onConfirm={handleAmountConfirm}
-//             />
-//         </SafeAreaView>
-//     );
-// };
+            const response = await walletService.submitPaymentAfterSelectingType(
+                numericAmount,
+                selectedPaymentType,
+                'test'
+            );
 
-// export default WalletPageComponent;
+            setOutTradeNo(response.out_trade_no);
+            console.log('handleAmountConfirm outtradeno here,', response.out_trade_no);
+            console.log('just state outTradeNo here,', outTradeNo);
+            setIsExpectingPayment(true);
+            paymentInitiatedTime.current = new Date().getTime();
 
-import {
-    View,
-    Image,
-    Text,
-    ScrollView,
-    AppState,
-    Pressable,
-    ImageBackground,
-    ActivityIndicator,
-    Modal,
-    Alert,
-    TextInput,
-    Linking
-} from 'react-native';
-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 { walletService } from '../../service/walletService';
-import UnionPayImage from '../../assets/unionpay.png';
-import PayMeImage from '../../assets/payme.png';
-import { formatCouponDate, formatDate } from '../../util/lib';
-import { set } from 'date-fns';
-import { reloadAppAsync } from 'expo';
+            const payUrl = response.pay_url;
+            const supported = await Linking.canOpenURL(payUrl);
 
-const TopUpModal = ({ visible, onClose, onSelect, paymentOptions }) => {
-    const getPaymentImage = (key) => {
-        switch (key) {
-            case 'union_pay_wap_payment':
-                return UnionPayImage;
-            case 'payme_wap_payment':
-                return PayMeImage;
-            default:
-                return null;
+            if (supported) {
+                await Linking.openURL(payUrl);
+            } else {
+                throw new Error("Can't open payment URL");
+            }
+        } catch (error) {
+            console.error('Top-up failed:', error);
+            Alert.alert('Error', 'Failed to process top-up. Please try again.');
         }
     };
+
     return (
-        <Modal animationType="fade" transparent={true} visible={visible} onRequestClose={onClose}>
-            <View
-                style={{
-                    flex: 1,
-                    justifyContent: 'center',
-                    alignItems: 'center',
-                    backgroundColor: 'rgba(0,0,0,0.5)'
-                }}
-            >
-                <View
-                    style={{
-                        backgroundColor: 'white',
-                        padding: 20,
-                        borderRadius: 10,
-                        width: '80%',
-                        maxHeight: '80%'
-                    }}
-                >
-                    <Text style={{ fontSize: 20, marginBottom: 20 }}>選擇支付方式</Text>
-                    <ScrollView>
-                        {Object.entries(paymentOptions).map(([key, value]) => (
-                            <Pressable
-                                key={key}
-                                onPress={() => onSelect(value)}
-                                style={{
-                                    padding: 10,
-                                    marginBottom: 10,
-                                    borderBottomWidth: 1,
-                                    borderBottomColor: '#eee'
-                                }}
-                            >
-                                <View className="flex flex-row items-center space-x-2">
-                                    <Image
-                                        source={getPaymentImage(key)}
-                                        style={{ width: 40, height: 40, marginRight: 10 }}
-                                        resizeMode="contain"
-                                    />
-                                    <Text className="tracking-wider">
-                                        {key === 'union_pay_wap_payment' ? 'UnionPay' : 'PayMe'}
+        <SafeAreaView className="flex-1 bg-white" edges={['top', 'right', 'left']}>
+            <ScrollView className="flex-1 ">
+                <View className="flex-1 mx-[5%]">
+                    <View style={{ marginTop: 25 }}>
+                        <Pressable
+                            onPress={() => {
+                                if (router.canGoBack()) {
+                                    router.back();
+                                } else {
+                                    router.replace('/accountMainPage');
+                                }
+                            }}
+                        >
+                            <CrossLogoSvg />
+                        </Pressable>
+                        <Text style={{ fontSize: 45, marginVertical: 25 }}>錢包</Text>
+                    </View>
+                    <View>
+                        <ImageBackground
+                            className="flex-col-reverse shadow-lg"
+                            style={{ height: 200 }}
+                            source={require('../../assets/walletCard1.png')}
+                            resizeMode="contain"
+                        >
+                            <View className="mx-[5%] pb-6">
+                                <Text className="text-white text-xl">餘額 (HKD)</Text>
+                                <View className="flex-row  items-center justify-between ">
+                                    <Text style={{ fontSize: 52 }} className=" text-white font-bold">
+                                        {loading ? (
+                                            <View className="items-center justify-center">
+                                                <ActivityIndicator />
+                                            </View>
+                                        ) : (
+                                            <>
+                                                <Text>$</Text>
+                                                {formatMoney(walletBalance)}
+                                            </>
+                                        )}
                                     </Text>
+                                    <Pressable
+                                        className="rounded-2xl items-center justify-center p-3 px-5 pr-6 "
+                                        style={{
+                                            backgroundColor: 'rgba(231, 242, 248, 0.2)'
+                                        }}
+                                        onPress={() => {
+                                            console.log('增值');
+                                            setModalVisible(true);
+                                        }}
+                                    >
+                                        <Text className="text-white font-bold">+ 增值</Text>
+                                    </Pressable>
                                 </View>
-                            </Pressable>
-                        ))}
-                    </ScrollView>
-                    <Pressable onPress={onClose} style={{ padding: 10, alignItems: 'center', marginTop: 10 }}>
-                        <Text style={{ color: 'red' }}>關閉</Text>
-                    </Pressable>
+                            </View>
+                        </ImageBackground>
+                    </View>
+                    <View className="flex-row-reverse mt-2 mb-6">
+                        <Pressable
+                            onPress={() => {
+                                router.push({
+                                    pathname: '/paymentRecord',
+                                    params: { walletBalance: formatMoney(walletBalance) }
+                                });
+                            }}
+                        >
+                            <Text className="text-[#02677D] text-lg underline">付款記錄</Text>
+                        </Pressable>
+                    </View>
                 </View>
-            </View>
-        </Modal>
-    );
-};
-const AmountInputModal = ({ visible, onClose, onConfirm }) => {
-    const [inputAmount, setInputAmount] = useState('');
 
-    return (
-        <Modal animationType="fade" transparent={true} visible={visible} onRequestClose={onClose}>
-            <View
-                style={{
-                    flex: 1,
-                    justifyContent: 'center',
-                    alignItems: 'center',
-                    backgroundColor: 'rgba(0,0,0,0.5)'
-                }}
-            >
-                <View
-                    style={{
-                        backgroundColor: 'white',
-                        padding: 20,
-                        borderRadius: 10,
-                        width: '80%'
-                    }}
-                >
-                    <Text style={{ fontSize: 20, marginBottom: 20 }}>輸入增值金額</Text>
-                    <TextInput
-                        style={{
-                            borderWidth: 1,
-                            borderColor: '#ccc',
-                            borderRadius: 5,
-                            padding: 10,
-                            marginBottom: 20,
-                            fontSize: 18
-                        }}
-                        keyboardType="numeric"
-                        placeholder="輸入金額"
-                        value={inputAmount}
-                        onChangeText={setInputAmount}
-                    />
-                    <Pressable
-                        onPress={() => onConfirm(inputAmount)}
-                        style={{
-                            backgroundColor: '#02677D',
-                            padding: 10,
-                            borderRadius: 5,
-                            alignItems: 'center'
-                        }}
-                    >
-                        <Text style={{ color: 'white', fontSize: 18 }}>確認</Text>
-                    </Pressable>
-                    <Pressable onPress={onClose} style={{ padding: 10, alignItems: 'center', marginTop: 10 }}>
-                        <Text style={{ color: 'red' }}>取消</Text>
+                <View className="w-full h-1 bg-[#DBE4E8]" />
+
+                <View className="flex-row justify-between mx-[5%] pt-6 pb-3">
+                    <Text className="text-xl">優惠券</Text>
+                    <Pressable onPress={() => router.push('couponPage')}>
+                        <Text className="text-xl text-[#888888]">顯示所有</Text>
                     </Pressable>
                 </View>
-            </View>
-        </Modal>
+
+                <View className="flex-1 flex-col mx-[5%]">
+                    {loading ? (
+                        <View className="items-center justify-center">
+                            <ActivityIndicator />
+                        </View>
+                    ) : (
+                        <View>
+                            {coupons
+                                .filter(
+                                    (coupon) =>
+                                        coupon.is_consumed === false && new Date(coupon.expire_date) > new Date()
+                                )
+                                .slice(0, 2)
+                                .map((coupon, index) => (
+                                    <IndividualCouponComponent
+                                        key={index}
+                                        title={coupon.name}
+                                        price={coupon.amount}
+                                        detail={coupon.description}
+                                        date={formatCouponDate(coupon.expire_date)}
+                                    />
+                                ))}
+                        </View>
+                    )}
+                </View>
+            </ScrollView>
+            <TopUpModal
+                visible={modalVisible}
+                onClose={() => setModalVisible(false)}
+                onSelect={handleTopUp}
+                paymentOptions={paymentType}
+            />
+            <AmountInputModal
+                visible={amountModalVisible}
+                onClose={() => setAmountModalVisible(false)}
+                onConfirm={handleAmountConfirm}
+            />
+        </SafeAreaView>
     );
 };
 
-export const IndividualCouponComponent = ({
-    title,
-    price,
-    detail,
-    date
-}: {
-    title: string;
-    price: string;
-    detail: string;
-    date: string;
-}) => {
-    return (
-        <Pressable onPress={() => console.log('abc')}>
-            <View className="bg-[#e7f2f8] h-[124px]  rounded-xl flex-row mb-3">
-                <View className="bg-white mx-3 my-3 w-[28%] rounded-xl">
-                    <View className="flex-row justify-center items-center pr-4 pt-4 ">
-                        <Text className="color-[#02677d] text-2xl pl-2 pr-1">$</Text>
-                        <Text className="color-[#02677d] text-3xl font-bold" adjustsFontSizeToFit={true}>
-                            {price}
-                        </Text>
-                    </View>
-                    <View className="items-center justify-center">
-                        <Text className="text-base mt-1">{title}</Text>
-                    </View>
-                </View>
+export default WalletPageComponent;
 
-                {/* //dash line */}
-                <View style={{ overflow: 'hidden' }}>
-                    <View
-                        style={{
-                            borderStyle: 'dashed',
-                            borderWidth: 1,
-                            borderColor: '#CCCCCC',
-                            margin: -1,
-                            width: 0,
-                            marginRight: 0,
-                            height: '100%'
-                        }}
-                    >
-                        <View style={{ height: 60 }}></View>
-                    </View>
-                </View>
+//////BELOW uses QFPay 的托管收银台页面 to 增值
+//////BELOW uses QFPay 的托管收银台页面 to 增值
+//////BELOW uses QFPay 的托管收银台页面 to 增值
+//////BELOW uses QFPay 的托管收银台页面 to 增值
+//////BELOW uses QFPay 的托管收银台页面 to 增值
+
+// import {
+//     View,
+//     Image,
+//     Text,
+//     ScrollView,
+//     AppState,
+//     Pressable,
+//     ImageBackground,
+//     ActivityIndicator,
+//     Modal,
+//     Alert,
+//     TextInput,
+//     Linking
+// } from 'react-native';
+// 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 { walletService } from '../../service/walletService';
+// import UnionPayImage from '../../assets/unionpay.png';
+// import PayMeImage from '../../assets/payme.png';
+// import { formatCouponDate, formatDate } from '../../util/lib';
+// import { set } from 'date-fns';
+// import { reloadAppAsync } from 'expo';
+// import sha256 from 'crypto-js/sha256';
+
+// const AmountInputModal = ({ visible, onClose, onConfirm }) => {
+//     const [inputAmount, setInputAmount] = useState('');
+
+//     return (
+//         <Modal animationType="fade" transparent={true} visible={visible} onRequestClose={onClose}>
+//             <View
+//                 style={{
+//                     flex: 1,
+//                     justifyContent: 'center',
+//                     alignItems: 'center',
+//                     backgroundColor: 'rgba(0,0,0,0.5)'
+//                 }}
+//             >
+//                 <View
+//                     style={{
+//                         backgroundColor: 'white',
+//                         padding: 20,
+//                         borderRadius: 10,
+//                         width: '80%'
+//                     }}
+//                 >
+//                     <Text style={{ fontSize: 20, marginBottom: 20 }}>輸入增值金額</Text>
+//                     <TextInput
+//                         style={{
+//                             borderWidth: 1,
+//                             borderColor: '#ccc',
+//                             borderRadius: 5,
+//                             padding: 10,
+//                             marginBottom: 20,
+//                             fontSize: 18
+//                         }}
+//                         keyboardType="numeric"
+//                         placeholder="輸入金額"
+//                         value={inputAmount}
+//                         onChangeText={setInputAmount}
+//                     />
+//                     <Pressable
+//                         onPress={() => onConfirm(inputAmount)}
+//                         style={{
+//                             backgroundColor: '#02677D',
+//                             padding: 10,
+//                             borderRadius: 5,
+//                             alignItems: 'center'
+//                         }}
+//                     >
+//                         <Text style={{ color: 'white', fontSize: 18 }}>確認</Text>
+//                     </Pressable>
+//                     <Pressable onPress={onClose} style={{ padding: 10, alignItems: 'center', marginTop: 10 }}>
+//                         <Text style={{ color: 'red' }}>取消</Text>
+//                     </Pressable>
+//                 </View>
+//             </View>
+//         </Modal>
+//     );
+// };
+
+// export const IndividualCouponComponent = ({
+//     title,
+//     price,
+//     detail,
+//     date
+// }: {
+//     title: string;
+//     price: string;
+//     detail: string;
+//     date: string;
+// }) => {
+//     return (
+//         <Pressable onPress={() => console.log('abc')}>
+//             <View className="bg-[#e7f2f8] h-[124px]  rounded-xl flex-row mb-3">
+//                 <View className="bg-white mx-3 my-3 w-[28%] rounded-xl">
+//                     <View className="flex-row justify-center items-center pr-4 pt-4 ">
+//                         <Text className="color-[#02677d] text-2xl pl-2 pr-1">$</Text>
+//                         <Text className="color-[#02677d] text-3xl font-bold" adjustsFontSizeToFit={true}>
+//                             {price}
+//                         </Text>
+//                     </View>
+//                     <View className="items-center justify-center">
+//                         <Text className="text-base mt-1">{title}</Text>
+//                     </View>
+//                 </View>
 
-                <View className="flex-col flex-1  m-[5%] justify-center ">
-                    <Text className="text-lg">{title}</Text>
-                    <Text className="color-[#888888] text-sm">{detail}</Text>
-                    <View className="flex-row items-center ">
-                        <Text className="text-base">有效期 </Text>
-                        <Text className="text-base font-bold text-[#02677d]">{date}</Text>
-                    </View>
-                </View>
-            </View>
-        </Pressable>
-    );
-};
+//                 {/* //dash line */}
+//                 <View style={{ overflow: 'hidden' }}>
+//                     <View
+//                         style={{
+//                             borderStyle: 'dashed',
+//                             borderWidth: 1,
+//                             borderColor: '#CCCCCC',
+//                             margin: -1,
+//                             width: 0,
+//                             marginRight: 0,
+//                             height: '100%'
+//                         }}
+//                     >
+//                         <View style={{ height: 60 }}></View>
+//                     </View>
+//                 </View>
 
-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('');
-    const PAYMENT_CHECK_TIMEOUT = 5 * 60 * 1000; // 5 minutes in milliseconds
-    const [paymentStatus, setPaymentStatus] = useState(null);
-    const [isExpectingPayment, setIsExpectingPayment] = useState(false);
-    const appState = useRef(AppState.currentState);
-    const paymentInitiatedTime = useRef(null);
+//                 <View className="flex-col flex-1  m-[5%] justify-center ">
+//                     <Text className="text-lg">{title}</Text>
+//                     <Text className="color-[#888888] text-sm">{detail}</Text>
+//                     <View className="flex-row items-center ">
+//                         <Text className="text-base">有效期 </Text>
+//                         <Text className="text-base font-bold text-[#02677d]">{date}</Text>
+//                     </View>
+//                 </View>
+//             </View>
+//         </Pressable>
+//     );
+// };
 
-    useEffect(() => {
-        const subscription = AppState.addEventListener('change', (nextAppState) => {
-            if (
-                appState.current.match(/inactive|background/) &&
-                nextAppState === 'active' &&
-                isExpectingPayment &&
-                outTradeNo &&
-                paymentInitiatedTime.current
-            ) {
-                const currentTime = new Date().getTime();
-                if (currentTime - paymentInitiatedTime.current < PAYMENT_CHECK_TIMEOUT) {
-                    checkPaymentStatus();
-                } else {
-                    // Payment check timeout reached
-                    setIsExpectingPayment(false);
-                    setOutTradeNo('');
-                    paymentInitiatedTime.current = null;
-                    Alert.alert(
-                        'Payment Timeout',
-                        'The payment status check has timed out. Please check your payment history.'
-                    );
-                }
-            }
-            appState.current = nextAppState;
-        });
+// 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('');
+//     const PAYMENT_CHECK_TIMEOUT = 5 * 60 * 1000; // 5 minutes in milliseconds
+//     const [paymentStatus, setPaymentStatus] = useState(null);
+//     const [isExpectingPayment, setIsExpectingPayment] = useState(false);
+//     const appState = useRef(AppState.currentState);
+//     const paymentInitiatedTime = useRef(null);
 
-        return () => {
-            subscription.remove();
-        };
-    }, [outTradeNo, isExpectingPayment]);
+//     useEffect(() => {
+//         const subscription = AppState.addEventListener('change', (nextAppState) => {
+//             if (
+//                 appState.current.match(/inactive|background/) &&
+//                 nextAppState === 'active' &&
+//                 isExpectingPayment &&
+//                 // outTradeNo &&
+//                 paymentInitiatedTime.current
+//             ) {
+//                 const currentTime = new Date().getTime();
+//                 if (currentTime - paymentInitiatedTime.current < PAYMENT_CHECK_TIMEOUT) {
+//                     checkPaymentStatus();
+//                 } else {
+//                     // Payment check timeout reached
+//                     setIsExpectingPayment(false);
+//                     setOutTradeNo('');
+//                     paymentInitiatedTime.current = null;
+//                     Alert.alert(
+//                         'Payment Timeout',
+//                         'The payment status check has timed out. Please check your payment history.'
+//                     );
+//                 }
+//             }
+//             appState.current = nextAppState;
+//         });
 
-    const checkPaymentStatus = async () => {
-        try {
-            const result = await walletService.checkPaymentStatus(outTradeNo);
-            setPaymentStatus(result);
-            console.log('checkPaymentStatus from walletPageComponent', result);
-            if (result) {
-                // Payment successful
-                Alert.alert('Success', 'Payment was successful!', [
-                    {
-                        text: 'OK',
-                        onPress: async () => {
-                            const wallet = await walletService.getWalletBalance();
-                            setWalletBalance(wallet);
-                            console.log('new wallet:', wallet);
-                        }
-                    }
-                ]);
-            } else {
-                Alert.alert('Payment Failed', 'Payment was not successful. Please try again.');
-            }
-            setIsExpectingPayment(false);
-            setOutTradeNo('');
-            paymentInitiatedTime.current = null;
-        } catch (error) {
-            console.error('Failed to check payment status:', error);
-            Alert.alert('Error', 'Failed to check payment status. Please check your payment history.');
-        }
-    };
+//         return () => {
+//             subscription.remove();
+//         };
+//     }, [outTradeNo, isExpectingPayment]);
 
-    // useEffect(() => {
-    //     const handleAppStateChange = (nextAppState) => {
-    //         if (appState.match(/inactive|background/) && nextAppState === 'active') {
-    //             console.log('App has come to the foreground!');
-    //             // Check payment status or update UI here
-    //             console.log('outTradeNo', outTradeNo);
-    //         }
-    //         setAppState(nextAppState);
-    //     };
+//     const checkPaymentStatus = async () => {
+//         try {
+//             const result = await walletService.checkPaymentStatus(outTradeNo);
+//             setPaymentStatus(result);
+//             console.log('checkPaymentStatus from walletPageComponent', result);
+//             if (result) {
+//                 // Payment successful
+//                 Alert.alert('Success', 'Payment was successful!', [
+//                     {
+//                         text: 'OK',
+//                         onPress: async () => {
+//                             const wallet = await walletService.getWalletBalance();
+//                             setWalletBalance(wallet);
+//                             console.log('new wallet:', wallet);
+//                         }
+//                     }
+//                 ]);
+//             } else {
+//                 Alert.alert('Payment Failed', 'Payment was not successful. Please try again.');
+//             }
+//             setIsExpectingPayment(false);
+//             setOutTradeNo('');
+//             paymentInitiatedTime.current = null;
+//         } catch (error) {
+//             console.error('Failed to check payment status:', error);
+//             Alert.alert('Error', 'Failed to check payment status. Please check your payment history.');
+//         }
+//     };
 
-    //     AppState.addEventListener('change', handleAppStateChange);
-    // }, [appState]);
+//     useEffect(() => {
+//         const fetchData = async () => {
+//             try {
+//                 setLoading(true);
+//                 const info = await walletService.getCustomerInfo();
 
-    useEffect(() => {
-        const fetchData = async () => {
-            try {
-                setLoading(true);
-                const info = await walletService.getCustomerInfo();
-                // const coupon = await walletService.getCouponForSpecificUser(info.id);
-                const wallet = await walletService.getWalletBalance();
-                console.log(wallet);
-                setUserID(info.id);
-                setWalletBalance(wallet);
-                setCoupons(coupon);
-            } catch (error) {
-                console.log(error);
-            } finally {
-                setLoading(false);
-            }
-        };
+//                 const wallet = await walletService.getWalletBalance();
+//                 console.log(wallet);
+//                 setUserID(info.id);
+//                 setWalletBalance(wallet);
+//                 setCoupons(coupon);
+//             } catch (error) {
+//                 console.log(error);
+//             } finally {
+//                 setLoading(false);
+//             }
+//         };
 
-        fetchData();
-    }, []);
+//         fetchData();
+//     }, []);
 
-    const formatMoney = (amount: any) => {
-        if (typeof amount !== 'number') {
-            amount = Number(amount);
-        }
-        return amount.toLocaleString('en-US');
-    };
-    const filterPaymentOptions = (options, allowedKeys) => {
-        return Object.fromEntries(Object.entries(options).filter(([key]) => allowedKeys.includes(key)));
-    };
-    useEffect(() => {
-        const fetchPaymentType = async () => {
-            const response = await walletService.selectPaymentType();
-            console.log('response', response);
-            const filteredPaymentTypes = filterPaymentOptions(response, ['union_pay_wap_payment', 'payme_wap_payment']);
-            setPaymentType(filteredPaymentTypes);
-        };
-        fetchPaymentType();
-    }, []);
+//     const formatMoney = (amount: any) => {
+//         if (typeof amount !== 'number') {
+//             amount = Number(amount);
+//         }
+//         return amount.toLocaleString('en-US');
+//     };
+//     const filterPaymentOptions = (options, allowedKeys) => {
+//         return Object.fromEntries(Object.entries(options).filter(([key]) => allowedKeys.includes(key)));
+//     };
 
-    const handleTopUp = (selectedValue) => {
-        setSelectedPaymentType(selectedValue);
-        setModalVisible(false);
-        setAmountModalVisible(true);
-    };
+//     function formatTime(utcTimeString) {
+//         // Parse the UTC time string
+//         const date = new Date(utcTimeString);
 
-    const handleAmountConfirm = async (inputAmount) => {
-        setAmountModalVisible(false);
+//         // Add 8 hours
+//         date.setHours(date.getHours());
 
-        try {
-            const numericAmount = parseFloat(inputAmount);
-            if (isNaN(numericAmount) || numericAmount <= 0) {
-                throw new Error('Invalid amount');
-            }
+//         // Format the date
+//         const year = date.getFullYear();
+//         const month = String(date.getMonth() + 1).padStart(2, '0');
+//         const day = String(date.getDate()).padStart(2, '0');
+//         const hours = String(date.getHours()).padStart(2, '0');
+//         const minutes = String(date.getMinutes()).padStart(2, '0');
+//         const seconds = String(date.getSeconds()).padStart(2, '0');
 
-            const response = await walletService.submitPaymentAfterSelectingType(
-                numericAmount,
-                selectedPaymentType,
-                'test'
-            );
+//         // Return the formatted string
+//         return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
+//     }
 
-            setOutTradeNo(response.out_trade_no);
-            console.log('handleAmountConfirm outtradeno here,', response.out_trade_no);
-            console.log('just state outTradeNo here,', outTradeNo);
-            setIsExpectingPayment(true);
-            paymentInitiatedTime.current = new Date().getTime();
+//     useEffect(() => {
+//         const fetchPaymentType = async () => {
+//             const response = await walletService.selectPaymentType();
+//             // console.log('response', response);
+//             const filteredPaymentTypes = filterPaymentOptions(response, ['union_pay_wap_payment', 'payme_wap_payment']);
+//             setPaymentType(filteredPaymentTypes);
+//         };
+//         fetchPaymentType();
+//     }, []);
 
-            const payUrl = response.pay_url;
-            const supported = await Linking.canOpenURL(payUrl);
+//     const handleAmountConfirm = async (inputAmount) => {
+//         setAmountModalVisible(false);
+//         try {
+//             const response = await walletService.getOutTradeNo();
+//             if (response) {
+//                 setIsExpectingPayment(true);
+//                 paymentInitiatedTime.current = new Date().getTime();
+//                 const now = new Date();
+//                 const formattedTime = formatTime(now);
+//                 console.log(formattedTime);
+//                 const out_trade_no = response;
+
+//                 let amount = parseInt(inputAmount, 10) * 100;
+//                 const origin = 'https://openapi-hk.qfapi.com/checkstand/#/?';
+//                 const obj = {
+//                     appcode: process.env.QFPAY_CODE,
+//                     goods_name: 'Crazy Charge 錢包增值',
+//                     out_trade_no: out_trade_no,
+//                     paysource: 'crazycharge_checkout',
+//                     return_url: 'https://www.google.com',
+//                     failed_url: 'https://www.google.com',
+//                     notify_url: 'https://api.crazycharge.com.hk/api/v1/clients/qfpay/webhook',
+//                     sign_type: 'sha256',
+//                     txamt: amount,
+//                     txcurrcd: 'HKD',
+//                     txdtm: formattedTime
+//                 };
 
-            if (supported) {
-                await Linking.openURL(payUrl);
-            } else {
-                throw new Error("Can't open payment URL");
-            }
-        } catch (error) {
-            console.error('Top-up failed:', error);
-            Alert.alert('Error', 'Failed to process top-up. Please try again.');
-        }
-    };
+//                 const paramStringify = (json, flag?) => {
+//                     let str = '';
+//                     let keysArr = Object.keys(json);
+//                     keysArr.sort().forEach((val) => {
+//                         if (!json[val]) return;
+//                         str += `${val}=${flag ? encodeURIComponent(json[val]) : json[val]}&`;
+//                     });
+//                     return str.slice(0, -1);
+//                 };
 
-    return (
-        <SafeAreaView className="flex-1 bg-white" edges={['top', 'right', 'left']}>
-            <ScrollView className="flex-1 ">
-                <View className="flex-1 mx-[5%]">
-                    <View style={{ marginTop: 25 }}>
-                        <Pressable
-                            onPress={() => {
-                                if (router.canGoBack()) {
-                                    router.back();
-                                } else {
-                                    router.replace('/accountMainPage');
-                                }
-                            }}
-                        >
-                            <CrossLogoSvg />
-                        </Pressable>
-                        <Text style={{ fontSize: 45, marginVertical: 25 }}>錢包</Text>
-                    </View>
-                    <View>
-                        <ImageBackground
-                            className="flex-col-reverse shadow-lg"
-                            style={{ height: 200 }}
-                            source={require('../../assets/walletCard1.png')}
-                            resizeMode="contain"
-                        >
-                            <View className="mx-[5%] pb-6">
-                                <Text className="text-white text-xl">餘額 (HKD)</Text>
-                                <View className="flex-row  items-center justify-between ">
-                                    <Text style={{ fontSize: 52 }} className=" text-white font-bold">
-                                        {loading ? (
-                                            <View className="items-center justify-center">
-                                                <ActivityIndicator />
-                                            </View>
-                                        ) : (
-                                            <>
-                                                <Text>$</Text>
-                                                {formatMoney(walletBalance)}
-                                            </>
-                                        )}
-                                    </Text>
-                                    <Pressable
-                                        className="rounded-2xl items-center justify-center p-3 px-5 pr-6 "
-                                        style={{
-                                            backgroundColor: 'rgba(231, 242, 248, 0.2)'
-                                        }}
-                                        onPress={() => {
-                                            console.log('增值');
-                                            setModalVisible(true);
-                                        }}
-                                    >
-                                        <Text className="text-white font-bold">+ 增值</Text>
-                                    </Pressable>
-                                </View>
-                            </View>
-                        </ImageBackground>
-                    </View>
-                    <View className="flex-row-reverse mt-2 mb-6">
-                        <Pressable
-                            onPress={() => {
-                                router.push({
-                                    pathname: '/paymentRecord',
-                                    params: { walletBalance: formatMoney(walletBalance) }
-                                });
-                            }}
-                        >
-                            <Text className="text-[#02677D] text-lg underline">付款記錄</Text>
-                        </Pressable>
-                    </View>
-                </View>
+//                 const api_key = process.env.QFPAY_KEY;
+//                 const params = paramStringify(obj);
+//                 const sign = sha256(`${params}${api_key}`).toString();
+//                 const url = `${origin}${paramStringify(obj, true)}&sign=${sign}`;
+
+//                 try {
+//                     const supported = await Linking.canOpenURL(url);
+//                     if (supported) {
+//                         await Linking.openURL(url);
+//                     } else {
+//                         Alert.alert('錯誤', '請稍後再試');
+//                     }
+//                 } catch (error) {
+//                     console.error('Top-up failed:', error);
+//                     Alert.alert('Error', 'Failed to process top-up. Please try again.');
+//                 }
+//             } else {
+//                 console.log('no');
+//             }
+//         } catch (error) {
+//             console.log(error);
+//         }
+//     };
 
-                <View className="w-full h-1 bg-[#DBE4E8]" />
+//     return (
+//         <SafeAreaView className="flex-1 bg-white" edges={['top', 'right', 'left']}>
+//             <ScrollView className="flex-1 ">
+//                 <View className="flex-1 mx-[5%]">
+//                     <View style={{ marginTop: 25 }}>
+//                         <Pressable
+//                             onPress={() => {
+//                                 if (router.canGoBack()) {
+//                                     router.back();
+//                                 } else {
+//                                     router.replace('/accountMainPage');
+//                                 }
+//                             }}
+//                         >
+//                             <CrossLogoSvg />
+//                         </Pressable>
+//                         <Text style={{ fontSize: 45, marginVertical: 25 }}>錢包</Text>
+//                     </View>
+//                     <View>
+//                         <ImageBackground
+//                             className="flex-col-reverse shadow-lg"
+//                             style={{ height: 200 }}
+//                             source={require('../../assets/walletCard1.png')}
+//                             resizeMode="contain"
+//                         >
+//                             <View className="mx-[5%] pb-6">
+//                                 <Text className="text-white text-xl">餘額 (HKD)</Text>
+//                                 <View className="flex-row  items-center justify-between ">
+//                                     <Text style={{ fontSize: 52 }} className=" text-white font-bold">
+//                                         {loading ? (
+//                                             <View className="items-center justify-center">
+//                                                 <ActivityIndicator />
+//                                             </View>
+//                                         ) : (
+//                                             <>
+//                                                 <Text>$</Text>
+//                                                 {formatMoney(walletBalance)}
+//                                             </>
+//                                         )}
+//                                     </Text>
+//                                     <Pressable
+//                                         className="rounded-2xl items-center justify-center p-3 px-5 pr-6 "
+//                                         style={{
+//                                             backgroundColor: 'rgba(231, 242, 248, 0.2)'
+//                                         }}
+//                                         onPress={() => {
+//                                             console.log('增值');
+//                                             setAmountModalVisible(true);
+//                                         }}
+//                                     >
+//                                         <Text className="text-white font-bold">+ 增值</Text>
+//                                     </Pressable>
+//                                 </View>
+//                             </View>
+//                         </ImageBackground>
+//                     </View>
+//                     <View className="flex-row-reverse mt-2 mb-6">
+//                         <Pressable
+//                             onPress={() => {
+//                                 router.push({
+//                                     pathname: '/paymentRecord',
+//                                     params: { walletBalance: formatMoney(walletBalance) }
+//                                 });
+//                             }}
+//                         >
+//                             <Text className="text-[#02677D] text-lg underline">付款記錄</Text>
+//                         </Pressable>
+//                     </View>
+//                 </View>
 
-                <View className="flex-row justify-between mx-[5%] pt-6 pb-3">
-                    <Text className="text-xl">優惠券</Text>
-                    <Pressable onPress={() => router.push('couponPage')}>
-                        <Text className="text-xl text-[#888888]">顯示所有</Text>
-                    </Pressable>
-                </View>
+//                 <View className="w-full h-1 bg-[#DBE4E8]" />
 
-                <View className="flex-1 flex-col mx-[5%]">
-                    {loading ? (
-                        <View className="items-center justify-center">
-                            <ActivityIndicator />
-                        </View>
-                    ) : (
-                        <View>
-                            {coupons
-                                .filter(
-                                    (coupon) =>
-                                        coupon.is_consumed === false && new Date(coupon.expire_date) > new Date()
-                                )
-                                .slice(0, 2)
-                                .map((coupon, index) => (
-                                    <IndividualCouponComponent
-                                        key={index}
-                                        title={coupon.name}
-                                        price={coupon.amount}
-                                        detail={coupon.description}
-                                        date={formatCouponDate(coupon.expire_date)}
-                                    />
-                                ))}
-                        </View>
-                    )}
-                </View>
-            </ScrollView>
-            <TopUpModal
-                visible={modalVisible}
-                onClose={() => setModalVisible(false)}
-                onSelect={handleTopUp}
-                paymentOptions={paymentType}
-            />
-            <AmountInputModal
-                visible={amountModalVisible}
-                onClose={() => setAmountModalVisible(false)}
-                onConfirm={handleAmountConfirm}
-            />
-        </SafeAreaView>
-    );
-};
+//                 <View className="flex-row justify-between mx-[5%] pt-6 pb-3">
+//                     <Text className="text-xl">優惠券</Text>
+//                     <Pressable onPress={() => router.push('couponPage')}>
+//                         <Text className="text-xl text-[#888888]">顯示所有</Text>
+//                     </Pressable>
+//                 </View>
 
-export default WalletPageComponent;
+//                 <View className="flex-1 flex-col mx-[5%]">
+//                     {loading ? (
+//                         <View className="items-center justify-center">
+//                             <ActivityIndicator />
+//                         </View>
+//                     ) : (
+//                         <View>
+//                             {coupons
+//                                 .filter(
+//                                     (coupon) =>
+//                                         coupon.is_consumed === false && new Date(coupon.expire_date) > new Date()
+//                                 )
+//                                 .slice(0, 2)
+//                                 .map((coupon, index) => (
+//                                     <IndividualCouponComponent
+//                                         key={index}
+//                                         title={coupon.name}
+//                                         price={coupon.amount}
+//                                         detail={coupon.description}
+//                                         date={formatCouponDate(coupon.expire_date)}
+//                                     />
+//                                 ))}
+//                         </View>
+//                     )}
+//                 </View>
+//             </ScrollView>
+//             {/* <TopUpModal
+//                 visible={modalVisible}
+//                 onClose={() => setModalVisible(false)}
+//                 onSelect={handleTopUp}
+//                 paymentOptions={paymentType}
+//             /> */}
+//             <AmountInputModal
+//                 visible={amountModalVisible}
+//                 onClose={() => setAmountModalVisible(false)}
+//                 onConfirm={handleAmountConfirm}
+//             />
+//         </SafeAreaView>
+//     );
+// };
+
+// export default WalletPageComponent;

+ 1 - 1
component/bookingMenuPage/makingBookingPageComponent.tsx

@@ -360,7 +360,7 @@ const MakingBookingPageComponent = () => {
         const label = encodeURIComponent(chargeStationName);
 
         // Google Maps App URL
-        const googleMapsUrl = `google.navigation:q=${latitude},${longitude}`;
+        const googleMapsUrl = `https://www.google.com/maps/search/?api=1&query=${latitude},${longitude}`;
 
         // Fallback URL for web browser
         const webUrl = `https://www.google.com/maps/dir/?api=1&destination=${latitude},${longitude}`;

+ 1 - 1
component/resultDetailPage/resultDetailPageComponent.tsx

@@ -249,7 +249,7 @@ const ResultDetailPageComponent = () => {
         const label = encodeURIComponent(chargeStationName);
 
         // Google Maps App URL
-        const googleMapsUrl = `google.navigation:q=${latitude},${longitude}`;
+        const googleMapsUrl = `https://www.google.com/maps/search/?api=1&query=${latitude},${longitude}`;
 
         // Fallback URL for web browser
         const webUrl = `https://www.google.com/maps/dir/?api=1&destination=${latitude},${longitude}`;

+ 13 - 0
package-lock.json

@@ -15,6 +15,7 @@
         "@types/lodash": "^4.17.7",
         "@types/react-native-datepicker": "^1.7.6",
         "axios": "^1.6.7",
+        "crypto-js": "^4.2.0",
         "date-fns": "^3.6.0",
         "date-fns-tz": "^3.1.3",
         "dotenv": "^16.4.5",
@@ -52,6 +53,7 @@
       },
       "devDependencies": {
         "@babel/core": "^7.20.0",
+        "@types/crypto-js": "^4.2.2",
         "@types/react": "~18.2.79",
         "@types/react-native-modern-datepicker": "^1.0.5",
         "react-native-dotenv": "^3.4.11",
@@ -6308,6 +6310,12 @@
       "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
       "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA=="
     },
+    "node_modules/@types/crypto-js": {
+      "version": "4.2.2",
+      "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.2.2.tgz",
+      "integrity": "sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==",
+      "dev": true
+    },
     "node_modules/@types/geojson": {
       "version": "7946.0.14",
       "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.14.tgz",
@@ -7734,6 +7742,11 @@
         "node": "*"
       }
     },
+    "node_modules/crypto-js": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
+      "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
+    },
     "node_modules/crypto-random-string": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz",

+ 2 - 0
package.json

@@ -16,6 +16,7 @@
     "@types/lodash": "^4.17.7",
     "@types/react-native-datepicker": "^1.7.6",
     "axios": "^1.6.7",
+    "crypto-js": "^4.2.0",
     "date-fns": "^3.6.0",
     "date-fns-tz": "^3.1.3",
     "dotenv": "^16.4.5",
@@ -53,6 +54,7 @@
   },
   "devDependencies": {
     "@babel/core": "^7.20.0",
+    "@types/crypto-js": "^4.2.2",
     "@types/react": "~18.2.79",
     "@types/react-native-modern-datepicker": "^1.0.5",
     "react-native-dotenv": "^3.4.11",

+ 25 - 0
service/walletService.tsx

@@ -83,6 +83,31 @@ class WalletService {
         }
     }
 
+    async getOutTradeNo() {
+        try {
+            const response = await axios.get(`${this.apiUrl}/clients/qfpay/out_trade_no`, {
+                headers: {
+                    Authorization: `Bearer ${await SecureStore.getItemAsync('accessToken')}`
+                }
+            });
+            if (response.status === 200) {
+                const outTradeNo = response.data.out_trade_no;
+
+                return outTradeNo;
+            } else {
+                console.error('get outTradeNo failed:', response.status);
+                return false;
+            }
+        } catch (error) {
+            if (axios.isAxiosError(error)) {
+                console.error('get outTradeNo error:', error.response?.data?.message || error.message);
+            } else {
+                console.error('An unexpected error occurred:', error);
+            }
+            return false;
+        }
+    }
+
     async getTransactionRecord() {
         try {
             const response = await axios.get(`${this.apiUrl}/clients/wallet/transaction/record`, {