myVehiclePageComponent.tsx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  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. console.log('processedUrl', processedUrl);
  64. updatedVehicles[i] = {
  65. ...car,
  66. processedImageUrl: processedUrl
  67. };
  68. }
  69. setVehicles(updatedVehicles);
  70. //all car data
  71. //find default from all car data
  72. const defaultCarId = userInfoResult.data.defaultCar.id;
  73. const defaultCar = updatedVehicles.find((car) => car.id === defaultCarId);
  74. setDefaultCar(defaultCar);
  75. //find processed Image urls
  76. } catch (error) {
  77. console.error('Error fetching data:', error);
  78. } finally {
  79. setIsLoading(false);
  80. }
  81. }, []);
  82. function repeat(char, times) {
  83. return new Array(times + 1).join(char);
  84. }
  85. // Use the function
  86. useEffect(() => {
  87. fetchData();
  88. }, [fetchData]);
  89. const otherVehicles = vehicles.filter((car) => car.id !== defaultCar?.id);
  90. // console.log(repeat('-', 50));
  91. // console.log(otherVehicles);
  92. return (
  93. <SafeAreaView className="flex-1 bg-white" edges={['top', 'right', 'left']}>
  94. <ScrollView showsVerticalScrollIndicator={false} className="flex-1 mx-[5%]">
  95. {isLoading ? (
  96. <View className="flex flex-col justify-center items-center h-screen">
  97. <ActivityIndicator />
  98. </View>
  99. ) : (
  100. <>
  101. <View style={{ marginTop: 25 }}>
  102. <Pressable
  103. className="self-start"
  104. onPress={() =>
  105. router.canGoBack() ? router.back() : router.replace('/accountMainPage')
  106. }
  107. >
  108. <CrossLogoSvg />
  109. </Pressable>
  110. <Text style={{ fontSize: 45, marginTop: 25, marginBottom: 10 }}>我的車輛</Text>
  111. </View>
  112. <View className="items-center">
  113. <Image
  114. source={require('../../assets/car.png')}
  115. // source={{ uri: defaultCar?.processedImageUrl }}
  116. resizeMode="contain"
  117. style={{ width: deviceWidth * 0.8, height: deviceHeight * 0.25 }}
  118. />
  119. </View>
  120. {defaultCar && (
  121. <View className="flex-row space-x-2">
  122. <View style={{ width: 4, height: '100%', backgroundColor: '#02677D' }} />
  123. <View>
  124. <View className="flex-row items-center">
  125. <Text className="text-lg text-[#02677D]">預設車輛</Text>
  126. <GreenStarSvg />
  127. </View>
  128. <Text className="text-2xl">{defaultCar.car_type.name}</Text>
  129. <Text className="text-lg text-[#888888]">{defaultCar.license_plate}</Text>
  130. </View>
  131. </View>
  132. )}
  133. <View className="w-full h-1 my-4 bg-[#DBE4E8]" />
  134. <Text className="text-xl mb-4">其他車輛</Text>
  135. {otherVehicles.map((car) => (
  136. <VehicleRow
  137. key={car.id}
  138. car={car}
  139. deviceHeight={deviceHeight}
  140. deviceWidth={deviceWidth}
  141. onPress={() =>
  142. router.push({
  143. pathname: 'manageVehiclePage',
  144. params: {
  145. carID: car.id,
  146. capacitance: car.car_type.capacitance,
  147. capacitance_unit: car.car_type.capacitance_unit,
  148. createdAt: car.car_type.createdAt,
  149. carModel: car.car_type.name,
  150. licensePlate: car.license_plate,
  151. carImage: car.processedImageUrl
  152. }
  153. })
  154. }
  155. />
  156. ))}
  157. <NormalButton
  158. title={<Text style={{ fontWeight: '700', fontSize: 20, color: '#fff' }}>新增車輛</Text>}
  159. onPress={() => router.push('addVehiclePage')}
  160. />
  161. </>
  162. )}
  163. </ScrollView>
  164. </SafeAreaView>
  165. // <SafeAreaView className="flex-1 bg-white" edges={['top', 'right', 'left']}>
  166. // <ScrollView showsVerticalScrollIndicator={false} className="flex-1 mx-[5%]">
  167. // <View style={{ marginTop: 25 }}>
  168. // <Pressable
  169. // className="self-start"
  170. // onPress={() => (router.canGoBack() ? router.back() : router.replace('/accountMainPage'))}
  171. // >
  172. // <CrossLogoSvg />
  173. // </Pressable>
  174. // <Text style={{ fontSize: 45, marginTop: 25, marginBottom: 10 }}>我的車輛</Text>
  175. // </View>
  176. // {isLoading ? (
  177. // <View className="flex flex-col justify-center items-center h-full ">
  178. // <ActivityIndicator />
  179. // </View>
  180. // ) : (
  181. // <>
  182. // <View className="items-center">
  183. // <Image
  184. // source={require('../../assets/car.png')}
  185. // // source={{ uri: defaultCar?.processedImageUrl }}
  186. // resizeMode="contain"
  187. // style={{ width: deviceWidth * 0.8, height: deviceHeight * 0.25 }}
  188. // />
  189. // </View>
  190. // {defaultCar && (
  191. // <View className="flex-row space-x-2">
  192. // <View style={{ width: 4, height: '100%', backgroundColor: '#02677D' }} />
  193. // <View>
  194. // <View className="flex-row items-center">
  195. // <Text className="text-lg text-[#02677D]">預設車輛</Text>
  196. // <GreenStarSvg />
  197. // </View>
  198. // <Text className="text-2xl">{defaultCar.car_type.name}</Text>
  199. // <Text className="text-lg text-[#888888]">{defaultCar.license_plate}</Text>
  200. // </View>
  201. // </View>
  202. // )}
  203. // <View className="w-full h-1 my-4 bg-[#DBE4E8]" />
  204. // <Text className="text-xl mb-4">其他車輛</Text>
  205. // {otherVehicles.map((car) => (
  206. // <VehicleRow
  207. // key={car.id}
  208. // car={car}
  209. // deviceHeight={deviceHeight}
  210. // deviceWidth={deviceWidth}
  211. // onPress={() =>
  212. // router.push({
  213. // pathname: 'manageVehiclePage',
  214. // params: {
  215. // carID: car.id,
  216. // capacitance: car.car_type.capacitance,
  217. // capacitance_unit: car.car_type.capacitance_unit,
  218. // createdAt: car.car_type.createdAt,
  219. // carModel: car.car_type.name,
  220. // licensePlate: car.license_plate,
  221. // carImage: car.processedImageUrl
  222. // }
  223. // })
  224. // }
  225. // />
  226. // ))}
  227. // <NormalButton
  228. // title={<Text style={{ fontWeight: '700', fontSize: 20, color: '#fff' }}>新增車輛</Text>}
  229. // onPress={() => router.push('addVehiclePage')}
  230. // />
  231. // </>
  232. // )}
  233. // </ScrollView>
  234. // </SafeAreaView>
  235. );
  236. };
  237. export default MyVehiclePageComponent;
  238. function repeat(arg0: string, arg1: number): any {
  239. throw new Error('Function not implemented.');
  240. }