registerChooseVehiclesOne.tsx 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. import React, { useEffect, useState } from 'react';
  2. import { View, Text, Image, Pressable, StyleSheet, ScrollView, ActivityIndicator } from 'react-native';
  3. import { FlashList } from '@shopify/flash-list';
  4. import { router } from 'expo-router';
  5. import { SafeAreaView } from 'react-native-safe-area-context';
  6. import useVehicleStore from '../../providers/vehicle_store';
  7. import { chargeStationService } from '../../service/chargeStationService';
  8. import { PreviousPageBlackSvg } from '../../component/global/SVG';
  9. interface AlphabetSection {
  10. letter: string;
  11. brands: CarBrand[];
  12. }
  13. interface CarBrand {
  14. id: number;
  15. name: string;
  16. img_url: string;
  17. car_types: any[];
  18. }
  19. const brandLogos = {
  20. audi: require('../../assets/audi.png'),
  21. benz: require('../../assets/benz.png'),
  22. bmw: require('../../assets/bmw.png'),
  23. byd: require('../../assets/byd.png'),
  24. lexus: require('../../assets/lexus.png'),
  25. mg: require('../../assets/mg.png'),
  26. porsche: require('../../assets/porsche.png'),
  27. tesla: require('../../assets/tesla.png'),
  28. toyota: require('../../assets/toyota.png'),
  29. xiaomi: require('../../assets/xiaomi.png')
  30. // Add all other brands here
  31. };
  32. const RegisterChooseVehiclesOne = () => {
  33. const [loading, setLoading] = useState(true);
  34. const [processedCarData, setProcessedCarData] = useState<CarBrand[]>([]);
  35. const { vehicleBrand, vehicleModel, BrandID, ModelID, setVehicleBrand, setBrandID } = useVehicleStore();
  36. useEffect(() => {
  37. const fetchCarBrand = async () => {
  38. try {
  39. const response = await chargeStationService.fetchCarBrand();
  40. if (response) {
  41. setProcessedCarData(response.data);
  42. }
  43. } catch (error) {
  44. console.log(error);
  45. } finally {
  46. setLoading(false);
  47. }
  48. };
  49. fetchCarBrand();
  50. }, []);
  51. useEffect(() => {
  52. console.log('Zustand VehicleBrand', vehicleBrand);
  53. console.log('Zustand BrandID', BrandID);
  54. console.log('Zustand VehicleModel', vehicleModel);
  55. console.log('Zustand ModelID', ModelID);
  56. }, [processedCarData]);
  57. const renderBrandItem = ({ item: brand }: { item: CarBrand }) => (
  58. <Pressable
  59. key={brand.id}
  60. style={styles.brandItem}
  61. onPress={() => {
  62. setVehicleBrand(brand.name);
  63. setBrandID(brand.id);
  64. router.push({
  65. pathname: 'registerChooseVehiclesTwo',
  66. params: {
  67. brandId: brand.id.toString(),
  68. brandName: brand.name,
  69. carTypes: JSON.stringify(brand.car_types)
  70. }
  71. });
  72. }}
  73. >
  74. <Image source={brandLogos[brand.name.toLowerCase()]} style={styles.logo} resizeMode="contain" />
  75. <Text style={styles.brandName}>{brand.name}</Text>
  76. </Pressable>
  77. );
  78. const renderAlphabetSection = ({ item: section }: { item: AlphabetSection }) => (
  79. <View>
  80. <View style={styles.letterHeader} className="h-9">
  81. <Text style={styles.letterText}>{section.letter}</Text>
  82. </View>
  83. <View style={styles.brandRow}>{section.brands.map((brand) => renderBrandItem({ item: brand }))}</View>
  84. </View>
  85. );
  86. return (
  87. <SafeAreaView className="flex-1 bg-white" edges={['top', 'right', 'left']}>
  88. <ScrollView showsVerticalScrollIndicator={false} className="flex-1 mx-[5%]">
  89. <View style={{ marginTop: 25 }}>
  90. <Pressable
  91. className="self-start"
  92. onPress={() => {
  93. if (router.canGoBack()) {
  94. router.back();
  95. } else {
  96. router.replace('/accountMainPage');
  97. }
  98. }}
  99. >
  100. <PreviousPageBlackSvg />
  101. </Pressable>
  102. <Text
  103. style={{
  104. fontSize: 30,
  105. marginTop: 25,
  106. marginBottom: 10
  107. }}
  108. >
  109. 選擇品牌
  110. </Text>
  111. </View>
  112. {loading ? (
  113. <View className="flex h-full items-center justify-center">
  114. <ActivityIndicator />
  115. </View>
  116. ) : (
  117. <View className="flex-1 min-h-[80vh]">
  118. <FlashList
  119. estimatedItemSize={100}
  120. data={processedCarData
  121. .sort((a, b) => a.name.localeCompare(b.name))
  122. .reduce((acc, brand) => {
  123. const letter = brand.name[0].toUpperCase();
  124. const existingSection = acc.find((section) => section.letter === letter);
  125. if (existingSection) {
  126. existingSection.brands.push(brand);
  127. } else {
  128. acc.push({ letter, brands: [brand] });
  129. }
  130. return acc;
  131. }, [] as AlphabetSection[])}
  132. renderItem={renderAlphabetSection}
  133. keyExtractor={(item) => item.letter}
  134. />
  135. </View>
  136. )}
  137. </ScrollView>
  138. </SafeAreaView>
  139. );
  140. };
  141. const styles = StyleSheet.create({
  142. letterHeader: {
  143. backgroundColor: '#E3F2F8',
  144. padding: 10,
  145. marginVertical: 10
  146. },
  147. letterText: {
  148. color: '#02677D',
  149. fontSize: 14,
  150. fontWeight: 'bold'
  151. },
  152. brandRow: {
  153. flexDirection: 'row',
  154. flexWrap: 'wrap'
  155. },
  156. brandItem: {
  157. width: '33.33%',
  158. alignItems: 'center',
  159. padding: 10
  160. },
  161. logo: {
  162. width: 80,
  163. height: 80
  164. },
  165. brandName: {
  166. marginTop: 5,
  167. textAlign: 'center'
  168. }
  169. });
  170. export default RegisterChooseVehiclesOne;
  171. // interface AlphabetSection {
  172. // letter: string;
  173. // brands: CarBrand[];
  174. // }
  175. // import React, { useEffect, useState } from 'react';
  176. // import { View, Text, Image, Pressable, StyleSheet, ScrollView, ActivityIndicator } from 'react-native';
  177. // import { FlashList } from '@shopify/flash-list';
  178. // import { router } from 'expo-router';
  179. // import { SafeAreaView } from 'react-native-safe-area-context';
  180. // import useVehicleStore from '../../providers/vehicle_store';
  181. // import { chargeStationService } from '../../service/chargeStationService';
  182. // import { PreviousPageBlackSvg } from '../../component/global/SVG';
  183. // const RegisterChooseVehiclesOne = () => {
  184. // const [loading, setLoading] = useState(true);
  185. // const [carData, setCarData] = useState();
  186. // const [extractedCarNameAndImgUrl, setExtractedCarNameAndImgUrl] = useState('');
  187. // const [processedCarData, setProcessedCarData] = useState([]);
  188. // const {
  189. // vehicleBrand,
  190. // vehicleModel,
  191. // BrandID,
  192. // ModelID,
  193. // licensePlate,
  194. // setVehicleBrand,
  195. // setVehicleModel,
  196. // setBrandID,
  197. // setModelID,
  198. // setLicensePlate
  199. // } = useVehicleStore();
  200. // //this uses getCarBrand to create an array of object with 2 keys: name and img_url
  201. // useEffect(() => {
  202. // const fetchCarBrand = async () => {
  203. // try {
  204. // const response = await chargeStationService.fetchCarBrand();
  205. // if (response) {
  206. // const processedData = await Promise.all(
  207. // response.data.map(async (car) => ({
  208. // ...car,
  209. // logo: await chargeStationService.getProcessedCarImageUrl(car.img_url)
  210. // }))
  211. // );
  212. // setProcessedCarData(processedData);
  213. // }
  214. // } catch (error) {
  215. // console.log(error);
  216. // } finally {
  217. // setLoading(false);
  218. // }
  219. // };
  220. // fetchCarBrand();
  221. // }, []);
  222. // useEffect(() => {
  223. // console.log('Zustand VehicleBrand', vehicleBrand);
  224. // console.log('Zustand BrandID', BrandID);
  225. // console.log('Zustand VehicleModel', vehicleModel);
  226. // console.log('Zustand ModelID', ModelID);
  227. // }, [processedCarData]);
  228. // const renderBrandItem = ({ item: brand }: { item }) => (
  229. // <Pressable
  230. // key={brand.id}
  231. // style={styles.brandItem}
  232. // onPress={() => {
  233. // setVehicleBrand(brand.name);
  234. // setBrandID(brand.id);
  235. // router.push({
  236. // pathname: 'registerChooseVehiclesTwo',
  237. // params: {
  238. // brandId: brand.id.toString(),
  239. // brandName: brand.name,
  240. // carTypes: JSON.stringify(brand.car_types)
  241. // }
  242. // });
  243. // }}
  244. // >
  245. // <Image source={{ uri: brand.logo }} style={styles.logo} resizeMode="contain" />
  246. // <Text style={styles.brandName}>{brand.name}</Text>
  247. // </Pressable>
  248. // );
  249. // const renderAlphabetSection = ({ item: section }: { item: AlphabetSection }) => (
  250. // <View>
  251. // <View style={styles.letterHeader} className="h-9">
  252. // <Text style={styles.letterText}>{section.letter}</Text>
  253. // </View>
  254. // <View style={styles.brandRow}>{section.brands.map((brand) => renderBrandItem({ item: brand }))}</View>
  255. // </View>
  256. // );
  257. // return (
  258. // <SafeAreaView className="flex-1 bg-white" edges={['top', 'right', 'left']}>
  259. // <ScrollView showsVerticalScrollIndicator={false} className="flex-1 mx-[5%]">
  260. // <View style={{ marginTop: 25 }}>
  261. // <Pressable
  262. // className="self-start"
  263. // onPress={() => {
  264. // if (router.canGoBack()) {
  265. // router.back();
  266. // } else {
  267. // router.replace('/accountMainPage');
  268. // }
  269. // }}
  270. // >
  271. // <PreviousPageBlackSvg />
  272. // </Pressable>
  273. // <Text
  274. // style={{
  275. // fontSize: 30,
  276. // marginTop: 25,
  277. // marginBottom: 10
  278. // }}
  279. // >
  280. // 選擇品牌
  281. // </Text>
  282. // </View>
  283. // {loading ? (
  284. // <View className="flex h-full items-center justify-center">
  285. // <ActivityIndicator />
  286. // </View>
  287. // ) : (
  288. // <View className="flex-1 min-h-[80vh]">
  289. // <FlashList
  290. // estimatedItemSize={100}
  291. // data={processedCarData
  292. // .sort((a, b) => a.name.localeCompare(b.name))
  293. // .reduce((acc, brand) => {
  294. // const letter = brand.name[0].toUpperCase();
  295. // const existingSection = acc.find((section) => section.letter === letter);
  296. // if (existingSection) {
  297. // existingSection.brands.push(brand);
  298. // } else {
  299. // acc.push({ letter, brands: [brand] });
  300. // }
  301. // return acc;
  302. // }, [] as AlphabetSection[])}
  303. // renderItem={renderAlphabetSection}
  304. // keyExtractor={(item) => item.letter}
  305. // />
  306. // </View>
  307. // )}
  308. // {/*
  309. // <View className="flex-1 min-h-[80vh]">
  310. // <FlashList
  311. // estimatedItemSize={100}
  312. // data={processedCarData.reduce((acc, brand) => {
  313. // const letter = brand.name[0].toUpperCase();
  314. // const existingSection = acc.find((section) => section.letter === letter);
  315. // if (existingSection) {
  316. // existingSection.brands.push(brand);
  317. // } else {
  318. // acc.push({ letter, brands: [brand] });
  319. // }
  320. // return acc;
  321. // }, [] as AlphabetSection[])}
  322. // renderItem={renderAlphabetSection}
  323. // keyExtractor={(item) => item.letter}
  324. // />
  325. // </View> */}
  326. // </ScrollView>
  327. // </SafeAreaView>
  328. // );
  329. // };
  330. // const styles = StyleSheet.create({
  331. // letterHeader: {
  332. // backgroundColor: '#E3F2F8',
  333. // padding: 10,
  334. // marginVertical: 10
  335. // },
  336. // letterText: {
  337. // color: '#02677D',
  338. // fontSize: 14,
  339. // fontWeight: 'bold'
  340. // },
  341. // brandRow: {
  342. // flexDirection: 'row',
  343. // flexWrap: 'wrap'
  344. // },
  345. // brandItem: {
  346. // width: '33.33%',
  347. // alignItems: 'center',
  348. // padding: 10
  349. // },
  350. // logo: {
  351. // width: 80,
  352. // height: 80
  353. // },
  354. // brandName: {
  355. // marginTop: 5,
  356. // textAlign: 'center'
  357. // }
  358. // });
  359. // export default RegisterChooseVehiclesOne;