| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630 |
- import {
- View,
- Text,
- ScrollView,
- Pressable,
- StyleSheet,
- Image,
- Dimensions,
- ActivityIndicator
- } from 'react-native';
- import { SafeAreaView } from 'react-native-safe-area-context';
- import { router } from 'expo-router';
- import NormalButton from '../global/normal_button';
- import {
- CheckMarkLogoSvg,
- DirectionLogoSvg,
- PreviousPageBlackSvg
- } from '../global/SVG';
- import { ChargingStationTabView } from '../global/chargingStationTabView';
- import ChooseCarForChargingRow from '../global/chooseCarForChargingRow';
- import { useEffect, useState } from 'react';
- import DropdownSelect from '../global/dropdown_select';
- import { chargeStationService } from '../../service/chargeStationService';
- const dummyDataChooseCarForCharging = [
- {
- imageUrl: require('../../assets/car1.png'),
- VehicleName: 'TESLA - Model 3',
- isDefault: true
- },
- { VehicleName: 'TESLA - Model Y', isDefault: false },
- {
- imageUrl: require('../../assets/car1.png'),
- VehicleName: 'TESLA - Model X',
- isDefault: false
- },
- { VehicleName: 'TESLA - Model 3', isDefault: false }
- ];
- 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 [openDrawer, setOpenDrawer] = useState<number | null>(0);
- const [selectedTime, setSelectedTime] = useState<string>('');
- const [availableTimeSlots, setAvailableTimeSlots] = useState<string[]>([]);
- const [selectedDrawer, setSelectedDrawer] = useState<number>(0);
- const [isLoading, setIsLoading] = useState(true);
- const [selectedDate, setSelectedDate] = useState<string>('');
- const toggleDrawer = (index: number) => {
- setOpenDrawer(openDrawer === index ? null : index);
- setSelectedDrawer(index);
- };
- const [availableDate, setAvailableDate] = useState<string[]>([]);
- useEffect(() => {
- const fetchingAvailableDates = async () => {
- const fetchedDates = await chargeStationService.fetchAvailableDates(
- '2405311022116801000'
- );
- setAvailableDate(fetchedDates);
- };
- fetchingAvailableDates();
- }, []);
- useEffect(() => {
- const fetchingAvailableTimeSlots = async () => {
- setIsLoading(true);
- try {
- const fetchedTimeSlots =
- await chargeStationService.fetchAvailableTimeSlots(
- '2405311022116801000',
- selectedDate
- );
- setAvailableTimeSlots(fetchedTimeSlots);
- console.log(`I AM TIMESLOT ${fetchedTimeSlots}`);
- } catch (error) {
- console.error('Error fetching time slots:', error);
- } finally {
- setIsLoading(false);
- }
- };
- if (selectedDate) {
- fetchingAvailableTimeSlots();
- }
- }, [selectedDate]);
- const timeData = [
- '14:00',
- '14:15',
- '14:30',
- '14:45',
- '15:00',
- '15:15',
- '15:30',
- '15:45',
- '16:00',
- '16:15',
- '16:30',
- '16:45',
- '17:00',
- '17:15',
- '17:30',
- '17:45'
- ];
- const dateData = [
- '今天',
- '3/15',
- '3/16',
- '3/17',
- '3/18',
- '3/19',
- '3/20',
- '3/21'
- ];
- const [uiState, setUiState] = useState({
- isCarSelected: false,
- isChargingPlanOpen: false,
- isDateOpen: false,
- isCharigingGunOpen: false
- });
- const [selectedChargingGun, setSelectedChargingGun] = useState('');
- const [chargingBasedOnWatt, setChargingBasedOnWatt] = useState(false);
- const [stopChargingUponBatteryFull, setStopChargingUponBatteryFull] =
- useState(false);
- const [selectedCar, setSelectedCar] = useState('');
- const [selectedDuration, setSelectedDuration] = useState('');
- const { width: screenWidth, height: screenHeight } =
- Dimensions.get('window');
- const layoutWidth = screenWidth;
- const layoutHeight = screenHeight * 0.4;
- 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">上環街市充電站</Text>
- <View className="flex-column">
- <View className="flex-row justify-between items-center mr-[5%]">
- <Text
- className="text-base"
- style={styles.grayColor}
- >
- 香港上環皇后大道中345號
- </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('路線')}
- 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>400米</Text>
- </View>
- </View>
- </View>
- </View>
- <View>
- {selectedCar !== '' ? (
- <>
- <Pressable
- onPress={() => {
- setSelectedCar('');
- 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}
- >
- <ScrollView
- horizontal={true}
- contentContainerStyle={{
- alignItems: 'center',
- flexDirection: 'row',
- marginVertical: 8
- }}
- className="space-x-2 "
- >
- {dummyDataChooseCarForCharging.map(
- (car, index) => (
- <ChooseCarForChargingRow
- onPress={() => {
- setSelectedCar(car.VehicleName);
- setSelectedDrawer(1);
- setOpenDrawer(1);
- }}
- imageUrl={car.imageUrl}
- key={`${car.VehicleName}+${index}`}
- VehicleName={car.VehicleName}
- isDefault={car.isDefault}
- />
- )
- )}
- </ScrollView>
- </AccordionItem>
- )}
- {stopChargingUponBatteryFull === true ||
- selectedDuration !== '' ? (
- <Pressable
- onPress={() => {
- setSelectedDuration('');
- setChargingBasedOnWatt(false);
- setStopChargingUponBatteryFull(false);
- setSelectedTime('');
- setSelectedDate('');
- setOpenDrawer(1);
- setSelectedDrawer(1);
- }}
- >
- <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">
- {selectedDuration !== ''
- ? `按每道電 - ${selectedDuration}`
- : '充滿停機'}
- </Text>
- </View>
- </Pressable>
- ) : (
- <AccordionItem
- title="選擇充電方案"
- isOpen={openDrawer === 1}
- onToggle={() => {
- if (selectedCar !== '') {
- toggleDrawer(1);
- }
- }}
- 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">
- {['30分鐘', '45分鐘', '60分鐘', '其他'].map(
- (duration) => (
- <Pressable
- key={duration}
- className={`${
- selectedDuration ===
- duration
- ? 'bg-[#34667c] '
- : 'bg-white'
- } border border-[#34667c] rounded-lg w-[22%] items-center`}
- onPress={() => {
- setSelectedDuration(
- duration
- );
- setOpenDrawer(2);
- setSelectedDrawer(2);
- }}
- >
- <Text
- className={`text-base p-2 ${
- selectedDuration ===
- duration
- ? 'text-white'
- : 'text-[#34667c]'
- } `}
- >
- {duration}
- </Text>
- </Pressable>
- )
- )}
- </View>
- )}
- </AccordionItem>
- )}
- {selectedTime !== '' ? (
- <Pressable
- onPress={() => {
- setOpenDrawer(2);
- setSelectedDrawer(2);
- 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">
- {selectedDate} - {selectedTime}
- </Text>
- </View>
- </Pressable>
- ) : (
- <AccordionItem
- title="選擇日期 (月/日)"
- isOpen={openDrawer === 2}
- onToggle={() => {
- if (
- stopChargingUponBatteryFull !== false ||
- selectedDuration !== ''
- ) {
- toggleDrawer(2);
- }
- }}
- isSelected={selectedDrawer === 2}
- >
- <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);
- }}
- >
- <Text
- className={`text-base p-2 ${
- selectedDate === date
- ? 'text-white'
- : 'text-[#34667c]'
- } `}
- >
- {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 justify-between mb-3 flex-wrap my-2 ">
- {availableTimeSlots.map((time) => (
- <Pressable
- key={time}
- className={`${
- selectedTime === time
- ? 'bg-[#34667c] '
- : 'bg-white'
- } border border-[#34667c] rounded-lg w-[22%] items-center mb-2`}
- onPress={() => {
- setSelectedTime(time);
- setOpenDrawer(3);
- setSelectedDrawer(3);
- }}
- >
- <Text
- className={`text-base p-2 ${
- selectedTime ===
- time
- ? 'text-white'
- : 'text-[#34667c]'
- } `}
- >
- {time}
- </Text>
- </Pressable>
- ))}
- </View>
- )}
- </>
- )}
- </AccordionItem>
- )}
- <View className="">
- <AccordionItem
- title="選擇充電座"
- isOpen={openDrawer === 3}
- onToggle={() => {
- if (selectedTime) {
- toggleDrawer(3);
- }
- }}
- isSelected={selectedDrawer === 3}
- >
- <View className="">
- <DropdownSelect
- dropdownOptions={[
- { label: '1', value: '1' },
- { label: '2', value: '2' }
- ]}
- placeholder={'選擇充電座號碼'}
- onSelect={(value) => {
- setSelectedChargingGun(value);
- router.push('/bookingConfirmationPage');
- }}
- extendedStyle={{
- borderColor: '#34667c',
- marginTop: 4
- }}
- />
- <Image
- style={{
- width: layoutWidth * 0.97,
- height: layoutHeight
- }}
- resizeMode="contain"
- source={require('../../assets/ChargeStationLayout.png')}
- />
- </View>
- </AccordionItem>
- </View>
- </View>
- <View className="mx-[5%] flex-1">
- <View
- className="flex-row border-slate-300 mt-3 mb-6 rounded-2xl flex-1"
- style={{ borderWidth: 1 }}
- >
- <View className="flex-1 m-4">
- <View className="flex-1 flex-row ">
- <View className=" flex-1 flex-column justify-between">
- <Text
- className="text-xl "
- style={styles.text}
- >
- 收費
- </Text>
- <View className="flex-row items-center space-x-2">
- <Text className="text-3xl text-[#02677D]">
- $20
- </Text>
- <Text style={styles.text}>
- 每15分鐘
- </Text>
- </View>
- </View>
- <View className="items-center justify-center">
- <View className="w-[1px] h-[60%] bg-[#CCCCCC]" />
- </View>
- <View className="flex-1 flex-column ">
- <View className="flex-1"></View>
- <View className="flex-row items-center ml-4 space-x-2 ">
- <Text className="text-3xl text-[#02677D]">
- $3.5
- </Text>
- <Text style={styles.text}>每度電</Text>
- </View>
- </View>
- </View>
- </View>
- </View>
- <Text className="text-xl pb-2 " 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
- },
- text: {
- fontWeight: 300,
- color: '#000000'
- }
- });
|