| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349 |
- import { View, Text, ScrollView, StyleSheet, Image, ActivityIndicator } from 'react-native';
- import { SafeAreaView } from 'react-native-safe-area-context';
- import RippleEffectBatteryIcon from '../global/rippleEffectBatteryIcon';
- import LoadingDots from '../global/loadingDots';
- import NormalButton from '../global/normal_button';
- import { router } from 'expo-router';
- import { BatteryIconSvg, LightingLogoSvg, TemperatureIconSvg } from '../global/SVG';
- import { useContext, useEffect, useState } from 'react';
- import { chargeStationService } from '../../service/chargeStationService';
- import { set } from 'date-fns';
- import { convertToHKTime } from '../../util/lib';
- import ChargingPenaltyPageComponent from './chargingPenaltyComponent';
- import { AuthContext } from '../../context/AuthProvider';
- const ChargingPageComponent = ({ data }) => {
- const reservationData = Array.isArray(data) ? data[0] : data;
- const [isLoading, setIsLoading] = useState(true);
- const [loading, setLoading] = useState(false);
- const [onGoingChargingData, setOnGoingChargingData] = useState();
- // console.log('data', data);
- // console.log('voltageA and currentA', onGoingChargingData.data.VoltageA, onGoingChargingData.dataCurrentA);
- const voltageA = onGoingChargingData?.data?.VoltageA;
- const currentA = onGoingChargingData?.data?.CurrentA;
- const { user } = useContext(AuthContext);
- // console.log('voltageA and currentA', voltageA, currentA);
- useEffect(() => {
- const fetchOngoingChargingData = async () => {
- setIsLoading(true);
- try {
- const response = await chargeStationService.fetchOngoingChargingData(reservationData.format_order_id);
- if (response) {
- setOnGoingChargingData(response);
- // console.log('i am ongoingchargingdata', response);
- // console.log('onGoingData current and voltage', response.CurrentA, response.VoltageA);
- } else {
- }
- } catch (error) {
- console.error('Error fetching reservation histories:', error);
- } finally {
- setIsLoading(false);
- }
- };
- fetchOngoingChargingData();
- }, [reservationData]);
- // //////////////////////////////////////////////////////////////////////
- // send an automatic handleStopCharge when reservationData.end_time is now
- const stopPayLoad = {
- StartChargeSeq: reservationData.format_order_id,
- ConnectorID: reservationData.connector.ConnectorID
- };
- const handleStopCharge = async () => {
- setLoading(true);
- try {
- const response = await chargeStationService.stopCharging(stopPayLoad);
- if (response) {
- setLoading(false);
- } else {
- setLoading(false);
- }
- } catch (error) {
- setLoading(false);
- }
- };
- //now i make a reservation, make it a 7 and see if it comes here
- useEffect(() => {
- const now = new Date();
- const endTime = reservationData?.end_time ? new Date(reservationData.end_time) : null;
- // console.log('now in chargingPageComponent', now);
- // console.log('endTime in chargingPageComponent', endTime);
- // console.log('Checking stop conditions:', { now, endTime, Soc: reservationData?.Soc });
- // Access the snapshot properties
- const snapshotData = reservationData?.snapshot ? JSON.parse(reservationData.snapshot) : null;
- // console.log('snapshotData in onGoingChargingData', snapshotData);
- // console.log('snapshot.is_ic_call', snapshotData?.is_ic_call);
- // console.log('snapshot.type', snapshotData?.type);
- if (reservationData && snapshotData) {
- const isWalkingOrIcCall = snapshotData.type === 'walking' || snapshotData.is_ic_call === true;
- const shouldStopCharge = reservationData.Soc >= 95 || (!isWalkingOrIcCall && endTime && now >= endTime);
- if (shouldStopCharge) {
- console.log(
- 'Initiating automatic stop. Reason:',
- reservationData.Soc >= 95 ? 'Battery reached 95% or higher' : 'End time reached'
- );
- handleStopCharge();
- }
- }
- }, [reservationData]);
- //用來計充電歷時
- const [timeSince, setTimeSince] = useState<string>('');
- useEffect(() => {
- const updateTimeSince = () => {
- if (reservationData && reservationData.actual_start_time) {
- setTimeSince(timeSinceBooking(reservationData.actual_start_time) || '計算中...');
- } else {
- setTimeSince('計算中...');
- }
- };
- updateTimeSince();
- // Update every minute
- const intervalId = setInterval(updateTimeSince, 60000);
- // Cleanup interval on component unmount
- return () => clearInterval(intervalId);
- }, [reservationData]);
- function timeSinceBooking(timeString) {
- if (timeString) {
- // console.log('timeString in timeSinceBooking', timeString);
- const startTime = new Date(timeString);
- const now = new Date();
- // console.log('now in timeSinceBooking', now);
- // console.log('startTime in timeSinceBooking', startTime);
- // console.log('now - startTime', now - startTime);
- const diffInMilliseconds = now - startTime;
- const diffInMinutes = Math.floor(diffInMilliseconds / (1000 * 60));
- // console.log('diffInMinutes in timeSinceBooking', diffInMinutes);
- if (diffInMinutes < 1) {
- return '< 1 minute';
- } else {
- return `${diffInMinutes} minute${diffInMinutes !== 1 ? 's' : ''}`;
- }
- }
- }
- //用來計充電歷時 //用來計充電歷時 //用來計充電歷時 //用來計充電歷時 //用來計充電歷時
- const displayKW = (currentA: number, voltageA: number) => {
- if (currentA && voltageA) {
- return (currentA * voltageA) / 1000;
- } else return 30.0;
- };
- const connectorIDToLabelMap = {
- '101708240502475001': '1',
- '101708240502476001': '2',
- '101708240502477001': '3',
- '101708240502478001': '4',
- '101708240502474001': '5',
- '101708240502474002': '6'
- };
- if (isLoading) {
- return (
- <SafeAreaView style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
- <ActivityIndicator size="large" />
- <Text>Loading...</Text>
- </SafeAreaView>
- );
- }
- return (
- <SafeAreaView style={{ flex: 1, backgroundColor: 'white' }} edges={['top', 'left', 'right']}>
- <ScrollView className="flex-1">
- <View className="flex-1 mx-[5%] space-y-4">
- <View className="items-center">
- <View className="mt-6 mb-4">
- <Text className="text-lg ">現正充電中:</Text>
- </View>
- <Text className="text-4xl font-light">
- {/* {reservationData.car.car_brand.name} {reservationData.car.car_type.name} */}
- {user?.nickname}
- </Text>
- </View>
- <View className="items-center">
- <Text className="text-lg" style={styles.grayColor}>
- 充電中
- </Text>
- <View className="flex-row space-x-4 p-4 pr-8 items-center justify-center ml-10">
- <RippleEffectBatteryIcon />
- <Text
- style={{
- color: '#02677D',
- fontSize: 60,
- fontWeight: 300
- }}
- >
- {/* 4852 */}
- {/* {onGoingChargingData ? `${onGoingChargingData.Soc} %` : 'Loading'} */}
- {`${reservationData.Soc}%`}
- {/* {`64%`} */}
- <LoadingDots />
- </Text>
- </View>
- {/* 尚餘時間未知點計住 comments左先
- <Text className="text-lg mb-6" style={styles.grayColor}>
- 尚餘時間 ~48 mins
- </Text> */}
- {/* <View className="mb-[-10] items-center justify-center ">
- <Image
- source={require('../../assets/car.png')}
- style={{ width: 430, height: 200 }}
- resizeMode="contain"
- />
- </View> */}
- </View>
- <View
- className="h-[220px] min-h-[20px] border-slate-300 rounded-2xl flex-column"
- style={{ borderWidth: 1 }}
- >
- {/* Top */}
- {/* this is actual total power */}
- <View className="h-[65%] flex-row justify-evenly items-center">
- <View className="flex-1 flex-column items-center space-y-2">
- <LightingLogoSvg />
- <Text style={styles.grayColor} className="text-base">
- 實際充電量(度數)
- </Text>
- {isLoading ? (
- <ActivityIndicator />
- ) : (
- <Text style={styles.greenColor} className="font-bold text-base">
- {/* {displayKW(onGoingChargingData.CurrentA, onGoingChargingData.VoltageA)}kW */}
- {reservationData.actual_total_power
- ? `${reservationData.actual_total_power.toFixed(1)}`
- : '計算中...'}
- </Text>
- )}
- </View>
- <View className="flex-1 flex-column items-center space-y-2">
- <BatteryIconSvg />
- <Text style={styles.grayColor} className="text-base">
- 實際功率 (kW)
- </Text>
- {isLoading ? (
- <ActivityIndicator />
- ) : (
- <Text style={styles.greenColor} className="font-bold text-base">
- {onGoingChargingData && voltageA && currentA
- ? ((voltageA * currentA) / 1000).toFixed(1)
- : '請見充電顯示螢幕'}
- </Text>
- )}
- </View>
- {/* <View className="flex-1 flex-column items-center space-y-2">
- <TemperatureIconSvg />
- <Text style={styles.grayColor} className="text-base">
- 溫度
- </Text>
- {isLoading ? (
- <ActivityIndicator />
- ) : (
- <Text style={styles.greenColor} className="font-bold text-base">
- 36°c
- </Text>
- )}
- </View> */}
- </View>
- <View className="mx-[5%]">
- <View className="h-[1px] w-[100%] bg-[#CCCCCC]" />
- </View>
- {/* bottom container */}
- <View className="h-[35%] mx-[5%] justify-center ">
- <Text style={styles.grayColor} className="text-base">
- 充電歷時 ~{timeSince}
- </Text>
- </View>
- </View>
- {/* <View
- className="min-h-[20px] border-slate-300 rounded-2xl justify-center p-4"
- style={{ borderWidth: 1 }}
- >
- <View className="flex-row items-center justify-between ">
- <View>
- <Text className="text-lg">預計充電費用</Text>
- <Text className="text-base" style={styles.grayColor}>
- 按每度電結算: 50 kWh
- </Text>
- </View>
- <Text className="text-3xl">HK$ 175</Text>
- </View>
- </View> */}
- <View className="border-slate-300 rounded-2xl justify-center p-4" style={{ borderWidth: 1 }}>
- <Text className="text-lg pb-1 ">其他資訊</Text>
- <View className="flex-row">
- <View className="flex-1 flex-column">
- <Text className="text-base" style={styles.grayColor}>
- 開始時間
- </Text>
- <Text className="text-base">
- {convertToHKTime(reservationData.actual_start_time).hkTime.slice(0, 5)}
- </Text>
- </View>
- <View className="flex-1 flex-column">
- <Text className="text-base" style={styles.grayColor}>
- 充電座
- </Text>
- <Text className="text-base">
- {`${connectorIDToLabelMap[reservationData.connector.ConnectorID]}號`}
- </Text>
- </View>
- </View>
- </View>
- <View>
- <NormalButton
- onPress={() => {
- router.push('mainPage');
- }}
- title={
- <Text className="text-xl text-white" style={{ fontWeight: 900 }}>
- 返回主頁
- </Text>
- }
- />
- </View>
- {/* <View>
- <NormalButton
- onPress={() => {
- router.push('/chargingPenaltyPage');
- }}
- title={
- <Text className="text-xl text-white" style={{ fontWeight: 900 }}>
- 觀看閒置/罰款狀態頁面
- </Text>
- }
- />
- </View> */}
- </View>
- </ScrollView>
- </SafeAreaView>
- );
- };
- export default ChargingPageComponent;
- const styles = StyleSheet.create({
- grayColor: {
- color: '#888888'
- },
- greenColor: {
- color: '#02677D'
- },
- text: {
- fontWeight: 300,
- color: '#000000'
- }
- });
|