myVehiclePageComponent.tsx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. import React, { useCallback, useEffect, useState } from 'react';
  2. import { View, Text, ScrollView, Pressable, Image, Dimensions, ActivityIndicator } from 'react-native';
  3. import { SafeAreaView } from 'react-native-safe-area-context';
  4. import { router } from 'expo-router';
  5. import { CrossLogoSvg, GreenStarSvg, RightArrowIconSvg } from '../global/SVG';
  6. import NormalButton from '../global/normal_button';
  7. import { chargeStationService } from '../../service/chargeStationService';
  8. import { authenticationService } from '../../service/authService';
  9. const truncateText = (text: any, maxLength: any) => {
  10. if (text.length <= maxLength) return text;
  11. return text.substr(0, maxLength) + '...';
  12. };
  13. const VehicleRow = ({ car, deviceWidth, deviceHeight, onPress }) => (
  14. <Pressable onPress={onPress}>
  15. <View
  16. className="rounded-xl mb-2 flex-row items-center justify-between "
  17. style={{
  18. width: deviceWidth * 0.9,
  19. height: deviceHeight * 0.12
  20. // backgroundColor: '#e9f2f7'
  21. }}
  22. >
  23. <Image
  24. style={{
  25. width: deviceWidth * 0.32,
  26. height: '100%'
  27. }}
  28. resizeMode="contain"
  29. // source={{ uri: car.processedImageUrl }}
  30. source={require('../../assets/car.png')}
  31. />
  32. <View className="flex-row items-center">
  33. <View className="flex-1 flex-col pl-2">
  34. <Text style={{ fontSize: 22, fontWeight: '600' }}>{car.car_brand.name}</Text>
  35. <Text style={{ fontSize: 18 }}>{truncateText(car.car_type.name, 10)}</Text>
  36. <Text style={{ fontSize: 16, color: '#02677D' }}>{car?.license_plate}</Text>
  37. </View>
  38. <View className="flex-1">
  39. <RightArrowIconSvg />
  40. </View>
  41. </View>
  42. </View>
  43. <View className="border-t mx-4 border-[#CCCCCC]"></View>
  44. </Pressable>
  45. );
  46. const MyVehiclePageComponent = () => {
  47. const { height: deviceHeight, width: deviceWidth } = Dimensions.get('window');
  48. const [vehicles, setVehicles] = useState([]);
  49. const [defaultCar, setDefaultCar] = useState(null);
  50. const [processedUrls, setProcessedUrls] = useState({});
  51. const [isLoading, setIsLoading] = useState(false);
  52. const fetchData = useCallback(async () => {
  53. setIsLoading(true);
  54. try {
  55. const [carsResult, userInfoResult] = await Promise.all([
  56. chargeStationService.getUserCars(),
  57. authenticationService.getUserInfo()
  58. ]);
  59. let updatedVehicles = [...carsResult.data];
  60. for (let i = 0; i < updatedVehicles.length; i++) {
  61. const car = updatedVehicles[i];
  62. const processedUrl = await chargeStationService.getProcessedImageUrl(car.car_type.type_image_url);
  63. updatedVehicles[i] = {
  64. ...car,
  65. processedImageUrl: processedUrl
  66. };
  67. }
  68. setVehicles(updatedVehicles);
  69. //all car data
  70. //find default from all car data
  71. const defaultCarId = userInfoResult.data.defaultCar.id;
  72. const defaultCar = updatedVehicles.find((car) => car.id === defaultCarId);
  73. setDefaultCar(defaultCar);
  74. //find processed Image urls
  75. } catch (error) {
  76. console.error('Error fetching data:', error);
  77. } finally {
  78. setIsLoading(false);
  79. }
  80. }, []);
  81. function repeat(char, times) {
  82. return new Array(times + 1).join(char);
  83. }
  84. // Use the function
  85. useEffect(() => {
  86. fetchData();
  87. }, [fetchData]);
  88. const otherVehicles = vehicles.filter((car) => car.id !== defaultCar?.id);
  89. // console.log(repeat('-', 50));
  90. // console.log(otherVehicles);
  91. return (
  92. <SafeAreaView className="flex-1 bg-white" edges={['top', 'right', 'left']}>
  93. <ScrollView showsVerticalScrollIndicator={false} className="flex-1 mx-[5%]">
  94. {isLoading ? (
  95. <View className="flex flex-col justify-center items-center h-screen">
  96. <ActivityIndicator />
  97. </View>
  98. ) : (
  99. <>
  100. <View style={{ marginTop: 25 }}>
  101. <Pressable
  102. className="self-start"
  103. onPress={() =>
  104. router.canGoBack() ? router.back() : router.replace('/accountMainPage')
  105. }
  106. >
  107. <CrossLogoSvg />
  108. </Pressable>
  109. <Text style={{ fontSize: 45, marginTop: 25, marginBottom: 10 }}>我的車輛</Text>
  110. </View>
  111. <View className="items-center">
  112. <Image
  113. source={require('../../assets/car.png')}
  114. // source={{ uri: defaultCar?.processedImageUrl }}
  115. resizeMode="contain"
  116. style={{ width: deviceWidth * 0.8, height: deviceHeight * 0.25 }}
  117. />
  118. </View>
  119. {defaultCar && (
  120. <View className="flex-row space-x-2">
  121. <View style={{ width: 4, height: '100%', backgroundColor: '#02677D' }} />
  122. <View>
  123. <View className="flex-row items-center">
  124. <Text className="text-lg text-[#02677D]">預設車輛</Text>
  125. <GreenStarSvg />
  126. </View>
  127. <Text className="text-2xl">{defaultCar.car_type.name}</Text>
  128. <Text className="text-lg text-[#888888]">{defaultCar.license_plate}</Text>
  129. </View>
  130. </View>
  131. )}
  132. <View className="w-full h-1 my-4 bg-[#DBE4E8]" />
  133. <Text className="text-xl mb-4">其他車輛</Text>
  134. {otherVehicles.map((car) => (
  135. <VehicleRow
  136. key={car.id}
  137. car={car}
  138. deviceHeight={deviceHeight}
  139. deviceWidth={deviceWidth}
  140. onPress={() =>
  141. router.push({
  142. pathname: 'manageVehiclePage',
  143. params: {
  144. carID: car.id,
  145. capacitance: car.car_type.capacitance,
  146. capacitance_unit: car.car_type.capacitance_unit,
  147. createdAt: car.car_type.createdAt,
  148. carModel: car.car_type.name,
  149. licensePlate: car.license_plate,
  150. carImage: car.processedImageUrl
  151. }
  152. })
  153. }
  154. />
  155. ))}
  156. <NormalButton
  157. title={<Text style={{ fontWeight: '700', fontSize: 20, color: '#fff' }}>新增車輛</Text>}
  158. onPress={() => router.push('addVehiclePage')}
  159. />
  160. </>
  161. )}
  162. </ScrollView>
  163. </SafeAreaView>
  164. // <SafeAreaView className="flex-1 bg-white" edges={['top', 'right', 'left']}>
  165. // <ScrollView showsVerticalScrollIndicator={false} className="flex-1 mx-[5%]">
  166. // <View style={{ marginTop: 25 }}>
  167. // <Pressable
  168. // className="self-start"
  169. // onPress={() => (router.canGoBack() ? router.back() : router.replace('/accountMainPage'))}
  170. // >
  171. // <CrossLogoSvg />
  172. // </Pressable>
  173. // <Text style={{ fontSize: 45, marginTop: 25, marginBottom: 10 }}>我的車輛</Text>
  174. // </View>
  175. // {isLoading ? (
  176. // <View className="flex flex-col justify-center items-center h-full ">
  177. // <ActivityIndicator />
  178. // </View>
  179. // ) : (
  180. // <>
  181. // <View className="items-center">
  182. // <Image
  183. // source={require('../../assets/car.png')}
  184. // // source={{ uri: defaultCar?.processedImageUrl }}
  185. // resizeMode="contain"
  186. // style={{ width: deviceWidth * 0.8, height: deviceHeight * 0.25 }}
  187. // />
  188. // </View>
  189. // {defaultCar && (
  190. // <View className="flex-row space-x-2">
  191. // <View style={{ width: 4, height: '100%', backgroundColor: '#02677D' }} />
  192. // <View>
  193. // <View className="flex-row items-center">
  194. // <Text className="text-lg text-[#02677D]">預設車輛</Text>
  195. // <GreenStarSvg />
  196. // </View>
  197. // <Text className="text-2xl">{defaultCar.car_type.name}</Text>
  198. // <Text className="text-lg text-[#888888]">{defaultCar.license_plate}</Text>
  199. // </View>
  200. // </View>
  201. // )}
  202. // <View className="w-full h-1 my-4 bg-[#DBE4E8]" />
  203. // <Text className="text-xl mb-4">其他車輛</Text>
  204. // {otherVehicles.map((car) => (
  205. // <VehicleRow
  206. // key={car.id}
  207. // car={car}
  208. // deviceHeight={deviceHeight}
  209. // deviceWidth={deviceWidth}
  210. // onPress={() =>
  211. // router.push({
  212. // pathname: 'manageVehiclePage',
  213. // params: {
  214. // carID: car.id,
  215. // capacitance: car.car_type.capacitance,
  216. // capacitance_unit: car.car_type.capacitance_unit,
  217. // createdAt: car.car_type.createdAt,
  218. // carModel: car.car_type.name,
  219. // licensePlate: car.license_plate,
  220. // carImage: car.processedImageUrl
  221. // }
  222. // })
  223. // }
  224. // />
  225. // ))}
  226. // <NormalButton
  227. // title={<Text style={{ fontWeight: '700', fontSize: 20, color: '#fff' }}>新增車輛</Text>}
  228. // onPress={() => router.push('addVehiclePage')}
  229. // />
  230. // </>
  231. // )}
  232. // </ScrollView>
  233. // </SafeAreaView>
  234. );
  235. };
  236. export default MyVehiclePageComponent;
  237. function repeat(arg0: string, arg1: number): any {
  238. throw new Error('Function not implemented.');
  239. }