|
|
@@ -3,7 +3,9 @@ import { useEffect, useRef, useState } from 'react';
|
|
|
import {
|
|
|
ActivityIndicator,
|
|
|
Alert,
|
|
|
+ AppState,
|
|
|
Dimensions,
|
|
|
+ Linking,
|
|
|
Pressable,
|
|
|
ScrollView,
|
|
|
StyleSheet,
|
|
|
@@ -11,7 +13,7 @@ import {
|
|
|
Vibration,
|
|
|
View
|
|
|
} from 'react-native';
|
|
|
-
|
|
|
+import sha256 from 'crypto-js/sha256';
|
|
|
import ChooseCarForChargingRow from '../../../../component/global/chooseCarForChargingRow';
|
|
|
import { CrossLogoWhiteSvg, QuestionSvg } from '../../../../component/global/SVG';
|
|
|
import { router } from 'expo-router';
|
|
|
@@ -26,103 +28,102 @@ import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
|
|
|
|
const { width: screenWidth, height: screenHeight } = Dimensions.get('window');
|
|
|
|
|
|
-const ChooseCar = ({ carData, loading, selectedCar, setSelectedCar }) => {
|
|
|
- const isLargeScreen = screenHeight >= 800;
|
|
|
- const defaultImageUrl = require('../../../../assets/car1.png');
|
|
|
+// const ChooseCar = ({ carData, loading, selectedCar, setSelectedCar }) => {
|
|
|
+// const isLargeScreen = screenHeight >= 800;
|
|
|
+// const defaultImageUrl = require('../../../../assets/car1.png');
|
|
|
|
|
|
- return (
|
|
|
- <View
|
|
|
- style={{
|
|
|
- ...(isLargeScreen
|
|
|
- ? {
|
|
|
- marginTop: '10%',
|
|
|
- marginBottom: '12%',
|
|
|
- paddingBottom: 12
|
|
|
- }
|
|
|
- : {
|
|
|
- flex: 1,
|
|
|
- alignItems: 'center',
|
|
|
- justifyContent: 'center'
|
|
|
- })
|
|
|
- }}
|
|
|
- >
|
|
|
- <View className="justify-center items-center flex-1 ">
|
|
|
- <View
|
|
|
- style={{
|
|
|
- ...(isLargeScreen
|
|
|
- ? {}
|
|
|
- : {
|
|
|
- backgroundColor: 'rgba(0,0,0,0.7)'
|
|
|
- })
|
|
|
- }}
|
|
|
- >
|
|
|
- {loading ? (
|
|
|
- <View className="w-full">
|
|
|
- <ActivityIndicator color="#34657b" />
|
|
|
- </View>
|
|
|
- ) : (
|
|
|
- <View className="w-screen bg-[#000000B3]">
|
|
|
- <View className="flex-row items-center justify-between mx-[5%] ">
|
|
|
- <Pressable
|
|
|
- className="pt-4 "
|
|
|
- onPress={() => {
|
|
|
- if (router.canGoBack()) {
|
|
|
- router.back();
|
|
|
- } else {
|
|
|
- router.replace('mainPage');
|
|
|
- }
|
|
|
- }}
|
|
|
- >
|
|
|
- <CrossLogoWhiteSvg />
|
|
|
- </Pressable>
|
|
|
+// return (
|
|
|
+// <View
|
|
|
+// style={{
|
|
|
+// ...(isLargeScreen
|
|
|
+// ? {
|
|
|
+// marginTop: '10%',
|
|
|
+// marginBottom: '12%',
|
|
|
+// paddingBottom: 12
|
|
|
+// }
|
|
|
+// : {
|
|
|
+// flex: 1,
|
|
|
+// alignItems: 'center',
|
|
|
+// justifyContent: 'center'
|
|
|
+// })
|
|
|
+// }}
|
|
|
+// >
|
|
|
+// <View className="justify-center items-center flex-1 ">
|
|
|
+// <View
|
|
|
+// style={{
|
|
|
+// ...(isLargeScreen
|
|
|
+// ? {}
|
|
|
+// : {
|
|
|
+// backgroundColor: 'rgba(0,0,0,0.7)'
|
|
|
+// })
|
|
|
+// }}
|
|
|
+// >
|
|
|
+// {loading ? (
|
|
|
+// <View className="w-full">
|
|
|
+// <ActivityIndicator color="#34657b" />
|
|
|
+// </View>
|
|
|
+// ) : (
|
|
|
+// <View className="w-screen bg-[#000000B3]">
|
|
|
+// <View className="flex-row items-center justify-between mx-[5%] ">
|
|
|
+// <Pressable
|
|
|
+// className="pt-4 "
|
|
|
+// onPress={() => {
|
|
|
+// if (router.canGoBack()) {
|
|
|
+// router.back();
|
|
|
+// } else {
|
|
|
+// router.replace('mainPage');
|
|
|
+// }
|
|
|
+// }}
|
|
|
+// >
|
|
|
+// <CrossLogoWhiteSvg />
|
|
|
+// </Pressable>
|
|
|
|
|
|
- <Text className="text-base text-white pt-2">選擇充電車輛</Text>
|
|
|
- <Text className="text-xl text-white pt-2"></Text>
|
|
|
- </View>
|
|
|
+// <Text className="text-base text-white pt-2">選擇充電車輛</Text>
|
|
|
+// <Text className="text-xl text-white pt-2"></Text>
|
|
|
+// </View>
|
|
|
|
|
|
- <ScrollView
|
|
|
- horizontal={true}
|
|
|
- showsHorizontalScrollIndicator={false}
|
|
|
- contentContainerStyle={{
|
|
|
- alignItems: 'center',
|
|
|
- flexDirection: 'row',
|
|
|
- marginVertical: 12
|
|
|
- }}
|
|
|
- className="space-x-2 mx-[5%]"
|
|
|
- >
|
|
|
- {carData.map((car, index) => (
|
|
|
- <ChooseCarForChargingRow
|
|
|
- key={`${car.name}+${index}`}
|
|
|
- image={car.image}
|
|
|
- onPress={() => {
|
|
|
- setSelectedCar(car.id);
|
|
|
- console.log(car.id);
|
|
|
- }}
|
|
|
- isSelected={selectedCar === car.id}
|
|
|
- // imageUrl={image}
|
|
|
- VehicleName={car.name}
|
|
|
- isDefault={car.isDefault}
|
|
|
- />
|
|
|
- ))}
|
|
|
- </ScrollView>
|
|
|
- </View>
|
|
|
- )}
|
|
|
- </View>
|
|
|
- </View>
|
|
|
- </View>
|
|
|
- );
|
|
|
-};
|
|
|
+// <ScrollView
|
|
|
+// horizontal={true}
|
|
|
+// showsHorizontalScrollIndicator={false}
|
|
|
+// contentContainerStyle={{
|
|
|
+// alignItems: 'center',
|
|
|
+// flexDirection: 'row',
|
|
|
+// marginVertical: 12
|
|
|
+// }}
|
|
|
+// className="space-x-2 mx-[5%]"
|
|
|
+// >
|
|
|
+// {carData.map((car, index) => (
|
|
|
+// <ChooseCarForChargingRow
|
|
|
+// key={`${car.name}+${index}`}
|
|
|
+// image={car.image}
|
|
|
+// onPress={() => {
|
|
|
+// setSelectedCar(car.id);
|
|
|
+// console.log(car.id);
|
|
|
+// }}
|
|
|
+// isSelected={selectedCar === car.id}
|
|
|
+// // imageUrl={image}
|
|
|
+// VehicleName={car.name}
|
|
|
+// isDefault={car.isDefault}
|
|
|
+// />
|
|
|
+// ))}
|
|
|
+// </ScrollView>
|
|
|
+// </View>
|
|
|
+// )}
|
|
|
+// </View>
|
|
|
+// </View>
|
|
|
+// </View>
|
|
|
+// );
|
|
|
+// };
|
|
|
|
|
|
//reminder: scan qr code page, ic call should be false
|
|
|
const ScanQrPage = () => {
|
|
|
- const { userID, setUserID } = useUserInfoStore();
|
|
|
- // State declarations
|
|
|
+ const { userID, currentPrice } = useUserInfoStore();
|
|
|
+ const { width: screenWidth, height: screenHeight } = Dimensions.get('window');
|
|
|
const [permission, requestPermission] = useCameraPermissions();
|
|
|
const [scanned, setScanned] = useState(false);
|
|
|
const viewRef = useRef(null);
|
|
|
const [scannedResult, setScannedResult] = useState('');
|
|
|
const [selectedCar, setSelectedCar] = useState('');
|
|
|
-
|
|
|
const now = new Date();
|
|
|
const [loading, setLoading] = useState(true);
|
|
|
const [loading2, setLoading2] = useState(false);
|
|
|
@@ -138,15 +139,13 @@ const ScanQrPage = () => {
|
|
|
full: false
|
|
|
});
|
|
|
const [selectedDuration, setSelectedDuration] = useState(null);
|
|
|
-
|
|
|
- const planMap = {
|
|
|
- 25: { duration: 40, fee: 70, kWh: 20, displayDuration: 25 },
|
|
|
- 30: { duration: 45, fee: 87.5, kWh: 25, displayDuration: 30 },
|
|
|
- 40: { duration: 55, fee: 105, kWh: 30, displayDuration: 40 },
|
|
|
- 45: { duration: 60, fee: 140, kWh: 40, displayDuration: 45 },
|
|
|
- full: { duration: 120, fee: 280, displayDuration: '充滿停機' } // Assuming 2 hours for "充滿停機"
|
|
|
- };
|
|
|
-
|
|
|
+ const appState = useRef(AppState.currentState);
|
|
|
+ const [paymentStatus, setPaymentStatus] = useState(null);
|
|
|
+ const [isExpectingPayment, setIsExpectingPayment] = useState(false);
|
|
|
+ const paymentInitiatedTime = useRef(null);
|
|
|
+ const PAYMENT_CHECK_TIMEOUT = 5 * 60 * 1000; // 5 minutes in milliseconds
|
|
|
+ const [outTradeNo, setOutTradeNo] = useState('');
|
|
|
+ const [totalFee, setTotalFee] = useState(0);
|
|
|
// Effect for requesting camera permissions
|
|
|
useEffect(() => {
|
|
|
(async () => {
|
|
|
@@ -212,24 +211,16 @@ const ScanQrPage = () => {
|
|
|
fetchDefaultCar();
|
|
|
}, []);
|
|
|
|
|
|
- if (!permission) {
|
|
|
- return <View />;
|
|
|
- }
|
|
|
-
|
|
|
- if (!permission.granted) {
|
|
|
- return (
|
|
|
- <View className="flex-1 justify-center items-center">
|
|
|
- <Text style={{ textAlign: 'center' }}>
|
|
|
- 我們需要相機權限來掃描機器上的二維碼,以便識別並啟動充電機器。我們不會儲存或共享任何掃描到的資訊。
|
|
|
- 請前往設定開啟相機權限
|
|
|
- </Text>
|
|
|
- </View>
|
|
|
- );
|
|
|
- }
|
|
|
+ const planMap = {
|
|
|
+ 25: { duration: 40, kWh: 20, displayDuration: 25, fee: 20 * currentPrice },
|
|
|
+ 30: { duration: 45, kWh: 25, displayDuration: 30, fee: 25 * currentPrice },
|
|
|
+ 40: { duration: 55, kWh: 30, displayDuration: 40, fee: 30 * currentPrice },
|
|
|
+ 45: { duration: 60, kWh: 40, displayDuration: 45, fee: 40 * currentPrice },
|
|
|
+ full: { duration: 120, displayDuration: '充滿停機', fee: 80 * currentPrice }
|
|
|
+ };
|
|
|
|
|
|
// Function to handle barcode scanning
|
|
|
const handleBarCodeScanned = async ({ bounds, data, type }: { bounds?: any; data: any; type: any }) => {
|
|
|
- // Check if bounds exists and has the expected properties
|
|
|
if (
|
|
|
!bounds ||
|
|
|
typeof bounds.origin?.x !== 'number' ||
|
|
|
@@ -244,7 +235,6 @@ const ScanQrPage = () => {
|
|
|
Vibration.vibrate(100);
|
|
|
console.log(`type: ${type} data: ${data} typeofData ${typeof data}`);
|
|
|
|
|
|
- // Continue with the rest of your scanning logic...
|
|
|
try {
|
|
|
const response = await chargeStationService.getTodayReservation();
|
|
|
if (response) {
|
|
|
@@ -357,6 +347,7 @@ const ScanQrPage = () => {
|
|
|
|
|
|
const handleDurationSelect = (duration) => {
|
|
|
setSelectedDuration(duration);
|
|
|
+ console.log(duration);
|
|
|
};
|
|
|
const handleCancel = () => {
|
|
|
setSelectedDuration(null);
|
|
|
@@ -376,15 +367,16 @@ const ScanQrPage = () => {
|
|
|
|
|
|
if (selectedDuration === 'full') {
|
|
|
endTime = new Date(now.getTime() + 2 * 60 * 60 * 1000); // 2 hours for "充滿停機"
|
|
|
- fee = 280;
|
|
|
+ fee = planMap.full.fee;
|
|
|
totalPower = 0; // Set to 0 for "充滿停機"
|
|
|
} else {
|
|
|
const durationInMinutes = parseInt(selectedDuration);
|
|
|
endTime = new Date(now.getTime() + durationInMinutes * 60 * 1000);
|
|
|
+ console.log('endTime', endTime);
|
|
|
fee = planMap[selectedDuration].fee;
|
|
|
totalPower = durationInMinutes; // Use the actual duration for other cases
|
|
|
}
|
|
|
-
|
|
|
+ setTotalFee(fee);
|
|
|
const dataForSubmission = {
|
|
|
stationID: '2405311022116801000',
|
|
|
connector: scannedResult,
|
|
|
@@ -403,9 +395,264 @@ const ScanQrPage = () => {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+ //below commented is the original WORKING startCharging, if i fucked up, return back to using this!!!
|
|
|
+
|
|
|
+ // const startCharging = async (dataForSubmission) => {
|
|
|
+ // try {
|
|
|
+ // const wallet = await walletService.getWalletBalance();
|
|
|
+ // console.log('wallet in startCharging in scanQrPage', wallet);
|
|
|
+
|
|
|
+ // const response = await walletService.submitPayment(
|
|
|
+ // dataForSubmission.stationID,
|
|
|
+ // dataForSubmission.connector,
|
|
|
+ // dataForSubmission.user,
|
|
|
+ // dataForSubmission.book_time,
|
|
|
+ // dataForSubmission.end_time,
|
|
|
+ // dataForSubmission.total_power,
|
|
|
+ // dataForSubmission.total_fee,
|
|
|
+ // dataForSubmission.promotion_code,
|
|
|
+ // dataForSubmission.car,
|
|
|
+ // dataForSubmission.type,
|
|
|
+ // dataForSubmission.is_ic_call
|
|
|
+ // );
|
|
|
+ // if (response.status === 200 || response.status === 201) {
|
|
|
+ // setSelectedDuration(null);
|
|
|
+ // console.log('Charging started from startCharging', response);
|
|
|
+ // setIsConfirmLoading(false);
|
|
|
+ // // Set a flag in AsyncStorage to indicate charging has started
|
|
|
+
|
|
|
+ // await AsyncStorage.setItem('chargingStarted', 'true');
|
|
|
+
|
|
|
+ // Alert.alert('啟動成功', '請稍後等待頁面自動跳轉至充電介面', [
|
|
|
+ // {
|
|
|
+ // text: 'OK',
|
|
|
+ // onPress: async () => {
|
|
|
+ // setModalVisible(false);
|
|
|
+ // setLoading(true);
|
|
|
+
|
|
|
+ // // Wait for 2 seconds
|
|
|
+ // await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
|
+
|
|
|
+ // // Hide loading spinner and navigate
|
|
|
+ // setLoading(false);
|
|
|
+
|
|
|
+ // router.push('(auth)/(tabs)/(charging)/chargingPage');
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // ]);
|
|
|
+
|
|
|
+ // // Start the navigation attempt loop
|
|
|
+ // // startNavigationAttempts();
|
|
|
+ // } else if (response.status === 400) {
|
|
|
+ // console.log('400 error in paymentSummaryPageComponent');
|
|
|
+ // Alert.alert('餘額不足', '您的餘額不足,請充值後再試。');
|
|
|
+ // } else {
|
|
|
+ // console.log('Failed to start charging:', response);
|
|
|
+ // Alert.alert('掃描失敗 請稍後再試。', response);
|
|
|
+ // }
|
|
|
+ // } catch (error) {
|
|
|
+ // console.log('Failed to start chasssssssrging:', error);
|
|
|
+ // }
|
|
|
+ // };
|
|
|
+
|
|
|
+ //below is the new flow for startCharging.
|
|
|
+
|
|
|
+ // 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;
|
|
|
+ // });
|
|
|
+
|
|
|
+ // return () => {
|
|
|
+ // subscription.remove();
|
|
|
+ // };
|
|
|
+ // }, [outTradeNo, isExpectingPayment]);
|
|
|
+
|
|
|
+ //check payment status
|
|
|
+
|
|
|
+ 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;
|
|
|
+ });
|
|
|
+
|
|
|
+ return () => {
|
|
|
+ subscription.remove();
|
|
|
+ };
|
|
|
+ }, [outTradeNo, isExpectingPayment]);
|
|
|
+
|
|
|
+ const checkPaymentStatus = async () => {
|
|
|
+ try {
|
|
|
+ console.log('outTradeNo in scanQR Page checkpaymentstatus ', outTradeNo);
|
|
|
+ const result = await walletService.checkPaymentStatus(outTradeNo);
|
|
|
+ setPaymentStatus(result);
|
|
|
+ console.log('checkPaymentStatus from scan QR checkpaymentStatus', result);
|
|
|
+
|
|
|
+ if (result && !result.some((item) => item.errmsg?.includes('處理中'))) {
|
|
|
+ // Payment successful
|
|
|
+ console.log('totalFee', totalFee);
|
|
|
+ Alert.alert('付款已成功', `你已成功增值HKD $${totalFee}。請重新掃描去啟動充電槍。`, [
|
|
|
+ {
|
|
|
+ text: '確認',
|
|
|
+ onPress: async () => {
|
|
|
+ setModalVisible(false);
|
|
|
+ router.dismiss();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ]);
|
|
|
+ } else {
|
|
|
+ Alert.alert('付款失敗', '請再試一次。', [
|
|
|
+ {
|
|
|
+ text: '確定',
|
|
|
+ onPress: () => {
|
|
|
+ setModalVisible(false);
|
|
|
+ router.dismiss();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+ 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.');
|
|
|
+ }
|
|
|
+ };
|
|
|
+ function formatTime(utcTimeString) {
|
|
|
+ // Parse the UTC time string
|
|
|
+ const date = new Date(utcTimeString);
|
|
|
+
|
|
|
+ // Add 8 hours
|
|
|
+ date.setHours(date.getHours());
|
|
|
+
|
|
|
+ // 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');
|
|
|
+
|
|
|
+ // Return the formatted string
|
|
|
+ return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
|
+ }
|
|
|
+
|
|
|
+ const oneTimeCharging = async (inputAmount) => {
|
|
|
+ try {
|
|
|
+ const response = await walletService.getOutTradeNo();
|
|
|
+ console.log('outtradeno in oneTimeCharging', response);
|
|
|
+ if (response) {
|
|
|
+ setOutTradeNo(response);
|
|
|
+ setIsExpectingPayment(true);
|
|
|
+ paymentInitiatedTime.current = new Date().getTime();
|
|
|
+ const now = new Date();
|
|
|
+ const formattedTime = formatTime(now);
|
|
|
+ console.log('formattedTime in oneTimeCharging', formattedTime);
|
|
|
+
|
|
|
+ let amount = inputAmount * 100;
|
|
|
+ console.log('amount in scanqr oneTimeCharging', amount);
|
|
|
+ const origin = 'https://openapi-hk.qfapi.com/checkstand/#/?';
|
|
|
+ const obj = {
|
|
|
+ appcode: '6937EF25DF6D4FA78BB2285441BC05E9',
|
|
|
+ goods_name: 'Crazy Charge 錢包增值',
|
|
|
+ out_trade_no: response,
|
|
|
+ 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
|
|
|
+ };
|
|
|
+
|
|
|
+ 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 = '8F59E31F6ADF4D2894365F2BB6D2FF2C';
|
|
|
+ const params = paramStringify(obj);
|
|
|
+ const sign = sha256(`${params}${api_key}`).toString();
|
|
|
+ const url = `${origin}${paramStringify(obj, true)}&sign=${sign}`;
|
|
|
+
|
|
|
+ try {
|
|
|
+ console.log(url);
|
|
|
+ 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', '一次性付款失敗,請稍後再試');
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ console.log('nasdasdasdsdfgo');
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.log(error);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
const startCharging = async (dataForSubmission) => {
|
|
|
try {
|
|
|
- console.log('dataForSubmission', dataForSubmission);
|
|
|
+ const wallet = await walletService.getWalletBalance();
|
|
|
+ console.log('wallet in startCharging in scanQrPage', wallet);
|
|
|
+ oneTimeCharging(dataForSubmission.total_fee);
|
|
|
+
|
|
|
+ if (wallet < dataForSubmission.total_fee) {
|
|
|
+ oneTimeCharging(dataForSubmission.total_fee);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
const response = await walletService.submitPayment(
|
|
|
dataForSubmission.stationID,
|
|
|
dataForSubmission.connector,
|
|
|
@@ -419,7 +666,8 @@ const ScanQrPage = () => {
|
|
|
dataForSubmission.type,
|
|
|
dataForSubmission.is_ic_call
|
|
|
);
|
|
|
- if (response) {
|
|
|
+ if (response.status === 200 || response.status === 201) {
|
|
|
+ setSelectedDuration(null);
|
|
|
console.log('Charging started from startCharging', response);
|
|
|
setIsConfirmLoading(false);
|
|
|
// Set a flag in AsyncStorage to indicate charging has started
|
|
|
@@ -446,6 +694,9 @@ const ScanQrPage = () => {
|
|
|
|
|
|
// Start the navigation attempt loop
|
|
|
// startNavigationAttempts();
|
|
|
+ } else if (response.status === 400) {
|
|
|
+ console.log('400 error in paymentSummaryPageComponent');
|
|
|
+ Alert.alert('餘額不足', '您的餘額不足,請充值後再試。');
|
|
|
} else {
|
|
|
console.log('Failed to start charging:', response);
|
|
|
Alert.alert('掃描失敗 請稍後再試。', response);
|
|
|
@@ -489,9 +740,138 @@ const ScanQrPage = () => {
|
|
|
// setTimeout(attemptNavigation, 15000);
|
|
|
// };
|
|
|
|
|
|
+ // return (
|
|
|
+ // <View style={styles.container} ref={viewRef}>
|
|
|
+ // {loading ? (
|
|
|
+ // <View className="flex-1 items-center justify-center">
|
|
|
+ // <ActivityIndicator />
|
|
|
+ // </View>
|
|
|
+ // ) : (
|
|
|
+ // <CameraView
|
|
|
+ // style={styles.camera}
|
|
|
+ // facing="back"
|
|
|
+ // barcodeScannerSettings={{
|
|
|
+ // barcodeTypes: ['qr']
|
|
|
+ // }}
|
|
|
+ // onBarcodeScanned={scanned ? undefined : handleBarCodeScanned}
|
|
|
+ // responsiveOrientationWhenOrientationLocked={true}
|
|
|
+ // >
|
|
|
+ // <View style={styles.overlay}>
|
|
|
+ // <View style={styles.topOverlay}>
|
|
|
+ // {/* <ChooseCar
|
|
|
+ // carData={carData}
|
|
|
+ // loading={loading}
|
|
|
+ // selectedCar={selectedCar}
|
|
|
+ // setSelectedCar={setSelectedCar}
|
|
|
+ // /> */}
|
|
|
+ // <Pressable
|
|
|
+ // // style={styles.closeButton}
|
|
|
+ // className="absolute top-20 left-10 z-10 "
|
|
|
+ // onPress={() => {
|
|
|
+ // if (router.canGoBack()) {
|
|
|
+ // router.back();
|
|
|
+ // } else {
|
|
|
+ // router.push('/mainPage');
|
|
|
+ // }
|
|
|
+ // }}
|
|
|
+ // >
|
|
|
+ // <CrossLogoWhiteSvg />
|
|
|
+ // </Pressable>
|
|
|
+ // </View>
|
|
|
+ // <View style={styles.centerRow}>
|
|
|
+ // <View style={styles.leftOverlay}></View>
|
|
|
+ // <View style={styles.transparentArea}></View>
|
|
|
+ // <View style={styles.rightOverlay} />
|
|
|
+ // </View>
|
|
|
+ // <View className="items-center justify-between" style={styles.bottomOverlay}>
|
|
|
+ // <View>
|
|
|
+ // <Text className="text-white text-lg font-bold mt-2 text-center">
|
|
|
+ // 請掃瞄充電座上的二維碼
|
|
|
+ // </Text>
|
|
|
+ // </View>
|
|
|
+ // <View className="flex-row space-x-2 items-center ">
|
|
|
+ // <QuestionSvg />
|
|
|
+
|
|
|
+ // <Pressable onPress={() => router.push('assistancePage')}>
|
|
|
+ // <Text className="text-white text-base">需要協助?</Text>
|
|
|
+ // </Pressable>
|
|
|
+ // </View>
|
|
|
+ // <View />
|
|
|
+ // </View>
|
|
|
+ // </View>
|
|
|
+ // </CameraView>
|
|
|
+ // )}
|
|
|
+ // <Modal isVisible={isModalVisible} backdropOpacity={0.5} animationIn="fadeIn" animationOut="fadeOut">
|
|
|
+ // <View style={styles.modalContent} className="flex flex-col">
|
|
|
+ // <Text className="text-xl font-bold mt-2 text-center">請選擇充電時間</Text>
|
|
|
+ // <Text className="text-base m-2 mb-4 text-center">按鈕呈紅色代表該時段已被他人預約</Text>
|
|
|
+ // <View className="flex flex-row flex-wrap ">
|
|
|
+ // {Object.entries(availableSlots).map(([duration, available]) => (
|
|
|
+ // <NormalButton
|
|
|
+ // key={duration}
|
|
|
+ // title={
|
|
|
+ // duration === 'full' ? (
|
|
|
+ // <Text className={selectedDuration === duration ? 'text-white' : ''}>
|
|
|
+ // 充滿停機
|
|
|
+ // </Text>
|
|
|
+ // ) : (
|
|
|
+ // <Text
|
|
|
+ // className={selectedDuration === duration ? 'text-white' : ''}
|
|
|
+ // >{`${planMap[duration].kWh} 度電 - ${planMap[duration].displayDuration} 分鐘`}</Text>
|
|
|
+ // )
|
|
|
+ // }
|
|
|
+ // onPress={() => handleDurationSelect(duration)}
|
|
|
+ // extendedStyle={[
|
|
|
+ // styles.durationButton,
|
|
|
+ // {
|
|
|
+ // backgroundColor: available
|
|
|
+ // ? selectedDuration === duration
|
|
|
+ // ? '#02677d'
|
|
|
+ // : 'white'
|
|
|
+ // : 'red',
|
|
|
+ // borderColor: available ? 'black' : 'red',
|
|
|
+ // borderWidth: 1
|
|
|
+ // }
|
|
|
+ // ]}
|
|
|
+ // disabled={!available}
|
|
|
+ // />
|
|
|
+ // ))}
|
|
|
+ // </View>
|
|
|
+ // {selectedDuration && (
|
|
|
+ // <NormalButton
|
|
|
+ // title={
|
|
|
+ // isConfirmLoading ? (
|
|
|
+ // <ActivityIndicator color="white" />
|
|
|
+ // ) : (
|
|
|
+ // <Text className="text-white">確認</Text>
|
|
|
+ // )
|
|
|
+ // }
|
|
|
+ // onPress={handleConfirm}
|
|
|
+ // extendedStyle={styles.confirmButton}
|
|
|
+ // />
|
|
|
+ // )}
|
|
|
+ // <NormalButton
|
|
|
+ // title={<Text className="">取消</Text>}
|
|
|
+ // onPress={handleCancel}
|
|
|
+ // extendedStyle={styles.cancelButton}
|
|
|
+ // />
|
|
|
+ // </View>
|
|
|
+ // </Modal>
|
|
|
+ // </View>
|
|
|
+ // );
|
|
|
+
|
|
|
return (
|
|
|
<View style={styles.container} ref={viewRef}>
|
|
|
- {loading ? (
|
|
|
+ {!permission ? (
|
|
|
+ <View />
|
|
|
+ ) : !permission.granted ? (
|
|
|
+ <View className="flex-1 justify-center items-center">
|
|
|
+ <Text style={{ textAlign: 'center' }}>
|
|
|
+ 我們需要相機權限來掃描機器上的二維碼,以便識別並啟動充電機器。我們不會儲存或共享任何掃描到的資訊。
|
|
|
+ 請前往設定開啟相機權限
|
|
|
+ </Text>
|
|
|
+ </View>
|
|
|
+ ) : loading ? (
|
|
|
<View className="flex-1 items-center justify-center">
|
|
|
<ActivityIndicator />
|
|
|
</View>
|
|
|
@@ -507,14 +887,7 @@ const ScanQrPage = () => {
|
|
|
>
|
|
|
<View style={styles.overlay}>
|
|
|
<View style={styles.topOverlay}>
|
|
|
- {/* <ChooseCar
|
|
|
- carData={carData}
|
|
|
- loading={loading}
|
|
|
- selectedCar={selectedCar}
|
|
|
- setSelectedCar={setSelectedCar}
|
|
|
- /> */}
|
|
|
<Pressable
|
|
|
- // style={styles.closeButton}
|
|
|
className="absolute top-20 left-10 z-10 "
|
|
|
onPress={() => {
|
|
|
if (router.canGoBack()) {
|