setVehiclesOne.tsx 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. interface AlphabetSection {
  2. letter: string;
  3. brands: CarBrand[];
  4. }
  5. const carBrands: AlphabetSection[] = [
  6. {
  7. letter: 'A',
  8. brands: [
  9. { name: 'Audi', logo: require('../../../../../assets/audi.png') },
  10. { name: 'Acura', logo: require('../../../../../assets/acura.png') }
  11. ]
  12. },
  13. {
  14. letter: 'B',
  15. brands: [
  16. { name: 'BMW', logo: require('../../../../../assets/bmw.png') },
  17. { name: 'BYD', logo: require('../../../../../assets/byd.png') }
  18. ]
  19. },
  20. {
  21. letter: 'C',
  22. brands: [
  23. { name: 'Chevrolet', logo: require('../../../../../assets/chevrolet.png') },
  24. { name: 'Cadillac', logo: require('../../../../../assets/cadillac.png') }
  25. ]
  26. },
  27. {
  28. letter: 'F',
  29. brands: [
  30. { name: 'Ford', logo: require('../../../../../assets/ford.png') },
  31. { name: 'Fiat', logo: require('../../../../../assets/fiat.png') }
  32. ]
  33. },
  34. {
  35. letter: 'G',
  36. brands: [{ name: 'Genesis', logo: require('../../../../../assets/genesis.png') }]
  37. },
  38. {
  39. letter: 'H',
  40. brands: [
  41. { name: 'Honda', logo: require('../../../../../assets/honda.png') },
  42. { name: 'Hyundai', logo: require('../../../../../assets/hyundai.png') }
  43. ]
  44. },
  45. {
  46. letter: 'J',
  47. brands: [{ name: 'Jaguar', logo: require('../../../../../assets/jaguar.png') }]
  48. },
  49. {
  50. letter: 'K',
  51. brands: [{ name: 'Kia', logo: require('../../../../../assets/kia.png') }]
  52. },
  53. {
  54. letter: 'M',
  55. brands: [
  56. { name: 'Mercedes-Benz', logo: require('../../../../../assets/benz.png') },
  57. { name: 'Mini', logo: require('../../../../../assets/mini.png') },
  58. { name: 'Mazda', logo: require('../../../../../assets/mazda.png') }
  59. ]
  60. },
  61. {
  62. letter: 'N',
  63. brands: [{ name: 'Nissan', logo: require('../../../../../assets/nissan.png') }]
  64. },
  65. {
  66. letter: 'P',
  67. brands: [{ name: 'Porsche', logo: require('../../../../../assets/porsche.png') }]
  68. },
  69. {
  70. letter: 'S',
  71. brands: [{ name: 'Subaru', logo: require('../../../../../assets/subaru.png') }]
  72. },
  73. {
  74. letter: 'T',
  75. brands: [
  76. { name: 'Tesla', logo: require('../../../../../assets/tesla.png') },
  77. { name: 'Toyota', logo: require('../../../../../assets/toyota.png') }
  78. ]
  79. },
  80. {
  81. letter: 'V',
  82. brands: [
  83. { name: 'Volkswagen', logo: require('../../../../../assets/volkswagen.png') },
  84. { name: 'Volvo', logo: require('../../../../../assets/volvo.png') }
  85. ]
  86. }
  87. ];
  88. import React, { useEffect, useState } from 'react';
  89. import { View, Text, Image, Pressable, StyleSheet, ScrollView } from 'react-native';
  90. import { FlashList } from '@shopify/flash-list';
  91. import { router } from 'expo-router';
  92. import useVehicleStore from '../../../../../providers/vehicle_store';
  93. import { PreviousPageBlackSvg } from '../../../../../component/global/SVG';
  94. import { SafeAreaView } from 'react-native-safe-area-context';
  95. import { chargeStationService } from '../../../../../service/chargeStationService';
  96. const SetVehiclesOne = () => {
  97. const [carData, setCarData] = useState();
  98. const [extractedCarNameAndImgUrl, setExtractedCarNameAndImgUrl] = useState('');
  99. const [processedCarData, setProcessedCarData] = useState([]);
  100. const {
  101. vehicleBrand,
  102. vehicleModel,
  103. BrandID,
  104. ModelID,
  105. licensePlate,
  106. setVehicleBrand,
  107. setVehicleModel,
  108. setBrandID,
  109. setModelID,
  110. setLicensePlate
  111. } = useVehicleStore();
  112. //this uses getCarBrand to create an array of object with 2 keys: name and img_url
  113. useEffect(() => {
  114. const fetchCarBrand = async () => {
  115. try {
  116. const response = await chargeStationService.fetchCarBrand();
  117. if (response) {
  118. const processedData = await Promise.all(
  119. response.data.map(async (car) => ({
  120. ...car,
  121. logo: await chargeStationService.getProcessedCarImageUrl(car.img_url)
  122. }))
  123. );
  124. setProcessedCarData(processedData);
  125. }
  126. } catch (error) {
  127. console.log(error);
  128. }
  129. };
  130. fetchCarBrand();
  131. }, []);
  132. useEffect(() => {
  133. console.log('Zustand VehicleBrand', vehicleBrand);
  134. console.log('Zustand BrandID', BrandID);
  135. console.log('Zustand VehicleModel', vehicleModel);
  136. console.log('Zustand ModelID', ModelID);
  137. }, [processedCarData]);
  138. const renderBrandItem = ({ item: brand }: { item }) => (
  139. <Pressable
  140. style={styles.brandItem}
  141. onPress={() => {
  142. setVehicleBrand(brand.name);
  143. setBrandID(brand.id);
  144. router.push({
  145. pathname: 'setVehiclesTwo',
  146. params: {
  147. brandId: brand.id.toString(),
  148. brandName: brand.name,
  149. carTypes: JSON.stringify(brand.car_types)
  150. }
  151. });
  152. }}
  153. >
  154. <Image source={{ uri: brand.logo }} style={styles.logo} resizeMode="contain" />
  155. <Text style={styles.brandName}>{brand.name}</Text>
  156. </Pressable>
  157. );
  158. const renderAlphabetSection = ({ item: section }: { item: AlphabetSection }) => (
  159. <View>
  160. <View style={styles.letterHeader} className="h-9">
  161. <Text style={styles.letterText}>{section.letter}</Text>
  162. </View>
  163. <View style={styles.brandRow}>{section.brands.map((brand) => renderBrandItem({ item: brand }))}</View>
  164. </View>
  165. );
  166. return (
  167. <SafeAreaView className="flex-1 bg-white" edges={['top', 'right', 'left']}>
  168. <ScrollView showsVerticalScrollIndicator={false} className="flex-1 mx-[5%]">
  169. <View style={{ marginTop: 25 }}>
  170. <Pressable
  171. className="self-start"
  172. onPress={() => {
  173. if (router.canGoBack()) {
  174. router.back();
  175. } else {
  176. router.replace('/accountMainPage');
  177. }
  178. }}
  179. >
  180. <PreviousPageBlackSvg />
  181. </Pressable>
  182. <Text
  183. style={{
  184. fontSize: 30,
  185. marginTop: 25,
  186. marginBottom: 10
  187. }}
  188. >
  189. 選擇品牌
  190. </Text>
  191. </View>
  192. <View className="flex-1">
  193. <FlashList
  194. estimatedItemSize={100}
  195. data={processedCarData.reduce((acc, brand) => {
  196. const letter = brand.name[0].toUpperCase();
  197. const existingSection = acc.find((section) => section.letter === letter);
  198. if (existingSection) {
  199. existingSection.brands.push(brand);
  200. } else {
  201. acc.push({ letter, brands: [brand] });
  202. }
  203. return acc;
  204. }, [] as AlphabetSection[])}
  205. renderItem={renderAlphabetSection}
  206. keyExtractor={(item) => item.letter}
  207. />
  208. </View>
  209. </ScrollView>
  210. </SafeAreaView>
  211. );
  212. };
  213. const styles = StyleSheet.create({
  214. letterHeader: {
  215. backgroundColor: '#E3F2F8',
  216. padding: 10,
  217. marginVertical: 10
  218. },
  219. letterText: {
  220. color: '#02677D',
  221. fontSize: 14,
  222. fontWeight: 'bold'
  223. },
  224. brandRow: {
  225. flexDirection: 'row',
  226. flexWrap: 'wrap'
  227. },
  228. brandItem: {
  229. width: '33.33%',
  230. alignItems: 'center',
  231. padding: 10
  232. },
  233. logo: {
  234. width: 80,
  235. height: 80
  236. },
  237. brandName: {
  238. marginTop: 5,
  239. textAlign: 'center'
  240. }
  241. });
  242. export default SetVehiclesOne;