import { CameraView, useCameraPermissions } from 'expo-camera';
import { useEffect, useRef, useState } from 'react';
import {
ActivityIndicator,
Alert,
Dimensions,
Pressable,
ScrollView,
StyleSheet,
Text,
Vibration,
View
} from 'react-native';
import ChooseCarForChargingRow from '../../../../component/global/chooseCarForChargingRow';
import { CrossLogoWhiteSvg, QuestionSvg } from '../../../../component/global/SVG';
import { router } from 'expo-router';
import { chargeStationService } from '../../../../service/chargeStationService';
import { authenticationService } from '../../../../service/authService';
import { walletService } from '../../../../service/walletService';
import useUserInfoStore from '../../../../providers/userinfo_store';
const { width: screenWidth, height: screenHeight } = Dimensions.get('window');
const ChooseCar = ({ carData, loading, selectedCar, setSelectedCar }) => {
const isLargeScreen = screenHeight >= 800;
const defaultImageUrl = require('../../../../assets/car1.png');
return (
{loading ? (
) : (
{
if (router.canGoBack()) {
router.back();
} else {
router.replace('mainPage');
}
}}
>
選擇充電車輛
{carData.map((car, index) => (
{
setSelectedCar(car.id);
console.log(car.id);
}}
isSelected={selectedCar === car.id}
// imageUrl={image}
VehicleName={car.name}
isDefault={car.isDefault}
/>
))}
)}
);
};
//reminder: scan qr code page, ic call should be false
const ScanQrPage = () => {
const { userID, setUserID } = useUserInfoStore();
// State declarations
const [permission, requestPermission] = useCameraPermissions();
const [scanned, setScanned] = useState(false);
const viewRef = useRef(null);
const [scannedResult, setScannedResult] = useState('');
const [selectedCar, setSelectedCar] = useState('');
const now = new Date();
const [loading, setLoading] = useState(true);
const [loading2, setLoading2] = useState(false);
const [loading3, setLoading3] = useState(false);
const [carData, setCarData] = useState([]);
// Effect for requesting camera permissions
useEffect(() => {
(async () => {
const { status } = await requestPermission();
if (status !== 'granted') {
alert(
'我們需要相機權限來掃描機器上的二維碼,以便識別並啟動充電機器。我們不會儲存或共享任何掃描到的資訊。 請前往設定開啟相機權限'
);
}
})();
}, []);
// Effect for fetching user's cars
useEffect(() => {
const fetchAllCars = async () => {
try {
const response = await chargeStationService.getUserCars();
if (response) {
// console.log(response.data);
const carTypes = response.data.map((item: any) => ({
id: item.id,
name: item.car_type.name,
image: item.car_type.type_image_url
}));
console.log('carTypes', carTypes);
// console.log('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', carTypes);
let updatedCarTypes = [...carTypes];
for (let i = 0; i
< carTypes.length; i++) { const car=updatedCarTypes[i]; const imageUrl=await
chargeStationService.getProcessedImageUrl(car.image); updatedCarTypes[i]={ ...car, image: imageUrl }; }
setCarData(updatedCarTypes); console.log('updatedCarTypes', updatedCarTypes); return true; } } catch (error) {
console.log(error); } finally { setLoading(false); } }; fetchAllCars(); }, []); if (!permission) { return ;
}
if (!permission.granted) {
return (
我們需要相機權限來掃描機器上的二維碼,以便識別並啟動充電機器。我們不會儲存或共享任何掃描到的資訊。
請前往設定開啟相機權限
);
}
// Function to handle barcode scanning
const handleBarCodeScanned = async ({ bounds, data, type }: { bounds: any; data: any; type: any }) => {
const { origin, size } = bounds;
// Calculate the size of the square transparent area
const transparentAreaSize = Math.min(screenWidth * 0.6, screenHeight * 0.3);
const transparentAreaX = (screenWidth - transparentAreaSize) / 2;
const transparentAreaY = (screenHeight - transparentAreaSize) / 2;
// Check if the barcode is within the transparent area
if (
origin.x >= transparentAreaX &&
origin.y >= transparentAreaY &&
origin.x + size.width <= transparentAreaX + transparentAreaSize && origin.y + size.height <=transparentAreaY +
transparentAreaSize ) { setScanned(true); setScannedResult(data); Vibration.vibrate(100); console.log(` type:
${type} data: ${data} typeofData ${typeof data}`); try { const response=await
chargeStationService.getTodayReservation(); if (response) { const now=new Date(); const
onlyThisConnector=response.filter( (reservation: any)=> reservation.connector.ConnectorID === data
);
onlyThisConnector.sort((a: any, b: any) => {
const timeA = new Date(a.book_time).getTime();
const timeB = new Date(b.book_time).getTime();
return timeA - timeB;
});
let previousReservation = null;
let upcomingReservation = null;
for (let i = 0; i < onlyThisConnector.length; i++) { const reservationTime=new
Date(onlyThisConnector[i].book_time).getTime(); if (reservationTime <=now.getTime()) {
previousReservation=onlyThisConnector[i]; } else { upcomingReservation=onlyThisConnector[i]; break; } } const
relevantReservations=[previousReservation || null, upcomingReservation || null]; console.log('Relevant
reservations:', relevantReservations); const getNearestSlot=(date: Date)=> {
const minutes = date.getMinutes();
const nearestSlot = new Date(date);
nearestSlot.setMinutes(minutes < 30 ? 0 : 30); nearestSlot.setSeconds(0); nearestSlot.setMilliseconds(0); return
nearestSlot; }; const currentSlot=getNearestSlot(now); const nextSlot=new Date(currentSlot.getTime() + 30 *
60 * 1000); const AreOrdersAdjacentToNow=relevantReservations.map((reservation, index)=> {
if (!reservation) return false;
const reservationTime = new Date(reservation.book_time);
return index === 0
? reservationTime.getTime() === currentSlot.getTime()
: reservationTime.getTime() === nextSlot.getTime();
});
console.log('AreOrdersAdjacentToNow:', AreOrdersAdjacentToNow);
if (!AreOrdersAdjacentToNow[0] && !AreOrdersAdjacentToNow[1]) {
console.log('Charging machine is available. Starting charging process...');
startCharging(data);
} else if (AreOrdersAdjacentToNow[0]) {
const previousReservation = relevantReservations[0];
if (previousReservation && previousReservation.user.id === userID) {
const reservationTime = new Date(previousReservation.book_time);
const timeDifference = now.getTime() - reservationTime.getTime();
const minutesDifference = timeDifference / (1000 * 60);
if (minutesDifference <= 15) { console.log('User arrived within 15 minutes of their reservation.');
startCharging(data); } else { console.log('User arrived more than 15 minutes late for their
reservation.'); if (!AreOrdersAdjacentToNow[1]) { console.log('Next slot is available. Allowing charging
despite late arrival.'); startCharging(data); } else { Alert.alert( '預約已過期'
, '您的預約時間已經過期,且下一個時段已被預約。請重新預約。' ); console.log('Next slot is not available. Charging not allowed.'); }
} } else { Alert.alert('無法使用', '此充電槍已經被預約,請選擇其他位置' ); } } else if (AreOrdersAdjacentToNow[1]) { const
upcomingReservation=relevantReservations[1]; if (upcomingReservation &&
upcomingReservation.user.id===userID) { const minutesUntilReservation=(new
Date(upcomingReservation.book_time).getTime() - now.getTime()) / (1000 * 60); if
(minutesUntilReservation <=5) { console.log('User arrived slightly early for their upcoming
reservation.'); startCharging(data); } else { Alert.alert( '預約時間未到' , `您的預約時間還有
${Math.round(minutesUntilReservation)} 分鐘開始。請稍後再試。` ); } } else {
Alert.alert('已被預約', '此充電槍已被其他用戶預約。請選擇其他位置。' ); } } else { Alert.alert('無法使用', '此充電槍目前無法使用。請選擇其他位置或稍後再試。'
); } } else { console.log('No response from getTodayReservation'); Alert.alert('系統錯誤', '無法獲取預約信息。請稍後再試。'
); } } catch (error) { console.error("Error fetching today's reservations:", error);
Alert.alert('系統錯誤', '發生未知錯誤。請稍後再試。' ); } setTimeout(()=> {
setScanned(false);
}, 2000);
}
};
//prepare data for submission
const dataForSubmission = {
stationID: '2405311022116801000',
connector: scannedResult,
user: userID,
book_time: now,
end_time: now,
total_power: 0,
total_fee: 0,
promotion_code: '',
car: selectedCar,
type: 'walking',
is_ic_call: false
};
const startCharging = async (scanResult: string) => {
try {
if (selectedCar === '') {
Alert.alert('請選擇車輛');
return;
}
const response = await walletService.submitPayment(
dataForSubmission.stationID,
scanResult,
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) {
console.log('Charging started from startCharging', response);
router.push('(auth)/(tabs)/(charging)/chargingPage');
} else {
console.log('Failed to start chargi12312312ng:', response);
Alert.alert('掃描失敗 請稍後再試。', response);
}
} catch (error) {
console.log('Failed to start charging:', error);
}
};
return (
{loading ? (
) : (
請選擇充電車輛{'\n'}及掃瞄充電座上的二維碼
router.push('assistancePage')}>
需要協助?
)}
);
};
const styles = StyleSheet.create({
container: {
flex: 1
},
camera: {
flex: 1
},
overlay: {
flex: 1
},
topOverlay: {
flex: 35,
alignItems: 'center',
backgroundColor: 'rgba(0,0,0,0.5)'
},
centerRow: {
flex: 30,
flexDirection: 'row'
},
leftOverlay: {
flex: 20,
backgroundColor: 'rgba(0,0,0,0.5)'
},
transparentArea: {
flex: 60,
aspectRatio: 1,
position: 'relative'
},
rightOverlay: {
flex: 20,
backgroundColor: 'rgba(0,0,0,0.5)'
},
bottomOverlay: {
flex: 35,
backgroundColor: 'rgba(0,0,0,0.5)'
}
});
export default ScanQrPage;