chargingPage.tsx 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. import { View, Text, ActivityIndicator, AppState, ScrollView, RefreshControl } from 'react-native';
  2. import React, { useCallback, useContext, useEffect, useRef, useState } from 'react';
  3. import ChargingPageComponent from '../../../../component/chargingPage/chargingPageComponent';
  4. import { chargeStationService } from '../../../../service/chargeStationService';
  5. import ChargingPenaltyPageComponent from '../../../../component/chargingPage/chargingPenaltyComponent';
  6. import NoChargingOngoingPageComponent from '../../../../component/chargingPage/noChargingOngoingPageComponent';
  7. import { useFocusEffect } from 'expo-router';
  8. import ChargingHurryUpPageComponent from '../../../../component/chargingPage/chargingHurryUpPageComponent';
  9. import FutureReservationPageComponent from '../../../../component/chargingPage/futureReservationPageComponent';
  10. import ChargingFinishPageComponent from '../../../../component/chargingPage/chargingFinishPageComponent';
  11. import { AuthContext } from '../../../../context/AuthProvider';
  12. //***********************************************************************
  13. //而家start time & end time 一樣就當Walk in, walkin 會改左d字眼在ChargingHurryUpPageComponent
  14. //如果以後scan qr code可選時間, ChargingHurryUp display 字眼個logic 就要改
  15. //***********************************************************************
  16. const ChargingPage = () => {
  17. const [data, setData] = useState();
  18. const [isLoading, setIsLoading] = useState(false);
  19. const [currentStatus, setCurrentStatus] = useState('');
  20. const intervalRef = useRef(null);
  21. const lastUpdateTimeRef = useRef(Date.now());
  22. const { user } = useContext(AuthContext);
  23. const [refreshing, setRefreshing] = useState(false);
  24. const [refetchTrigger, setRefetchTrigger] = useState(0);
  25. const fetchReservationData = useCallback(async () => {
  26. setIsLoading(true);
  27. try {
  28. const now = new Date();
  29. const response = await chargeStationService.fetchReservationHistories();
  30. lastUpdateTimeRef.current = Date.now();
  31. if (Object.keys(response).length === 0) {
  32. console.log('no reservation data');
  33. setCurrentStatus('noReservation');
  34. } else {
  35. // Check for recently finished reservations
  36. const finishedReservation = response.find((r) => {
  37. if (r.status.id === '8' && r.actual_end_time) {
  38. const endTime = new Date(r.actual_end_time);
  39. const timeDifference = now.getTime() - endTime.getTime();
  40. return timeDifference <= 1 * 60 * 1000; // Within 1 minutes
  41. }
  42. return false;
  43. });
  44. if (finishedReservation) {
  45. // console.log('now', now);
  46. // console.log('Finished reservation found:', finishedReservation);
  47. setCurrentStatus('finishReservation');
  48. setData(finishedReservation);
  49. } else {
  50. // Existing checks for other reservation types
  51. const penaltyReservation = response.filter(
  52. (r) => r.actual_start_time != null && r.actual_end_time != null && r.connector.Status === 7
  53. );
  54. if (penaltyReservation.length > 0) {
  55. setCurrentStatus('penaltyReservation');
  56. setData(penaltyReservation);
  57. } else {
  58. // Check for ongoing reservations (已插槍的預約)
  59. const onGoingReservation = response.filter(
  60. (r) => r.status.id === '7' && r.actual_end_time == null
  61. );
  62. // console.log('onGoingReservation', onGoingReservation);
  63. if (onGoingReservation.length > 0) {
  64. setCurrentStatus('onGoingReservation');
  65. setData(onGoingReservation);
  66. } else {
  67. // Check for recently passed reservations (仍未開始插槍充電的預約)
  68. const recentlyPassedReservations = response.filter((r) => {
  69. const bookTime = new Date(r.book_time);
  70. const fifteenMinutesAfterBookTime = new Date(bookTime.getTime() + 15 * 60 * 1000);
  71. const isWithin15MinutesAndStatus6 =
  72. now > bookTime && now <= fifteenMinutesAfterBookTime && r.status.id === '6';
  73. return isWithin15MinutesAndStatus6;
  74. });
  75. if (recentlyPassedReservations.length > 0) {
  76. // console.log(' i am recentlyPassedReservation', recentlyPassedReservations);
  77. setCurrentStatus('recentlyPassedReservations');
  78. setData(recentlyPassedReservations);
  79. } else {
  80. const futureReservation = response.filter((r) => {
  81. const bookTime = new Date(r.book_time);
  82. const fifteenMinutesAfterBookTime = new Date(bookTime.getTime() + 15 * 60 * 1000);
  83. return now < bookTime || (now > bookTime && now <= fifteenMinutesAfterBookTime);
  84. });
  85. if (futureReservation.length > 0) {
  86. futureReservation.sort((a, b) => new Date(a.end_time) - new Date(b.end_time));
  87. const closestReservation = futureReservation[0];
  88. setCurrentStatus('futureReservation');
  89. setData(closestReservation);
  90. } else {
  91. //if you are here, it means there are no future reservations (but there are past reservations)
  92. setCurrentStatus('noReservation');
  93. }
  94. }
  95. }
  96. }
  97. }
  98. }
  99. } catch (error) {
  100. console.error('Error fetching reservation histordfsdfes:', error);
  101. } finally {
  102. setIsLoading(false);
  103. }
  104. }, []);
  105. const onRefresh = useCallback(() => {
  106. setRefreshing(true);
  107. setRefetchTrigger((prev) => prev + 1);
  108. // Simulate a delay to show the refresh indicator
  109. setTimeout(() => {
  110. setRefreshing(false);
  111. fetchReservationData().finally(() => {
  112. setRefreshing(false);
  113. });
  114. }, 1000);
  115. }, []);
  116. const checkAndUpdateData = useCallback(() => {
  117. const currentTime = Date.now();
  118. const timeSinceLastUpdate = currentTime - lastUpdateTimeRef.current;
  119. if (timeSinceLastUpdate > 60000) {
  120. // If more than a minute has passed
  121. fetchReservationData();
  122. }
  123. }, [fetchReservationData]);
  124. useEffect(() => {
  125. const subscription = AppState.addEventListener('change', (nextAppState) => {
  126. if (nextAppState === 'active') {
  127. checkAndUpdateData();
  128. }
  129. });
  130. return () => {
  131. subscription.remove();
  132. };
  133. }, [checkAndUpdateData]);
  134. useEffect(() => {
  135. fetchReservationData();
  136. intervalRef.current = setInterval(fetchReservationData, 60000);
  137. return () => {
  138. if (intervalRef.current) {
  139. clearInterval(intervalRef.current);
  140. }
  141. };
  142. }, [fetchReservationData]);
  143. useFocusEffect(
  144. useCallback(() => {
  145. let isActive = true;
  146. const fetchData = async () => {
  147. try {
  148. await fetchReservationData();
  149. } catch (error) {
  150. console.error('Error in useFocusEffect:', error);
  151. }
  152. };
  153. fetchData();
  154. // Cleanup function
  155. return () => {
  156. isActive = false;
  157. // Any additional cleanup logic can go here
  158. };
  159. }, [fetchReservationData])
  160. );
  161. if (isLoading) {
  162. return (
  163. <View className="flex-1 justify-center bg-white">
  164. <ActivityIndicator color="#34657b" size="large" />
  165. </View>
  166. );
  167. }
  168. return (
  169. <ScrollView
  170. className="bg-white flex-1"
  171. refreshControl={
  172. <RefreshControl
  173. refreshing={refreshing}
  174. onRefresh={onRefresh}
  175. colors={['#34657b']} // Android
  176. tintColor="#34657b" // iOS
  177. />
  178. }
  179. >
  180. <View className="flex-1">
  181. {currentStatus === 'noReservation' && <NoChargingOngoingPageComponent />}
  182. {currentStatus === 'penaltyReservation' && <ChargingPenaltyPageComponent data={data} />}
  183. {currentStatus === 'onGoingReservation' && <ChargingPageComponent data={data} />}
  184. {currentStatus === 'recentlyPassedReservations' && <ChargingHurryUpPageComponent data={data} />}
  185. {currentStatus === 'futureReservation' && <FutureReservationPageComponent data={data} />}
  186. {currentStatus === 'finishReservation' && <ChargingFinishPageComponent data={data} />}
  187. </View>
  188. </ScrollView>
  189. );
  190. };
  191. export default ChargingPage;