myVehiclePageComponent.tsx 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  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={{
  30. uri: car.processedImageUrl || 'https://via.placeholder.com/150'
  31. }}
  32. />
  33. <View className="flex-row items-center">
  34. <View className="flex-1 flex-col pl-2">
  35. <Text style={{ fontSize: 22, fontWeight: '600' }}>{car.car_brand.name}</Text>
  36. <Text style={{ fontSize: 18 }}>{truncateText(car.car_type.name, 10)}</Text>
  37. <Text style={{ fontSize: 16, color: '#02677D' }}>{car.license_plate}</Text>
  38. </View>
  39. <View className="flex-1">
  40. <RightArrowIconSvg />
  41. </View>
  42. </View>
  43. </View>
  44. <View className="border-t mx-4 border-[#CCCCCC]"></View>
  45. </Pressable>
  46. );
  47. const MyVehiclePageComponent = () => {
  48. const { height: deviceHeight, width: deviceWidth } = Dimensions.get('window');
  49. const [vehicles, setVehicles] = useState([]);
  50. const [defaultCar, setDefaultCar] = useState(null);
  51. const [processedUrls, setProcessedUrls] = useState({});
  52. const [isLoading, setIsLoading] = useState(false);
  53. const fetchData = useCallback(async () => {
  54. setIsLoading(true);
  55. try {
  56. const [carsResult, userInfoResult] = await Promise.all([
  57. chargeStationService.getUserCars(),
  58. authenticationService.getUserInfo()
  59. ]);
  60. let updatedVehicles = [...carsResult.data];
  61. for (let i = 0; i < updatedVehicles.length; i++) {
  62. const car = updatedVehicles[i];
  63. const processedUrl = await chargeStationService.getProcessedImageUrl(car.car_type.type_image_url);
  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. <View style={{ marginTop: 25 }}>
  96. <Pressable
  97. className="self-start"
  98. onPress={() => (router.canGoBack() ? router.back() : router.replace('/accountMainPage'))}
  99. >
  100. <CrossLogoSvg />
  101. </Pressable>
  102. <Text style={{ fontSize: 45, marginTop: 25, marginBottom: 10 }}>我的車輛</Text>
  103. </View>
  104. {isLoading ? (
  105. <View className="flex flex-col justify-center items-center h-full ">
  106. <ActivityIndicator />
  107. </View>
  108. ) : (
  109. <>
  110. <View className="items-center">
  111. <Image
  112. // source={require('../../assets/car.png')}
  113. source={{ uri: defaultCar?.processedImageUrl }}
  114. resizeMode="contain"
  115. style={{ width: deviceWidth * 0.8, height: deviceHeight * 0.25 }}
  116. />
  117. </View>
  118. {defaultCar && (
  119. <View className="flex-row space-x-2">
  120. <View style={{ width: 4, height: '100%', backgroundColor: '#02677D' }} />
  121. <View>
  122. <View className="flex-row items-center">
  123. <Text className="text-lg text-[#02677D]">預設車輛</Text>
  124. <GreenStarSvg />
  125. </View>
  126. <Text className="text-2xl">{defaultCar.car_type.name}</Text>
  127. <Text className="text-lg text-[#888888]">{defaultCar.license_plate}</Text>
  128. </View>
  129. </View>
  130. )}
  131. <View className="w-full h-1 my-4 bg-[#DBE4E8]" />
  132. <Text className="text-xl mb-4">其他車輛</Text>
  133. {otherVehicles.map((car) => (
  134. <VehicleRow
  135. key={car.id}
  136. car={car}
  137. deviceHeight={deviceHeight}
  138. deviceWidth={deviceWidth}
  139. onPress={() =>
  140. router.push({
  141. pathname: 'manageVehiclePage',
  142. params: {
  143. carID: car.id,
  144. capacitance: car.car_type.capacitance,
  145. capacitance_unit: car.car_type.capacitance_unit,
  146. createdAt: car.car_type.createdAt,
  147. carModel: car.car_type.name,
  148. licensePlate: car.license_plate,
  149. carImage: car.processedImageUrl
  150. }
  151. })
  152. }
  153. />
  154. ))}
  155. <NormalButton
  156. title={<Text style={{ fontWeight: '700', fontSize: 20, color: '#fff' }}>新增車輛</Text>}
  157. onPress={() => router.push('addVehiclePage')}
  158. />
  159. </>
  160. )}
  161. </ScrollView>
  162. </SafeAreaView>
  163. );
  164. };
  165. export default MyVehiclePageComponent;
  166. function repeat(arg0: string, arg1: number): any {
  167. throw new Error('Function not implemented.');
  168. }