| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192 |
- import {
- View,
- Text,
- ScrollView,
- Pressable,
- StyleSheet,
- Image,
- Dimensions,
- ActivityIndicator,
- Platform,
- Linking,
- Alert
- } from 'react-native';
- import { SafeAreaView } from 'react-native-safe-area-context';
- import { router, useLocalSearchParams } from 'expo-router';
- import NormalButton from '../global/normal_button';
- import { CheckMarkLogoSvg, DirectionLogoSvg, PreviousPageBlackSvg } from '../global/SVG';
- import { ChargingStationTabView } from '../global/chargingStationTabView';
- import { useEffect, useState } from 'react';
- import DropdownSelect from '../global/dropdown_select';
- import { chargeStationService } from '../../service/chargeStationService';
- import * as Location from 'expo-location';
- import { calculateDistance } from '../global/distanceCalculator';
- import Modal from 'react-native-modal';
- import useUserInfoStore from '../../providers/userinfo_store';
- interface AccordionItemProps {
- title: string;
- children: React.ReactNode;
- isOpen: boolean;
- onToggle: () => void;
- isSelected: boolean;
- }
- const AccordionItem: React.FC<AccordionItemProps> = ({ title, children, isOpen, onToggle, isSelected }) => (
- <View className={`${isSelected ? 'bg-[#e7f5f8]' : 'bg-white'}`}>
- <View className="mx-[5%]">
- <Pressable onPress={onToggle}>
- <Text className={` pt-2 text-lg ${isSelected ? 'text-[#222222]' : 'text-[#888888] '}}`}>{title}</Text>
- </Pressable>
- {isOpen && <View>{children}</View>}
- </View>
- </View>
- );
- const MakingBookingPageComponent = () => {
- const [isModalVisible, setModalVisible] = useState(false);
- const [routerParams, setRouterParams] = useState(null);
- const [openDrawer, setOpenDrawer] = useState<number | null>(1);
- const [selectedTime, setSelectedTime] = useState<string>('');
- const [availableTimeSlots, setAvailableTimeSlots] = useState<string[]>([]);
- const [selectedDrawer, setSelectedDrawer] = useState<number>(1);
- const [isLoading, setIsLoading] = useState(true);
- const [selectedDate, setSelectedDate] = useState<string>('');
- const toggleDrawer = (index: number) => {
- setOpenDrawer(openDrawer === index ? null : index);
- setSelectedDrawer(index);
- };
- const [defaultCar, setDefaultCar] = useState(null);
- const [isDefaultCarLoading, setIsDefaultCarLoading] = useState(true);
- const [availableDate, setAvailableDate] = useState<string[]>([]);
- const [car, setCar] = useState([]);
- const [selectedCarID, setSelectedCarID] = useState('');
- const [selectedChargingGun, setSelectedChargingGun] = useState('');
- const [chargingBasedOnWatt, setChargingBasedOnWatt] = useState(true);
- const [stopChargingUponBatteryFull, setStopChargingUponBatteryFull] = useState(false);
- const [selectedCar, setSelectedCar] = useState('');
- const [selectedDuration, setSelectedDuration] = useState('');
- const { width: screenWidth, height: screenHeight } = Dimensions.get('window');
- const [price, setPrice] = useState(0);
- const layoutWidth = screenWidth;
- const layoutHeight = screenHeight * 0.32;
- const { userID, setUserID } = useUserInfoStore();
- const [formattedDates, setFormattedDates] = useState([]);
- const params = useLocalSearchParams();
- const chargeStationID = params.chargeStationID as string;
- const chargeStationName = params.chargeStationName as string;
- const chargeStationAddress = params.chargeStationAddress as string;
- const chargeStationLat = params.chargeStationLat as string;
- const chargeStationLng = params.chargeStationLng as string;
- const [selectedWatt, setSelectedWatt] = useState('');
- const [availableConnectorDropdownOptions, setAvailableConnectorDropdownOptions] = useState([]);
- const [carCapacitance, setCarCapacitance] = useState('');
- const [currentLocation, setCurrentLocation] = useState<Location.LocationObject | null>(null);
- const [distance, setDistance] = useState<string | null>(null);
- const [upcomingReservations, setUpcomingReservation] = useState([]);
- const [carLoadingState, setCarLoadingState] = useState(false);
- const [isDateLoading, setIsDateLoading] = useState(false);
- const [dataResponse, setDataResponse] = useState([]);
- //check for unpaid penalties
- useEffect(() => {
- const checkUnpaidPenalties = async () => {
- try {
- const reservationHistories = await chargeStationService.fetchReservationHistories();
- const unpaidPenalties = reservationHistories.filter(
- (reservation) => reservation.penalty_fee > 0 && reservation.penalty_paid_status === false
- );
- if (unpaidPenalties.length > 0) {
- const mostRecentUnpaidReservation = unpaidPenalties.reduce((mostRecent, current) => {
- return new Date(mostRecent.created_at) > new Date(current.created_at) ? mostRecent : current;
- }, unpaidPenalties[0]);
- Alert.alert(
- '未付罰款',
- '您有未支付的罰款。請先支付罰款後再開始充電。',
- [
- {
- text: '查看詳情',
- onPress: () => {
- // Navigate to a page showing penalty details
- router.push({
- pathname: '(auth)/(tabs)/(home)/penaltyPaymentPage',
- params: {
- book_time: mostRecentUnpaidReservation.book_time,
- end_time: mostRecentUnpaidReservation.end_time,
- actual_end_time: mostRecentUnpaidReservation.actual_end_time,
- penalty_fee: mostRecentUnpaidReservation.penalty_fee,
- format_order_id: mostRecentUnpaidReservation.format_order_id,
- id: mostRecentUnpaidReservation.id,
- stationName:
- mostRecentUnpaidReservation.connector.EquipmentID.StationID.snapshot
- .StationName,
- address:
- mostRecentUnpaidReservation.connector.EquipmentID.StationID.snapshot
- .Address
- }
- });
- }
- },
- {
- text: '返回',
- onPress: () => {
- if (router.canGoBack()) {
- router.back();
- } else {
- router.push('/mainPage');
- }
- }
- }
- ],
- { cancelable: false }
- );
- }
- } catch (error) {
- console.error('Error checking unpaid penalties:', error);
- // Handle the error appropriately (e.g., show an error message to the user)
- }
- };
- checkUnpaidPenalties();
- }, []);
- const handleSendingSize = async (watt) => {
- try {
- setIsLoading(true);
- const wattValue = parseInt(watt.split(' ')[0]);
- console.log('wattValue', wattValue);
- let size: number;
- //make the duration based on watt
- switch (wattValue) {
- case 20:
- size = 25;
- break;
- case 25:
- size = 30;
- break;
- case 30:
- size = 40;
- break;
- case 40:
- size = 45;
- break;
- default:
- console.error('Invalid selectedWatt value');
- return; // Exit the function if selectedWatt is invalid
- }
- const response = await chargeStationService.getReservationWithSize(size);
- if (response) {
- setDataResponse(response);
- // console.log('respoasdasdasdnse', response);
- const uniqueDates = new Set();
- response.forEach((item) => {
- item.timeSlot.forEach((slot) => {
- uniqueDates.add(slot.date);
- });
- });
- const availableDates = Array.from(uniqueDates).sort();
- setAvailableDate(availableDates);
- // console.log('formattedDates', formattedDates);
- } else {
- console.log('No response from getReservationWithSize');
- }
- } catch (error) {
- console.error('Error in handleSendingSize:', error);
- // Handle the error appropriately, maybe show an alert to the user
- } finally {
- setIsLoading(false);
- }
- };
- //get location
- useEffect(() => {
- const getCurrentLocation = async () => {
- let { status } = await Location.requestForegroundPermissionsAsync();
- if (status !== 'granted') {
- console.error('Permission to access location was denied');
- return;
- }
- let location = await Location.getLastKnownPositionAsync({});
- setCurrentLocation(location);
- };
- getCurrentLocation();
- }, []);
- //getDefaultCar
- // useEffect(() => {
- // const fetchDefaultCar = async () => {
- // setIsDefaultCarLoading(true);
- // try {
- // const response = await chargeStationService.getUserDefaultCars();
- // if (response && response.data) {
- // setDefaultCar(response.data.id);
- // setSelectedCarID(response.data.id);
- // setCarCapacitance(response.data.car_type.capacitance);
- // setSelectedCar(response.data.id);
- // console.log('*******', response.data.car_type.capacitance);
- // }
- // } catch (error) {
- // console.log('Error fetching default car:', error);
- // } finally {
- // setIsDefaultCarLoading(false);
- // }
- // };
- // fetchDefaultCar();
- // }, []);
- // const formatDistance = (distanceInMeters: number): string => {
- // if (distanceInMeters < 1000) {
- // return `${Math.round(distanceInMeters)}米`;
- // } else {
- // const distanceInKm = distanceInMeters / 1000;
- // return `${distanceInKm.toFixed(1)}公里`;
- // }
- // };
- // const getUpcomingReservations = (reservations: any, daysAhead = 3) => {
- // const today = new Date();
- // const threeDaysLater = new Date(today);
- // threeDaysLater.setDate(today.getDate() + daysAhead);
- // return reservations
- // .filter((reservation) => {
- // const reservationDate = new Date(reservation.book_time);
- // return reservationDate >= today && reservationDate <= threeDaysLater;
- // })
- // .sort((a, b) => new Date(a.reservationDate) - new Date(b.reservationDate));
- // };
- //USE BELOW to find upcoming reservations, then I filter availableDate and time based on the upcoming ones so user cannot book the same time twice.
- // const formatReservations = (reservations) => {
- // const formattedReservations = {};
- // reservations.forEach((reservation) => {
- // const bookTime = new Date(reservation.book_time);
- // const date = formatDate(bookTime);
- // const time = formatTime(bookTime);
- // if (!formattedReservations[date]) {
- // formattedReservations[date] = [];
- // }
- // formattedReservations[date].push(time);
- // });
- // return Object.entries(formattedReservations).map(([date, times]) => ({
- // date,
- // times
- // }));
- // };
- // const formatDate = (date) => {
- // const month = String(date.getMonth() + 1).padStart(2, '0');
- // const day = String(date.getDate()).padStart(2, '0');
- // return `${month}/${day}`;
- // };
- // const formatTime = (date) => {
- // return date.toTimeString().slice(0, 5);
- // };
- // useEffect(() => {
- // const fetchReservationHistories = async () => {
- // try {
- // const response = await chargeStationService.fetchReservationHistories();
- // if (response) {
- // // console.log('response', response);
- // // console.log('Reservation histories:', response);
- // const upcomingReservations = getUpcomingReservations(response);
- // // console.log('upcomingReservations', upcomingReservations);
- // const formattedReservations = formatReservations(upcomingReservations);
- // // console.log('formattedReservations', formattedReservations);
- // setUpcomingReservation(formattedReservations);
- // }
- // 2;
- // } catch (error) {
- // console.log(error);
- // }
- // };
- // fetchReservationHistories();
- // }, []);
- //USE ABOVE to find upcoming reservations, then I filter availableDate and time based on the upcoming ones so user cannot book the same time twice.
- // useEffect(() => {
- // const getDistance = async () => {
- // if (currentLocation) {
- // try {
- // const distance = await calculateDistance(
- // Number(params.chargeStationLat),
- // Number(params.chargeStationLng),
- // currentLocation
- // );
- // setDistance(formatDistance(distance));
- // } catch (error) {
- // console.error('Error calculating distance:', error);
- // }
- // }
- // };
- // getDistance();
- // }, [params.chargeStationLat, params.chargeStationLng, currentLocation]);
- useEffect(() => {
- const fetchPrice = async () => {
- try {
- const price = await chargeStationService.fetchChargeStationPrice(chargeStationID);
- setPrice(price);
- } catch (error) {
- console.error('Error fetching price:', error);
- }
- };
- fetchPrice();
- }, []);
- // function appendImageUrlToCarResult(carData, updatedVehicles) {
- // return carData.map((car) => {
- // const matchingVehicle = updatedVehicles.find((vehicle) => vehicle.car_type.name === car.car_name);
- // if (matchingVehicle) {
- // return {
- // ...car,
- // type_image_url: matchingVehicle.car_type.type_image_url
- // };
- // }
- // return car;
- // });
- // }
- // useEffect(() => {
- // setCarLoadingState(true);
- // const fetchUserInfoAndCarData = async () => {
- // try {
- // const fetchedUserInfo = await authenticationService.getUserInfo();
- // const userData = fetchedUserInfo?.data;
- // // console.log('userData', userData);
- // if (userData) {
- // setUserID(userData.id);
- // const carData = userData.cars.map((car: any) => ({
- // car_name: car.name,
- // car_capacitance: car.capacitance,
- // car_id: car.id,
- // isDefault: car.id === userData.defaultCar?.id
- // }));
- // // console.log('carDarta', carData);
- // setCar(carData);
- // const carResult = await chargeStationService.getUserCars();
- // let updatedVehicles = [...carResult.data];
- // // console.log('updatedVehiaacles', updatedVehicles);
- // const updatedCarResult = appendImageUrlToCarResult(carData, updatedVehicles);
- // setCar(updatedCarResult);
- // let updatedCarResultWithProcessedUrl = [...updatedCarResult];
- // for (let i = 0; i < updatedCarResultWithProcessedUrl.length; i++) {
- // const car = updatedCarResultWithProcessedUrl[i];
- // const processedUrl = await chargeStationService.getProcessedImageUrl(car.type_image_url);
- // updatedCarResultWithProcessedUrl[i] = {
- // ...car,
- // processedImageUrl: processedUrl
- // };
- // }
- // // console.log(updatedCarResultWithProcessedUrl);
- // setCar(updatedCarResultWithProcessedUrl);
- // }
- // } catch (error) {
- // console.error('Error fetching user info:', error);
- // } finally {
- // setCarLoadingState(false);
- // }
- // };
- // fetchUserInfoAndCarData();
- // }, []);
- // useEffect(() => {
- // const fetchingAvailableTimeSlots = async () => {
- // setIsLoading(true);
- // try {
- // const fetchedTimeSlots = await chargeStationService.fetchAvailableTimeSlots(
- // chargeStationID,
- // selectedDate
- // );
- // const now = new Date();
- // const today = `${String(now.getMonth() + 1).padStart(2, '0')}/${String(now.getDate()).padStart(
- // 2,
- // '0'
- // )}`;
- // let filteredTimeSlots = fetchedTimeSlots;
- // //filter out today's time slots that have already passed
- // if (selectedDate === today) {
- // const currentHours = now.getHours();
- // const currentMinutes = now.getMinutes();
- // filteredTimeSlots = fetchedTimeSlots.filter((time) => {
- // const [hours, minutes] = time.split(':').map(Number);
- // if (hours > currentHours) return true;
- // if (hours === currentHours && minutes > currentMinutes) return true;
- // return false;
- // });
- // }
- // //filter out time slots that are already fully booked
- // const reservedSlotsForDate = upcomingReservations.find((res) => res.date === selectedDate);
- // if (reservedSlotsForDate) {
- // filteredTimeSlots = filteredTimeSlots.filter((time) => !reservedSlotsForDate.times.includes(time));
- // }
- // setAvailableTimeSlots(filteredTimeSlots);
- // } catch (error) {
- // console.error('Error fetching time slots:', error);
- // } finally {
- // setIsLoading(false);
- // }
- // };
- // if (selectedDate) {
- // fetchingAvailableTimeSlots();
- // }
- // }, [selectedDate]);
- // useEffect(() => {
- // const fetchConnectorOptions = async () => {
- // try {
- // const fetchedData = await chargeStationService.fetchSpecificChargeStation(chargeStationID);
- // console.log('fetchedDate', fetchedData);
- // const dateObject = fetchedData.find((item) => item.date === selectedDate);
- // console.log('dateObject', dateObject);
- // if (!dateObject) {
- // setAvailableConnectorDropdownOptions([]);
- // return;
- // }
- // const rangeObject = dateObject.range.find((range) => range.start === selectedTime);
- // console.log('rangeObject', rangeObject);
- // if (!rangeObject) {
- // setAvailableConnectorDropdownOptions([]);
- // return;
- // }
- // const connectorIDs = rangeObject.connectors
- // .filter((connector) => connector.Status === '待机')
- // .map((connector) => connector.ConnectorID);
- // console.log('connectorIDs', connectorIDs);
- // setAvailableConnectorDropdownOptions(connectorIDs);
- // } catch (error) {
- // console.error('Error fetching charge station data:', error);
- // setAvailableConnectorDropdownOptions([]);
- // }
- // };
- // fetchConnectorOptions();
- // }, [chargeStationID, selectedDate, selectedTime]);
- // old
- // const formattedConnectorDropdownOptions = availableConnectorDropdownOptions.map((id, index) => ({
- // label: (index + 1).toString(),
- // value: id
- // }));
- const connectorIDToLabelMap = {
- '101708240502475001': '1',
- '101708240502476001': '2',
- '101708240502477001': '3',
- '101708240502478001': '4',
- '101708240502474001': '5',
- '101708240502474002': '6'
- };
- const connectorIDToLabelMapArray = [
- { value: '101708240502475001', label: '1' },
- { value: '101708240502476001', label: '2' },
- { value: '101708240502477001', label: '3' },
- { value: '101708240502478001', label: '4' },
- { value: '101708240502474001', label: '5' },
- { value: '101708240502474002', label: '6' }
- ];
- const formatDateString = (dateString: string) => {
- const [year, month, day] = dateString.split('-');
- return `${month}/${day}`;
- };
- // useEffect(() => {
- // const fetchingAvailableDates = async () => {
- // setIsDateLoading(true);
- // try {
- // const fetchedDates = await chargeStationService.fetchAvailableDates(chargeStationID);
- // console.log('fetchedDates', fetchedDates);
- // setAvailableDate(fetchedDates);
- // console.log(fetchedDates.slice(0, 3));
- // } catch (error) {
- // console.error('Error fetching available dates:', error);
- // } finally {
- // setIsDateLoading(false);
- // }
- // };
- // fetchingAvailableDates();
- // }, [chargeStationID]);
- const handleNavigationPress = () => {
- const latitude = chargeStationLat;
- const longitude = chargeStationLng;
- // console.log('latitude', latitude);
- // console.log('longitude', longitude);
- const label = encodeURIComponent(chargeStationName);
- // Google Maps App URL
- 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}`;
- Linking.canOpenURL(googleMapsUrl)
- .then((supported) => {
- if (supported) {
- Linking.openURL(googleMapsUrl);
- } else {
- Linking.openURL(webUrl).catch((err) => {
- console.error('An error occurred', err);
- Alert.alert(
- 'Error',
- "Unable to open Google Maps. Please make sure it's installed on your device.",
- [{ text: 'OK' }],
- { cancelable: false }
- );
- });
- }
- })
- .catch((err) => console.error('An error occurred', err));
- };
- const handleDateToTimeSlot = (date: string, connectorId: string) => {
- // Find the correct connector object
- const connectorData = dataResponse.find((item) => item.connector === connectorId);
- if (!connectorData) {
- console.error(`No data found for connector ${connectorId}`);
- setAvailableTimeSlots([]);
- return;
- }
- // Find the timeSlot object for the selected date
- const selectedTimeSlot = connectorData.timeSlot.find((slot) => slot.date === date);
- if (!selectedTimeSlot) {
- console.error(`No time slots found for date ${date}`);
- setAvailableTimeSlots([]);
- return;
- }
- const now = new Date();
- const selectedDateObj = new Date(date);
- const isToday = selectedDateObj.toDateString() === now.toDateString();
- let filteredSlots = selectedTimeSlot.availableTime;
- if (isToday) {
- filteredSlots = filteredSlots.filter((slot) => {
- const [hours, minutes] = slot.startTime.split(':').map(Number);
- const slotTime = new Date(selectedDateObj);
- slotTime.setHours(hours, minutes, 0, 0);
- return slotTime > now;
- });
- }
- console.log('Available Time Slots:', filteredSlots);
- setAvailableTimeSlots(filteredSlots);
- };
- const handleConfirmation = (value: any) => {
- setModalVisible(true);
- const selectedOption = formattedConnectorDropdownOptions.find((option) => option.value === value);
- const label = selectedOption ? selectedOption.label : '';
- setRouterParams({
- pathname: '/bookingConfirmationPage',
- params: {
- chargeStationName,
- chargeStationAddress,
- chargeStationID,
- connectorID: value,
- connectorLabel: label,
- userID,
- carCapacitance: carCapacitance,
- carID: selectedCarID,
- carName: selectedCar,
- date: selectedDate,
- bookTime: selectedTime,
- chargingMethod: stopChargingUponBatteryFull ? 'stopChargingUponBatteryFull' : 'chargingBasedOnWatt',
- chargingWatt: selectedWatt || '',
- price: price
- }
- });
- };
- const handleModalConfirm = () => {
- setModalVisible(false);
- if (routerParams) {
- console.log('routerParams', routerParams);
- router.push(routerParams);
- }
- };
- return (
- <SafeAreaView
- style={{
- flex: 1,
- backgroundColor: 'white'
- }}
- edges={['right', 'top', 'left']}
- >
- <ScrollView className="flex-1 bg-white" showsVerticalScrollIndicator={false}>
- <View className="pb-4 ">
- <View className="ml-[5%] pt-8">
- <Pressable
- style={{ alignSelf: 'flex-start' }}
- onPress={() => {
- if (router.canGoBack()) {
- router.back();
- } else {
- router.replace('./');
- }
- }}
- >
- <PreviousPageBlackSvg />
- </Pressable>
- <Text className="text-3xl mt-8">{chargeStationName}</Text>
- <View className="flex-column">
- <View className="flex-row justify-between items-center mr-[5%]">
- <Text className="text-base" style={styles.grayColor}>
- {chargeStationAddress}
- </Text>
- <NormalButton
- title={
- <View className="flex-row items-center justify-center text-center space-x-1">
- <DirectionLogoSvg />
- <Text className="text-base">路線</Text>
- </View>
- }
- // onPress={() => console.log('路線')}
- onPress={handleNavigationPress}
- extendedStyle={{
- backgroundColor: '#E3F2F8',
- borderRadius: 61,
- paddingHorizontal: 20,
- paddingVertical: 8
- }}
- />
- </View>
- <View className="flex-row space-x-2 items-center">
- <CheckMarkLogoSvg />
- <Text>Walk-In</Text>
- {/* <Text>{distance}</Text> */}
- </View>
- </View>
- </View>
- </View>
- <View>
- {/* {selectedCar !== '' ? (
- <>
- <Pressable
- onPress={() => {
- setSelectedCar('');
- setSelectedWatt('');
- setOpenDrawer(0);
- setSelectedDrawer(0);
- setSelectedDuration('');
- setChargingBasedOnWatt(false);
- setStopChargingUponBatteryFull(false);
- setSelectedDate('');
- setSelectedTime('');
- }}
- >
- <View className="mx-[5%]">
- <View className="flex-row items-center pt-4">
- <Text className="text-lg pr-2 text-[#34667c]">選擇充電車輛</Text>
- <CheckMarkLogoSvg />
- </View>
- <Text className="text-lg pb-4">{selectedCar}</Text>
- </View>
- </Pressable>
- </>
- ) : (
- <AccordionItem
- title="選擇充電車輛"
- isOpen={openDrawer === 0}
- onToggle={() => toggleDrawer(0)}
- isSelected={selectedDrawer === 0}
- >
- {carLoadingState ? (
- <View>
- <ActivityIndicator color="#34657b" />
- </View>
- ) : (
- <ScrollView
- horizontal={true}
- contentContainerStyle={{
- alignItems: 'center',
- flexDirection: 'row',
- marginVertical: 8
- }}
- className="space-x-2 "
- >
- {car
- .sort((a, b) => (b.isDefault ? 1 : 0) - (a.isDefault ? 1 : 0))
- .map((car, index) => (
- <ChooseCarForChargingRow
- onPress={() => {
- setSelectedCar(car.car_name);
- setSelectedCarID(car.car_id);
- setCarCapacitance(car.car_capacitance);
- setSelectedDrawer(1);
- setOpenDrawer(1);
- }}
- image={car.processedImageUrl}
- key={`${car.car_name}+${index}`}
- VehicleName={car.car_name}
- isDefault={car.isDefault}
- />
- ))}
- </ScrollView>
- )}
- </AccordionItem>
- )} */}
- {stopChargingUponBatteryFull === true || selectedWatt !== '' ? (
- <Pressable
- onPress={() => {
- setSelectedDuration('');
- setChargingBasedOnWatt(false);
- setStopChargingUponBatteryFull(false);
- setSelectedTime('');
- setSelectedDate('');
- setSelectedWatt('');
- setOpenDrawer(1);
- setSelectedDrawer(1);
- setSelectedChargingGun('');
- }}
- >
- <View className="mx-[5%] ">
- <View className="flex-row items-center pt-4">
- <Text className="text-lg pr-2 text-[#34667c]">選擇充電方案</Text>
- <CheckMarkLogoSvg />
- </View>
- <Text className="text-lg pb-4">
- {selectedWatt !== '' ? `按每道電 - ${selectedWatt.split('~')[0]}` : '充滿停機'}
- </Text>
- </View>
- </Pressable>
- ) : (
- <AccordionItem
- title="選擇充電方案"
- isOpen={openDrawer === 1}
- onToggle={() => {}}
- isSelected={selectedDrawer === 1}
- >
- <View className="flex-row justify-between mt-2 mb-3">
- <Pressable
- className={`border rounded-lg border-[#34667c] w-[47%] items-center bg-white ${
- chargingBasedOnWatt ? 'bg-[#34667c] ' : ''
- }`}
- onPress={() => {
- setChargingBasedOnWatt(!chargingBasedOnWatt);
- setStopChargingUponBatteryFull(false);
- }}
- >
- <Text
- className={`text-base p-2 text-[#34667c] ${
- chargingBasedOnWatt ? ' text-white' : 'text-[#34667c]'
- }`}
- >
- 按每度電
- </Text>
- </Pressable>
- {/* <Pressable
- onPress={() => {
- setStopChargingUponBatteryFull(!stopChargingUponBatteryFull);
- setChargingBasedOnWatt(false);
- setSelectedDrawer(2);
- setOpenDrawer(2);
- }}
- className={`border rounded-lg border-[#34667c] w-[47%] items-center bg-white ${
- stopChargingUponBatteryFull ? ' bg-[#34667c]' : ''
- }`}
- >
- <Text
- className={`text-base p-2 text-[#34667c] ${
- stopChargingUponBatteryFull ? ' text-white' : 'text-[#34667c]'
- }`}
- >
- 充滿停機
- </Text>
- </Pressable> */}
- </View>
- {chargingBasedOnWatt === true && (
- <View className="flex-row w-full justify-between mb-3">
- {['20 kWh~25mins', '25 kWh~30mins', '30 kWh~40mins', '40 kWh~45mins'].map(
- (watt) => (
- <Pressable
- key={watt}
- className={`${
- selectedWatt === watt ? 'bg-[#34667c] ' : 'bg-white'
- } border border-[#34667c] rounded-lg w-[22%] items-center`}
- onPress={() => {
- setSelectedWatt(watt);
- setOpenDrawer(2);
- setSelectedDrawer(2);
- handleSendingSize(watt);
- console.log('selectedWatt', selectedWatt);
- console.log('watt', watt);
- }}
- >
- <Text
- className={`text-base pt-2 pl-2 pr-2 ${
- selectedWatt === watt ? 'text-white' : 'text-[#34667c]'
- } `}
- >
- {watt.split('~')[0]}
- </Text>
- <Text className="text-xs pt-0 pb-1 text-[#666666]">
- {watt.split('~')[1]}
- </Text>
- </Pressable>
- )
- )}
- </View>
- )}
- </AccordionItem>
- )}
- {/* select gun */}
- {/* select gun */}
- <View className="">
- {selectedChargingGun !== '' ? (
- <Pressable
- onPress={() => {
- setSelectedChargingGun('');
- setOpenDrawer(2);
- setSelectedDrawer(2);
- }}
- >
- <View className="mx-[5%]">
- <View className="flex-row items-center pt-4">
- <Text className="text-lg pr-2 text-[#34667c]">選擇充電座</Text>
- <CheckMarkLogoSvg />
- </View>
- <View className="text-lg pb-4 flex flex-row items-center">
- <Text className="text-[#34667c] font-[600] text-2xl pr-2">
- {connectorIDToLabelMap[selectedChargingGun]}
- </Text>
- <Text className="text-lg">號充電座</Text>
- </View>
- </View>
- </Pressable>
- ) : (
- <AccordionItem
- title="選擇充電座"
- isOpen={openDrawer === 2}
- onToggle={() => {
- if (selectedWatt) {
- toggleDrawer(2);
- }
- }}
- isSelected={selectedDrawer === 2}
- >
- {selectedWatt !== '' ? (
- <View className="">
- <DropdownSelect
- dropdownOptions={connectorIDToLabelMapArray}
- placeholder={'選擇充電座號碼'}
- onSelect={(value) => {
- setSelectedChargingGun(value);
- setSelectedDrawer(3);
- setOpenDrawer(3);
- }}
- extendedStyle={{
- borderColor: '#34667c',
- marginTop: 4,
- padding: 12
- }}
- />
- <Image
- style={{
- width: layoutWidth * 0.9,
- height: layoutHeight
- }}
- resizeMode="contain"
- source={require('../../assets/floorPlan1.png')}
- />
- </View>
- ) : (
- <Text className="text-base text-gray-500 py-2">請先選擇充電方案</Text>
- )}
- </AccordionItem>
- )}
- </View>
- <Modal
- isVisible={isModalVisible}
- // onBackdropPress={() => setModalVisible(false)}
- backdropOpacity={0.5}
- animationIn="fadeIn"
- animationOut="fadeOut"
- >
- <View style={styles.modalContent}>
- <Text className="text-2xl font-[500] text-[#34667c] mb-6">
- 已選擇日期時間: {formatDateString(selectedDate)} - {selectedTime}
- </Text>
- <Text style={styles.modalText} className="text-[#34667c]">
- 若客戶逾時超過15分鐘,系統將視作自動放棄預約,客戶需要重新預約一次。
- 本公司有權保留全數費用,恕不退還。按下確認代表您已閱讀並同意上述條款。
- </Text>
- <NormalButton
- title={<Text className="text-white">我確認</Text>}
- onPress={handleModalConfirm}
- extendedStyle={styles.confirmButton}
- />
- </View>
- </Modal>
- {selectedDate !== '' && selectedTime !== '' ? (
- <>
- <Pressable
- onPress={() => {
- setOpenDrawer(3);
- setSelectedDrawer(3);
- setSelectedDate('');
- setSelectedTime('');
- }}
- >
- <View className="mx-[5%] ">
- <View className="flex-row items-center pt-4">
- <Text className="text-lg pr-2 text-[#34667c]">選擇日期</Text>
- <CheckMarkLogoSvg />
- </View>
- <Text className="text-lg pb-4">
- {formatDateString(selectedDate)} - {selectedTime}
- </Text>
- </View>
- </Pressable>
- </>
- ) : (
- <AccordionItem
- title="選擇日期 (月/日)"
- isOpen={openDrawer === 3}
- onToggle={() => {
- if (stopChargingUponBatteryFull !== false || selectedDuration !== '') {
- toggleDrawer(3);
- }
- }}
- isSelected={selectedDrawer === 3}
- >
- {isDateLoading ? (
- <View className="flex-1 items-center justify-center py-4">
- <ActivityIndicator size="large" color="#34667c" />
- </View>
- ) : (
- <View className="flex-row w-full flex-wrap mb-1 ">
- {availableDate.map((date) => (
- <Pressable
- key={date}
- className={`${
- selectedDate === date ? 'bg-[#34667c] ' : 'bg-white'
- } border border-[#34667c] rounded-lg w-[22%] items-center mt-1 mr-1 mb-1`}
- onPress={() => {
- setSelectedDate(date);
- handleDateToTimeSlot(date, selectedChargingGun);
- }}
- >
- <Text
- className={`text-base p-2 ${
- selectedDate === date ? 'text-white' : 'text-[#34667c]'
- } `}
- >
- {formatDateString(date)}
- </Text>
- </Pressable>
- ))}
- </View>
- )}
- {selectedDate !== '' && (
- <>
- <Text className="text-lg pr-2 ">選擇時間</Text>
- {isLoading ? (
- <View className="flex-1 mb-2">
- <ActivityIndicator />
- </View>
- ) : (
- <View className="flex-row w-full mb-3 flex-wrap my-2 ">
- {availableTimeSlots.map((slot, index) => (
- <Pressable
- key={index}
- className={`${
- selectedTime === slot.startTime ? 'bg-[#34667c] ' : 'bg-white'
- } border border-[#34667c] mr-2 rounded-lg w-[22%] items-center mb-2`}
- onPress={() => {
- setSelectedTime(slot.startTime);
- setRouterParams({
- pathname: '/bookingConfirmationPage',
- params: {
- chargeStationName,
- chargeStationAddress,
- chargeStationID,
- connectorID: selectedChargingGun,
- connectorLabel:
- connectorIDToLabelMap[selectedChargingGun],
- userID,
- carCapacitance: carCapacitance,
- carID: selectedCarID,
- carName: selectedCar,
- date: selectedDate,
- bookTime: slot.startTime,
- endTime: slot.endTime,
- chargingMethod: stopChargingUponBatteryFull
- ? 'stopChargingUponBatteryFull'
- : 'chargingBasedOnWatt',
- chargingWatt: selectedWatt || '',
- price: price
- }
- });
- setModalVisible(true);
- }}
- >
- <Text
- className={`text-base p-2 ${
- selectedTime === slot.startTime
- ? 'text-white'
- : 'text-[#34667c]'
- } `}
- >
- {slot.startTime}
- </Text>
- </Pressable>
- ))}
- </View>
- )}
- </>
- )}
- </AccordionItem>
- )}
- {/* <View className="">
- <AccordionItem
- title="選擇充電座"
- isOpen={openDrawer === 3}
- onToggle={() => {
- if (selectedTime) {
- // toggleDrawer(3);
- }
- }}
- isSelected={selectedDrawer === 3}
- >
- <View className="">
- <DropdownSelect
- dropdownOptions={formattedConnectorDropdownOptions}
- placeholder={'選擇充電座號碼'}
- onSelect={(value) => {
- setSelectedChargingGun(value);
- handleConfirmation(value);
- }}
- extendedStyle={{
- borderColor: '#34667c',
- marginTop: 4,
- padding: 12
- }}
- />
- <Image
- style={{
- width: layoutWidth * 0.9,
- height: layoutHeight
- }}
- resizeMode="contain"
- source={require('../../assets/floorPlan1.png')}
- />
- <Modal
- isVisible={isModalVisible}
- // onBackdropPress={() => setModalVisible(false)}
- backdropOpacity={0.5}
- animationIn="fadeIn"
- animationOut="fadeOut"
- >
- <View style={styles.modalContent}>
- <Text style={styles.modalText}>
- 若客戶逾時超過15分鐘,系統將視作自動放棄預約,客戶需要重新預約一次。
- 本公司有權保留全數費用,恕不退還。按下確認代表您已閱讀並同意上述條款。
- </Text>
- <NormalButton
- title={<Text className="text-white">我確認</Text>}
- onPress={handleModalConfirm}
- extendedStyle={styles.confirmButton}
- />
- </View>
- </Modal>
- </View>
- </AccordionItem>
- </View> */}
- </View>
- <View className="mx-[5%] flex-1">
- <Text className="text-xl pb-2 mt-6" style={styles.text}>
- 充電站資訊
- </Text>
- <View className="h-[250px]">
- <ChargingStationTabView titles={['預約充電事項', '其他']} />
- </View>
- </View>
- </ScrollView>
- </SafeAreaView>
- );
- };
- export default MakingBookingPageComponent;
- const styles = StyleSheet.create({
- grayColor: {
- color: '#888888'
- },
- topLeftTriangle: {
- width: 0,
- height: 0,
- borderLeftWidth: 50,
- borderBottomWidth: 50,
- borderLeftColor: '#02677D',
- borderBottomColor: 'transparent',
- position: 'absolute',
- top: 0,
- left: 0
- },
- modalContent: {
- backgroundColor: 'white',
- padding: 22,
- justifyContent: 'center',
- alignItems: 'center',
- borderRadius: 4,
- borderColor: 'rgba(0, 0, 0, 0.1)'
- },
- modalText: {
- fontSize: 18,
- marginBottom: 12,
- textAlign: 'center'
- },
- confirmButton: {
- backgroundColor: '#34667c',
- paddingHorizontal: 30,
- paddingVertical: 10,
- borderRadius: 5
- },
- text: {
- fontWeight: 300,
- color: '#000000'
- }
- });
|