registerChooseVehiclesOne.tsx 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. interface AlphabetSection {
  2. letter: string;
  3. brands: CarBrand[];
  4. }
  5. import React, { useEffect, useState } from 'react';
  6. import { View, Text, Image, Pressable, StyleSheet, ScrollView, ActivityIndicator } from 'react-native';
  7. import { FlashList } from '@shopify/flash-list';
  8. import { router } from 'expo-router';
  9. import { SafeAreaView } from 'react-native-safe-area-context';
  10. import useVehicleStore from '../../providers/vehicle_store';
  11. import { chargeStationService } from '../../service/chargeStationService';
  12. import { PreviousPageBlackSvg } from '../../component/global/SVG';
  13. const RegisterChooseVehiclesOne = () => {
  14. const [loading, setLoading] = useState(true);
  15. const [carData, setCarData] = useState();
  16. const [extractedCarNameAndImgUrl, setExtractedCarNameAndImgUrl] = useState('');
  17. const [processedCarData, setProcessedCarData] = useState([]);
  18. const {
  19. vehicleBrand,
  20. vehicleModel,
  21. BrandID,
  22. ModelID,
  23. licensePlate,
  24. setVehicleBrand,
  25. setVehicleModel,
  26. setBrandID,
  27. setModelID,
  28. setLicensePlate
  29. } = useVehicleStore();
  30. //this uses getCarBrand to create an array of object with 2 keys: name and img_url
  31. useEffect(() => {
  32. const fetchCarBrand = async () => {
  33. try {
  34. const response = await chargeStationService.fetchCarBrand();
  35. if (response) {
  36. const processedData = await Promise.all(
  37. response.data.map(async (car) => ({
  38. ...car,
  39. logo: await chargeStationService.getProcessedCarImageUrl(car.img_url)
  40. }))
  41. );
  42. setProcessedCarData(processedData);
  43. }
  44. } catch (error) {
  45. console.log(error);
  46. } finally {
  47. setLoading(false);
  48. }
  49. };
  50. fetchCarBrand();
  51. }, []);
  52. useEffect(() => {
  53. console.log('Zustand VehicleBrand', vehicleBrand);
  54. console.log('Zustand BrandID', BrandID);
  55. console.log('Zustand VehicleModel', vehicleModel);
  56. console.log('Zustand ModelID', ModelID);
  57. }, [processedCarData]);
  58. const renderBrandItem = ({ item: brand }: { item }) => (
  59. <Pressable
  60. key={brand.id}
  61. style={styles.brandItem}
  62. onPress={() => {
  63. setVehicleBrand(brand.name);
  64. setBrandID(brand.id);
  65. router.push({
  66. pathname: 'registerChooseVehiclesTwo',
  67. params: {
  68. brandId: brand.id.toString(),
  69. brandName: brand.name,
  70. carTypes: JSON.stringify(brand.car_types)
  71. }
  72. });
  73. }}
  74. >
  75. <Image source={{ uri: brand.logo }} style={styles.logo} resizeMode="contain" />
  76. <Text style={styles.brandName}>{brand.name}</Text>
  77. </Pressable>
  78. );
  79. const renderAlphabetSection = ({ item: section }: { item: AlphabetSection }) => (
  80. <View>
  81. <View style={styles.letterHeader} className="h-9">
  82. <Text style={styles.letterText}>{section.letter}</Text>
  83. </View>
  84. <View style={styles.brandRow}>{section.brands.map((brand) => renderBrandItem({ item: brand }))}</View>
  85. </View>
  86. );
  87. return (
  88. <SafeAreaView className="flex-1 bg-white" edges={['top', 'right', 'left']}>
  89. <ScrollView showsVerticalScrollIndicator={false} className="flex-1 mx-[5%]">
  90. <View style={{ marginTop: 25 }}>
  91. <Pressable
  92. className="self-start"
  93. onPress={() => {
  94. if (router.canGoBack()) {
  95. router.back();
  96. } else {
  97. router.replace('/accountMainPage');
  98. }
  99. }}
  100. >
  101. <PreviousPageBlackSvg />
  102. </Pressable>
  103. <Text
  104. style={{
  105. fontSize: 30,
  106. marginTop: 25,
  107. marginBottom: 10
  108. }}
  109. >
  110. 選擇品牌
  111. </Text>
  112. </View>
  113. {loading ? (
  114. <View className="flex h-full items-center justify-center">
  115. <ActivityIndicator />
  116. </View>
  117. ) : (
  118. <View className="flex-1 min-h-[80vh]">
  119. <FlashList
  120. estimatedItemSize={100}
  121. data={processedCarData
  122. .sort((a, b) => a.name.localeCompare(b.name))
  123. .reduce((acc, brand) => {
  124. const letter = brand.name[0].toUpperCase();
  125. const existingSection = acc.find((section) => section.letter === letter);
  126. if (existingSection) {
  127. existingSection.brands.push(brand);
  128. } else {
  129. acc.push({ letter, brands: [brand] });
  130. }
  131. return acc;
  132. }, [] as AlphabetSection[])}
  133. renderItem={renderAlphabetSection}
  134. keyExtractor={(item) => item.letter}
  135. />
  136. </View>
  137. )}
  138. {/*
  139. <View className="flex-1 min-h-[80vh]">
  140. <FlashList
  141. estimatedItemSize={100}
  142. data={processedCarData.reduce((acc, brand) => {
  143. const letter = brand.name[0].toUpperCase();
  144. const existingSection = acc.find((section) => section.letter === letter);
  145. if (existingSection) {
  146. existingSection.brands.push(brand);
  147. } else {
  148. acc.push({ letter, brands: [brand] });
  149. }
  150. return acc;
  151. }, [] as AlphabetSection[])}
  152. renderItem={renderAlphabetSection}
  153. keyExtractor={(item) => item.letter}
  154. />
  155. </View> */}
  156. </ScrollView>
  157. </SafeAreaView>
  158. );
  159. };
  160. const styles = StyleSheet.create({
  161. letterHeader: {
  162. backgroundColor: '#E3F2F8',
  163. padding: 10,
  164. marginVertical: 10
  165. },
  166. letterText: {
  167. color: '#02677D',
  168. fontSize: 14,
  169. fontWeight: 'bold'
  170. },
  171. brandRow: {
  172. flexDirection: 'row',
  173. flexWrap: 'wrap'
  174. },
  175. brandItem: {
  176. width: '33.33%',
  177. alignItems: 'center',
  178. padding: 10
  179. },
  180. logo: {
  181. width: 80,
  182. height: 80
  183. },
  184. brandName: {
  185. marginTop: 5,
  186. textAlign: 'center'
  187. }
  188. });
  189. export default RegisterChooseVehiclesOne;