chargingRecord.tsx 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. //the size of the TabView will follow its parent-container's size.
  2. import * as React from 'react';
  3. import * as Location from 'expo-location';
  4. import {
  5. View,
  6. Text,
  7. useWindowDimensions,
  8. Dimensions,
  9. StyleSheet,
  10. Image,
  11. ImageSourcePropType,
  12. ActivityIndicator,
  13. Pressable
  14. } from 'react-native';
  15. import { FlashList } from '@shopify/flash-list';
  16. import { useEffect, useState } from 'react';
  17. import { calculateDistance } from './distanceCalculator';
  18. import { router } from 'expo-router';
  19. import { useTranslation } from '../../util/hooks/useTranslation';
  20. export interface TabItem {
  21. imgURL: ImageSourcePropType;
  22. date: string;
  23. time: string;
  24. chargeStationName: string;
  25. chargeStationAddress: string;
  26. stationLat: string | number;
  27. stationLng: string | number;
  28. distance: string;
  29. format_order_id: string;
  30. actual_total_power?: number;
  31. actual_end_time?: string;
  32. actual_fee?: number;
  33. current_price?: number;
  34. id?: string;
  35. status?: any
  36. }
  37. interface TabViewComponentProps {
  38. tabItems: TabItem[];
  39. isLoading?: boolean;
  40. }
  41. const TabViewComponent: React.FC<TabViewComponentProps> = ({
  42. isLoading,
  43. tabItems,
  44. }) => {
  45. const layout = useWindowDimensions();
  46. const [currentLocation, setCurrentLocation] = useState<Location.LocationObject | null>(null);
  47. useEffect(() => {
  48. const getCurrentLocation = async () => {
  49. let { status } = await Location.requestForegroundPermissionsAsync();
  50. if (status !== 'granted') {
  51. console.error('Permission to access location was denied');
  52. return;
  53. }
  54. let location = await Location.getLastKnownPositionAsync({});
  55. setCurrentLocation(location);
  56. };
  57. getCurrentLocation();
  58. }, []);
  59. const FirstRoute = ({ tabItems, isLoading, currentLocation }: {
  60. tabItems: TabItem[];
  61. isLoading?: boolean;
  62. currentLocation: Location.LocationObject | null
  63. }) => (
  64. <View style={{ flex: 1, backgroundColor: 'white' }}>
  65. {isLoading ? (
  66. <View className="items-center justify-center flex-1">
  67. <ActivityIndicator color="#34657b" />
  68. </View>
  69. ) : (
  70. <FlashList
  71. nestedScrollEnabled={true}
  72. data={tabItems.filter((item) => item?.actual_total_power && item?.actual_total_power !== 0)}
  73. renderItem={({ item }) => <TabItem item={item} currentLocation={currentLocation} />}
  74. keyExtractor={(item, index) => index.toString()}
  75. />
  76. )}
  77. </View>
  78. );
  79. return (
  80. <FirstRoute tabItems={tabItems} isLoading={isLoading} currentLocation={currentLocation} />
  81. );
  82. };
  83. const TabItem = ({ item, currentLocation }: { item: TabItem; currentLocation: Location.LocationObject | null }) => {
  84. const [distance, setDistance] = useState<number | null>(null);
  85. const { t } = useTranslation();
  86. useEffect(() => {
  87. const getDistance = async () => {
  88. if (currentLocation) {
  89. const result = await calculateDistance(
  90. Number(item.stationLat),
  91. Number(item.stationLng),
  92. currentLocation
  93. );
  94. setDistance(result);
  95. }
  96. };
  97. getDistance();
  98. }, [currentLocation, item.stationLat, item.stationLng]);
  99. return (
  100. <Pressable
  101. onPress={() => {
  102. console.log(item.format_order_id);
  103. }}
  104. >
  105. <View style={styles.container}>
  106. <Image style={styles.image} source={item.imgURL} />
  107. <View className="flex flex-col flex-wrap gap-2 mr-2">
  108. <Text
  109. style={{
  110. fontWeight: '700',
  111. color: '#02677D',
  112. fontSize: 16
  113. }}
  114. >
  115. {`${item.date}${t('chargingHistory.charging_record.day')} - ${item.time}${t('chargingHistory.charging_record.to')}${item.actual_end_time}`}
  116. </Text>
  117. <View className="flex flex-row flex-wrap justify-between">
  118. <Text
  119. style={{
  120. fontWeight: '400',
  121. fontSize: 14,
  122. color: '#222222',
  123. flexWrap: 'wrap',
  124. flexShrink: 1
  125. }}
  126. numberOfLines={0}
  127. >
  128. {t('chargingHistory.charging_record.charged_amount')}:{' '}
  129. {item.actual_total_power
  130. ? item.actual_total_power % 1 === 0
  131. ? item.actual_total_power
  132. : item.actual_total_power.toFixed(1)
  133. : ''}
  134. </Text>
  135. <Text
  136. style={{
  137. fontWeight: '400',
  138. fontSize: 14,
  139. color: '#222222',
  140. flexWrap: 'wrap',
  141. flexShrink: 1
  142. }}
  143. numberOfLines={0}
  144. >
  145. {t('chargingHistory.charging_record.amount_payable')}:{' '}
  146. {item.actual_fee !== undefined && item.actual_fee !== null
  147. ? item.actual_fee <= 0
  148. ? '$0'
  149. : item.actual_fee % 1 === 0
  150. ? `$${item.actual_fee}`
  151. : `$${item.actual_fee.toFixed(1)}`
  152. : ''}
  153. </Text>
  154. </View>
  155. <Text
  156. style={{
  157. fontWeight: '400',
  158. fontSize: 14,
  159. color: '#888888'
  160. }}
  161. >
  162. {item.chargeStationName}
  163. </Text>
  164. <View className="flex flex-row space-x-2">
  165. {
  166. item.status.id === 7 || item.status.id === 13?
  167. <Text
  168. style={{
  169. fontWeight: '400',
  170. fontSize: 14,
  171. color: '#02677D'
  172. }}
  173. >
  174. {t('chargingHistory.charging_record.order_in_progress')}
  175. </Text>
  176. :
  177. <Text
  178. style={{
  179. fontWeight: '400',
  180. fontSize: 14,
  181. color: '#02677D'
  182. }}
  183. onPress={() => {
  184. router.push({ pathname: 'chargingDetailsPage', params: { id: item.id, chargeStationName: item.chargeStationName }})
  185. }}
  186. >
  187. {t('chargingHistory.charging_record.order_details')} &gt;
  188. </Text>
  189. }
  190. </View>
  191. </View>
  192. </View>
  193. </Pressable>
  194. );
  195. };
  196. export default TabViewComponent;
  197. const styles = StyleSheet.create({
  198. container: {
  199. flexDirection: 'row',
  200. width: '100%',
  201. flex: 1,
  202. alignItems: 'center'
  203. },
  204. image: {
  205. width: 100,
  206. height: 100,
  207. margin: 15,
  208. borderRadius: 10
  209. },
  210. textContainer: {
  211. flex: 1,
  212. flexDirection: 'column',
  213. gap: 8,
  214. marginTop: 20,
  215. marginRight: 8 // Add right margin to prevent text from touching the edge
  216. }
  217. });