|
|
@@ -17,7 +17,7 @@ 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 }) => {
|
|
|
@@ -55,7 +55,7 @@ const ChooseCar = ({ carData, loading, selectedCar, setSelectedCar }) => {
|
|
|
<ActivityIndicator color="#34657b" />
|
|
|
</View>
|
|
|
) : (
|
|
|
- <View className="w-full bg-[#000000B3]">
|
|
|
+ <View className="w-screen bg-[#000000B3]">
|
|
|
<View className="flex-row items-center justify-between mx-[5%] ">
|
|
|
<Pressable
|
|
|
className="pt-4 "
|
|
|
@@ -107,16 +107,18 @@ const ChooseCar = ({ carData, loading, selectedCar, setSelectedCar }) => {
|
|
|
);
|
|
|
};
|
|
|
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 [userID, setUserID] = useState<string>('');
|
|
|
+
|
|
|
const now = new Date();
|
|
|
- const [loading, setLoading] = useState(false);
|
|
|
+ const [loading, setLoading] = useState(true);
|
|
|
const [loading2, setLoading2] = useState(false);
|
|
|
+ const [loading3, setLoading3] = useState(false);
|
|
|
const [carData, setCarData] = useState([]);
|
|
|
|
|
|
// Effect for requesting camera permissions
|
|
|
@@ -132,7 +134,6 @@ const ScanQrPage = () => {
|
|
|
// Effect for fetching user's cars
|
|
|
useEffect(() => {
|
|
|
const fetchAllCars = async () => {
|
|
|
- setLoading(true);
|
|
|
try {
|
|
|
const response = await chargeStationService.getUserCars();
|
|
|
if (response) {
|
|
|
@@ -142,6 +143,7 @@ const ScanQrPage = () => {
|
|
|
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++) {
|
|
|
@@ -153,6 +155,7 @@ const ScanQrPage = () => {
|
|
|
};
|
|
|
}
|
|
|
setCarData(updatedCarTypes);
|
|
|
+ console.log('updatedCarTypes', updatedCarTypes);
|
|
|
return true;
|
|
|
}
|
|
|
} catch (error) {
|
|
|
@@ -164,23 +167,6 @@ const ScanQrPage = () => {
|
|
|
fetchAllCars();
|
|
|
}, []);
|
|
|
|
|
|
- // Effect for fetching user ID
|
|
|
- useEffect(() => {
|
|
|
- const fetchID = async () => {
|
|
|
- try {
|
|
|
- const response = await authenticationService.getUserInfo();
|
|
|
- if (response) {
|
|
|
- setUserID(response.data.id);
|
|
|
- } else {
|
|
|
- console.log('fail to set user ID');
|
|
|
- }
|
|
|
- } catch (error) {
|
|
|
- console.log(error);
|
|
|
- }
|
|
|
- };
|
|
|
- fetchID();
|
|
|
- }, []);
|
|
|
-
|
|
|
if (!permission) {
|
|
|
return <View />;
|
|
|
}
|
|
|
@@ -193,34 +179,8 @@ const ScanQrPage = () => {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
- // // Function to handle barcode scanning
|
|
|
- // const handleBarCodeScanned = ({ 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}`);
|
|
|
- // startCharging(data);
|
|
|
- // setTimeout(() => {
|
|
|
- // setScanned(false);
|
|
|
- // }, 2000);
|
|
|
- // }
|
|
|
- // };
|
|
|
-
|
|
|
// Function to handle barcode scanning
|
|
|
- const handleBarCodeScanned = ({ bounds, data, type }: { bounds: any; data: any; type: any }) => {
|
|
|
+ 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);
|
|
|
@@ -238,90 +198,126 @@ const ScanQrPage = () => {
|
|
|
setScannedResult(data);
|
|
|
Vibration.vibrate(100);
|
|
|
console.log(` type: ${type} data: ${data} typeofData ${typeof data}`);
|
|
|
- //HERE I will not be startCharging, I will call a function to check
|
|
|
- startCharging(data);
|
|
|
- setTimeout(() => {
|
|
|
- setScanned(false);
|
|
|
- }, 2000);
|
|
|
- }
|
|
|
- };
|
|
|
- //WAIT FOR KUN TO CREATE ANOTHER API,
|
|
|
- //USE THE NEW API FOR SCAN QR CODE FUNCTIONALITY
|
|
|
- // ***********************************************************
|
|
|
- // **************************************************************
|
|
|
- // **************************************************************
|
|
|
- // **************************************************************
|
|
|
- // **************************************************************
|
|
|
- // **************************************************************
|
|
|
- // **************************************************************
|
|
|
- // **************************************************************
|
|
|
- const checkCurrentReservation = async () => {
|
|
|
- const now = new Date();
|
|
|
- try {
|
|
|
- console.log('i am checking current reservation');
|
|
|
- const response = await chargeStationService.fetchReservationHistories();
|
|
|
- if (response) {
|
|
|
- //check if any reservation is within 15 minutes
|
|
|
- console.log('response of checkCurrentReservation', response);
|
|
|
- const filteredResponse = response.filter((r) => {
|
|
|
- const bookTime = new Date(r.book_time);
|
|
|
- const fifteenMinutesAfterBookTime = new Date(bookTime.getTime() + 15 * 60 * 1000);
|
|
|
- const isWithin15MinutesAndStatus6 =
|
|
|
- now > bookTime && now <= fifteenMinutesAfterBookTime && r.status.id === '6';
|
|
|
- return isWithin15MinutesAndStatus6;
|
|
|
- });
|
|
|
- if (filteredResponse.length > 0) {
|
|
|
- console.log('there is a reservation within 15 minutes');
|
|
|
- return filteredResponse;
|
|
|
- }
|
|
|
- }
|
|
|
- //meaning no reservation within 15 minutes
|
|
|
- else {
|
|
|
- console.log('no reservation within 15 minutes');
|
|
|
- return false;
|
|
|
- }
|
|
|
- } catch (error) {
|
|
|
- console.log(error);
|
|
|
- }
|
|
|
- };
|
|
|
|
|
|
- const checkQrCode = async (data: string) => {
|
|
|
- setLoading2(true);
|
|
|
- const connectorID = data;
|
|
|
- try {
|
|
|
- const response = await checkCurrentReservation();
|
|
|
- if (response) {
|
|
|
- console.log('checking if scan code is for this reservation, from checkQrCode', response);
|
|
|
- //if there is a reservation within 15 minutes
|
|
|
- const checkIfScanCodeIsForThisReservation = response.connector.id === data;
|
|
|
- if (checkIfScanCodeIsForThisReservation) {
|
|
|
- startCharging(data);
|
|
|
- return true;
|
|
|
- } else {
|
|
|
- console.log(
|
|
|
- 'The user indeed has a valid reservation, but the reservation is not for this charging machine.'
|
|
|
+ try {
|
|
|
+ const response = await chargeStationService.getTodayReservation();
|
|
|
+ if (response) {
|
|
|
+ const now = new Date();
|
|
|
+
|
|
|
+ const onlyThisConnector = response.filter(
|
|
|
+ (reservation: any) => reservation.connector.ConnectorID === data
|
|
|
);
|
|
|
- Alert.alert('您預約了另一座充電座\n請前往正確的充電座進行充電。');
|
|
|
- return false;
|
|
|
+
|
|
|
+ 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('系統錯誤', '無法獲取預約信息。請稍後再試。');
|
|
|
}
|
|
|
- } else {
|
|
|
- //if there is no reservation within 15 minutes
|
|
|
- //meaing these are walk in clients wanting to charge
|
|
|
- //first, i have to check the current time,
|
|
|
- //if the availability of current time slot is not available then i return alert
|
|
|
+ } catch (error) {
|
|
|
+ console.error("Error fetching today's reservations:", error);
|
|
|
+ Alert.alert('系統錯誤', '發生未知錯誤。請稍後再試。');
|
|
|
}
|
|
|
- } catch (error) {
|
|
|
- console.log(error);
|
|
|
+
|
|
|
+ setTimeout(() => {
|
|
|
+ setScanned(false);
|
|
|
+ }, 2000);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
- // **************************************************************
|
|
|
- // **************************************************************
|
|
|
- // **************************************************************
|
|
|
- // **************************************************************
|
|
|
- // **************************************************************
|
|
|
- // **************************************************************
|
|
|
- // **************************************************************
|
|
|
//prepare data for submission
|
|
|
const dataForSubmission = {
|
|
|
stationID: '2405311022116801000',
|
|
|
@@ -333,7 +329,8 @@ const ScanQrPage = () => {
|
|
|
total_fee: 0,
|
|
|
promotion_code: '',
|
|
|
car: selectedCar,
|
|
|
- type: 'walking'
|
|
|
+ type: 'walking',
|
|
|
+ is_ic_call: false
|
|
|
};
|
|
|
|
|
|
const startCharging = async (scanResult: string) => {
|
|
|
@@ -353,7 +350,8 @@ const ScanQrPage = () => {
|
|
|
dataForSubmission.total_fee,
|
|
|
dataForSubmission.promotion_code,
|
|
|
dataForSubmission.car,
|
|
|
- dataForSubmission.type
|
|
|
+ dataForSubmission.type,
|
|
|
+ dataForSubmission.is_ic_call
|
|
|
);
|
|
|
|
|
|
if (response) {
|
|
|
@@ -367,60 +365,6 @@ const ScanQrPage = () => {
|
|
|
console.log('Failed to start charging:', error);
|
|
|
}
|
|
|
};
|
|
|
- const abc = new Date();
|
|
|
-
|
|
|
- async function checkIfConnectorIsAvailable(stationID: string) {
|
|
|
- try {
|
|
|
- const apiResponse = await chargeStationService.fetchSpecificChargeStation(stationID);
|
|
|
- if (apiResponse) {
|
|
|
- console.log('apiResponse', apiResponse);
|
|
|
- const inputDate = new Date();
|
|
|
- const formattedDate =
|
|
|
- (inputDate.getMonth() + 1).toString().padStart(2, '0') +
|
|
|
- '/' +
|
|
|
- inputDate.getDate().toString().padStart(2, '0');
|
|
|
-
|
|
|
- // Get the hours and minutes
|
|
|
- const hours = inputDate.getHours();
|
|
|
- const minutes = inputDate.getMinutes();
|
|
|
-
|
|
|
- // Round down to the nearest 30-minute slot
|
|
|
- const slotStart = `${hours.toString().padStart(2, '0')}:${minutes < 30 ? '00' : '30'}`;
|
|
|
- console.log('slotStart', slotStart);
|
|
|
-
|
|
|
- const findSlot = (date, start) => {
|
|
|
- const dayData = apiResponse.find((day) => day.date === date);
|
|
|
- if (!dayData) return null;
|
|
|
-
|
|
|
- return dayData.range.find((slot) => slot.start === start);
|
|
|
- };
|
|
|
-
|
|
|
- const currentSlot = findSlot(formattedDate, slotStart);
|
|
|
- console.log('currentSlot', currentSlot);
|
|
|
-
|
|
|
- let nextSlotStart;
|
|
|
- if (slotStart.endsWith('30')) {
|
|
|
- nextSlotStart = `${(hours + 1).toString().padStart(2, '0')}:00`;
|
|
|
- } else {
|
|
|
- nextSlotStart = `${hours.toString().padStart(2, '0')}:30`;
|
|
|
- }
|
|
|
- const nextSlot = findSlot(formattedDate, nextSlotStart);
|
|
|
- console.log('nextSlot', nextSlot);
|
|
|
- return {
|
|
|
- currentSlot,
|
|
|
- nextSlot
|
|
|
- };
|
|
|
- } else {
|
|
|
- console.log('no response from fetchSpecificChargeStation in scanQRcode Page');
|
|
|
- return false;
|
|
|
- }
|
|
|
- } catch (error) {
|
|
|
- console.log(error);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- const adbc = checkIfConnectorIsAvailable('2405311022116801000');
|
|
|
- console.log(adbc);
|
|
|
|
|
|
return (
|
|
|
<View style={styles.container} ref={viewRef}>
|