chargingPageComponent.tsx 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. import { View, Text, ScrollView, StyleSheet, Image, ActivityIndicator } from 'react-native';
  2. import { SafeAreaView } from 'react-native-safe-area-context';
  3. import RippleEffectBatteryIcon from '../global/rippleEffectBatteryIcon';
  4. import LoadingDots from '../global/loadingDots';
  5. import NormalButton from '../global/normal_button';
  6. import { router } from 'expo-router';
  7. import { BatteryIconSvg, LightingLogoSvg, TemperatureIconSvg } from '../global/SVG';
  8. import { useContext, useEffect, useState } from 'react';
  9. import { chargeStationService } from '../../service/chargeStationService';
  10. import { set } from 'date-fns';
  11. import { convertToHKTime } from '../../util/lib';
  12. import ChargingPenaltyPageComponent from './chargingPenaltyComponent';
  13. import { AuthContext } from '../../context/AuthProvider';
  14. const ChargingPageComponent = ({ data }) => {
  15. const reservationData = Array.isArray(data) ? data[0] : data;
  16. const [isLoading, setIsLoading] = useState(true);
  17. const [loading, setLoading] = useState(false);
  18. const [onGoingChargingData, setOnGoingChargingData] = useState();
  19. // console.log('data', data);
  20. // console.log('voltageA and currentA', onGoingChargingData.data.VoltageA, onGoingChargingData.dataCurrentA);
  21. const voltageA = onGoingChargingData?.data?.VoltageA;
  22. const currentA = onGoingChargingData?.data?.CurrentA;
  23. const { user } = useContext(AuthContext);
  24. // console.log('voltageA and currentA', voltageA, currentA);
  25. useEffect(() => {
  26. const fetchOngoingChargingData = async () => {
  27. setIsLoading(true);
  28. try {
  29. const response = await chargeStationService.fetchOngoingChargingData(reservationData.format_order_id);
  30. if (response) {
  31. setOnGoingChargingData(response);
  32. // console.log('i am ongoingchargingdata', response);
  33. // console.log('onGoingData current and voltage', response.CurrentA, response.VoltageA);
  34. } else {
  35. console.log('error fetching data');
  36. }
  37. } catch (error) {
  38. console.error('Error fetching reservation histories:', error);
  39. } finally {
  40. setIsLoading(false);
  41. }
  42. };
  43. fetchOngoingChargingData();
  44. }, [reservationData]);
  45. // //////////////////////////////////////////////////////////////////////
  46. // send an automatic handleStopCharge when reservationData.end_time is now
  47. const stopPayLoad = {
  48. StartChargeSeq: reservationData.format_order_id,
  49. ConnectorID: reservationData.connector.ConnectorID
  50. };
  51. const handleStopCharge = async () => {
  52. setLoading(true);
  53. try {
  54. console.log('stopPayLoad', stopPayLoad);
  55. const response = await chargeStationService.stopCharging(stopPayLoad);
  56. if (response) {
  57. console.log('handleStopCharge begins, response received:', response);
  58. setLoading(false);
  59. } else {
  60. setLoading(false);
  61. console.log('handleStopCharge失敗');
  62. }
  63. } catch (error) {
  64. setLoading(false);
  65. console.log('handleStopCharge error', error);
  66. }
  67. };
  68. //now i make a reservation, make it a 7 and see if it comes here
  69. useEffect(() => {
  70. const now = new Date();
  71. const endTime = reservationData?.end_time ? new Date(reservationData.end_time) : null;
  72. // console.log('now in chargingPageComponent', now);
  73. // console.log('endTime in chargingPageComponent', endTime);
  74. // console.log('Checking stop conditions:', { now, endTime, Soc: reservationData?.Soc });
  75. // Access the snapshot properties
  76. const snapshotData = reservationData?.snapshot ? JSON.parse(reservationData.snapshot) : null;
  77. // console.log('snapshotData in onGoingChargingData', snapshotData);
  78. // console.log('snapshot.is_ic_call', snapshotData?.is_ic_call);
  79. // console.log('snapshot.type', snapshotData?.type);
  80. if (reservationData && snapshotData) {
  81. const isWalkingOrIcCall = snapshotData.type === 'walking' || snapshotData.is_ic_call === true;
  82. const shouldStopCharge = reservationData.Soc >= 95 || (!isWalkingOrIcCall && endTime && now >= endTime);
  83. if (shouldStopCharge) {
  84. console.log(
  85. 'Initiating automatic stop. Reason:',
  86. reservationData.Soc >= 95 ? 'Battery reached 95% or higher' : 'End time reached'
  87. );
  88. handleStopCharge();
  89. }
  90. }
  91. }, [reservationData]);
  92. /////////////////////////////////////////////////////////////
  93. //用來計充電歷時 //用來計充電歷時 //用來計充電歷時 //用來計充電歷時 //用來計充電歷時
  94. const [timeSince, setTimeSince] = useState<string>('');
  95. useEffect(() => {
  96. const updateTimeSince = () => {
  97. if (reservationData && reservationData.actual_start_time) {
  98. setTimeSince(timeSinceBooking(reservationData.actual_start_time) || '計算中...');
  99. } else {
  100. setTimeSince('計算中...');
  101. }
  102. };
  103. updateTimeSince();
  104. // Update every minute
  105. const intervalId = setInterval(updateTimeSince, 60000);
  106. // Cleanup interval on component unmount
  107. return () => clearInterval(intervalId);
  108. }, [reservationData]);
  109. function timeSinceBooking(timeString) {
  110. if (timeString) {
  111. // console.log('timeString in timeSinceBooking', timeString);
  112. const startTime = new Date(timeString);
  113. const now = new Date();
  114. // console.log('now in timeSinceBooking', now);
  115. // console.log('startTime in timeSinceBooking', startTime);
  116. // console.log('now - startTime', now - startTime);
  117. const diffInMilliseconds = now - startTime;
  118. const diffInMinutes = Math.floor(diffInMilliseconds / (1000 * 60));
  119. // console.log('diffInMinutes in timeSinceBooking', diffInMinutes);
  120. if (diffInMinutes < 1) {
  121. return '< 1 minute';
  122. } else {
  123. return `${diffInMinutes} minute${diffInMinutes !== 1 ? 's' : ''}`;
  124. }
  125. }
  126. }
  127. //用來計充電歷時 //用來計充電歷時 //用來計充電歷時 //用來計充電歷時 //用來計充電歷時
  128. const displayKW = (currentA: number, voltageA: number) => {
  129. if (currentA && voltageA) {
  130. return (currentA * voltageA) / 1000;
  131. } else return 30.0;
  132. };
  133. const connectorIDToLabelMap = {
  134. '101708240502475001': '1',
  135. '101708240502476001': '2',
  136. '101708240502477001': '3',
  137. '101708240502478001': '4',
  138. '101708240502474001': '5',
  139. '101708240502474002': '6'
  140. };
  141. if (isLoading) {
  142. return (
  143. <SafeAreaView style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
  144. <ActivityIndicator size="large" />
  145. <Text>Loading...</Text>
  146. </SafeAreaView>
  147. );
  148. }
  149. return (
  150. <SafeAreaView style={{ flex: 1, backgroundColor: 'white' }} edges={['top', 'left', 'right']}>
  151. <ScrollView className="flex-1">
  152. <View className="flex-1 mx-[5%] space-y-4">
  153. <View className="items-center">
  154. <View className="mt-6 mb-4">
  155. <Text className="text-lg ">現正充電中:</Text>
  156. </View>
  157. <Text className="text-4xl font-light">
  158. {/* {reservationData.car.car_brand.name} {reservationData.car.car_type.name} */}
  159. {user?.nickname}
  160. </Text>
  161. </View>
  162. <View className="items-center">
  163. <Text className="text-lg" style={styles.grayColor}>
  164. 充電中
  165. </Text>
  166. <View className="flex-row space-x-4 p-4 pr-8 items-center justify-center ml-10">
  167. <RippleEffectBatteryIcon />
  168. <Text
  169. style={{
  170. color: '#02677D',
  171. fontSize: 60,
  172. fontWeight: 300
  173. }}
  174. >
  175. {/* 4852 */}
  176. {/* {onGoingChargingData ? `${onGoingChargingData.Soc} %` : 'Loading'} */}
  177. {`${reservationData.Soc}%`}
  178. {/* {`64%`} */}
  179. <LoadingDots />
  180. </Text>
  181. </View>
  182. {/* 尚餘時間未知點計住 comments左先
  183. <Text className="text-lg mb-6" style={styles.grayColor}>
  184. 尚餘時間 ~48 mins
  185. </Text> */}
  186. {/* <View className="mb-[-10] items-center justify-center ">
  187. <Image
  188. source={require('../../assets/car.png')}
  189. style={{ width: 430, height: 200 }}
  190. resizeMode="contain"
  191. />
  192. </View> */}
  193. </View>
  194. <View
  195. className="h-[220px] min-h-[20px] border-slate-300 rounded-2xl flex-column"
  196. style={{ borderWidth: 1 }}
  197. >
  198. {/* Top */}
  199. {/* this is actual total power */}
  200. <View className="h-[65%] flex-row justify-evenly items-center">
  201. <View className="flex-1 flex-column items-center space-y-2">
  202. <LightingLogoSvg />
  203. <Text style={styles.grayColor} className="text-base">
  204. 實際充電量(度數)
  205. </Text>
  206. {isLoading ? (
  207. <ActivityIndicator />
  208. ) : (
  209. <Text style={styles.greenColor} className="font-bold text-base">
  210. {/* {displayKW(onGoingChargingData.CurrentA, onGoingChargingData.VoltageA)}kW */}
  211. {reservationData.actual_total_power
  212. ? `${reservationData.actual_total_power.toFixed(1)}`
  213. : '計算中...'}
  214. </Text>
  215. )}
  216. </View>
  217. <View className="flex-1 flex-column items-center space-y-2">
  218. <BatteryIconSvg />
  219. <Text style={styles.grayColor} className="text-base">
  220. 實際功率 (kW)
  221. </Text>
  222. {isLoading ? (
  223. <ActivityIndicator />
  224. ) : (
  225. <Text style={styles.greenColor} className="font-bold text-base">
  226. {onGoingChargingData && voltageA && currentA
  227. ? ((voltageA * currentA) / 1000).toFixed(1)
  228. : '請見充電顯示螢幕'}
  229. </Text>
  230. )}
  231. </View>
  232. {/* <View className="flex-1 flex-column items-center space-y-2">
  233. <TemperatureIconSvg />
  234. <Text style={styles.grayColor} className="text-base">
  235. 溫度
  236. </Text>
  237. {isLoading ? (
  238. <ActivityIndicator />
  239. ) : (
  240. <Text style={styles.greenColor} className="font-bold text-base">
  241. 36°c
  242. </Text>
  243. )}
  244. </View> */}
  245. </View>
  246. <View className="mx-[5%]">
  247. <View className="h-[1px] w-[100%] bg-[#CCCCCC]" />
  248. </View>
  249. {/* bottom container */}
  250. <View className="h-[35%] mx-[5%] justify-center ">
  251. <Text style={styles.grayColor} className="text-base">
  252. 充電歷時 ~{timeSince}
  253. </Text>
  254. </View>
  255. </View>
  256. {/* <View
  257. className="min-h-[20px] border-slate-300 rounded-2xl justify-center p-4"
  258. style={{ borderWidth: 1 }}
  259. >
  260. <View className="flex-row items-center justify-between ">
  261. <View>
  262. <Text className="text-lg">預計充電費用</Text>
  263. <Text className="text-base" style={styles.grayColor}>
  264. 按每度電結算: 50 kWh
  265. </Text>
  266. </View>
  267. <Text className="text-3xl">HK$ 175</Text>
  268. </View>
  269. </View> */}
  270. <View className="border-slate-300 rounded-2xl justify-center p-4" style={{ borderWidth: 1 }}>
  271. <Text className="text-lg pb-1 ">其他資訊</Text>
  272. <View className="flex-row">
  273. <View className="flex-1 flex-column">
  274. <Text className="text-base" style={styles.grayColor}>
  275. 開始時間
  276. </Text>
  277. <Text className="text-base">
  278. {convertToHKTime(reservationData.actual_start_time).hkTime.slice(0, 5)}
  279. </Text>
  280. </View>
  281. <View className="flex-1 flex-column">
  282. <Text className="text-base" style={styles.grayColor}>
  283. 充電座
  284. </Text>
  285. <Text className="text-base">
  286. {`${connectorIDToLabelMap[reservationData.connector.ConnectorID]}號`}
  287. </Text>
  288. </View>
  289. </View>
  290. </View>
  291. <View>
  292. <NormalButton
  293. onPress={() => {
  294. router.push('mainPage');
  295. }}
  296. title={
  297. <Text className="text-xl text-white" style={{ fontWeight: 900 }}>
  298. 返回主頁
  299. </Text>
  300. }
  301. />
  302. </View>
  303. {/* <View>
  304. <NormalButton
  305. onPress={() => {
  306. router.push('/chargingPenaltyPage');
  307. }}
  308. title={
  309. <Text className="text-xl text-white" style={{ fontWeight: 900 }}>
  310. 觀看閒置/罰款狀態頁面
  311. </Text>
  312. }
  313. />
  314. </View> */}
  315. </View>
  316. </ScrollView>
  317. </SafeAreaView>
  318. );
  319. };
  320. export default ChargingPageComponent;
  321. const styles = StyleSheet.create({
  322. grayColor: {
  323. color: '#888888'
  324. },
  325. greenColor: {
  326. color: '#02677D'
  327. },
  328. text: {
  329. fontWeight: 300,
  330. color: '#000000'
  331. }
  332. });