setVehiclesOne.tsx 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  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. };
  31. const SetVehiclesOne = () => {
  32. const [loading, setLoading] = useState(true);
  33. const [processedCarData, setProcessedCarData] = useState<CarBrand[]>([]);
  34. const { vehicleBrand, vehicleModel, BrandID, ModelID, setVehicleBrand, setBrandID } = useVehicleStore();
  35. useEffect(() => {
  36. const fetchCarBrand = async () => {
  37. try {
  38. const response = await chargeStationService.fetchCarBrand();
  39. if (response) {
  40. setProcessedCarData(response.data);
  41. console.log(
  42. 'All brand names:',
  43. response.data.map((brand) => brand.name)
  44. );
  45. }
  46. } catch (error) {
  47. console.log(error);
  48. } finally {
  49. setLoading(false);
  50. }
  51. };
  52. fetchCarBrand();
  53. }, []);
  54. useEffect(() => {
  55. console.log('Zustand VehicleBrand', vehicleBrand);
  56. console.log('Zustand BrandID', BrandID);
  57. console.log('Zustand VehicleModel', vehicleModel);
  58. console.log('Zustand ModelID', ModelID);
  59. }, [processedCarData]);
  60. const renderBrandItem = ({ item: brand }: { item: CarBrand }) => (
  61. <Pressable
  62. key={brand.id}
  63. style={styles.brandItem}
  64. onPress={() => {
  65. setVehicleBrand(brand.name);
  66. setBrandID(brand.id);
  67. router.push({
  68. pathname: 'setVehiclesTwo',
  69. params: {
  70. brandId: brand.id.toString(),
  71. brandName: brand.name,
  72. carTypes: JSON.stringify(brand.car_types)
  73. }
  74. });
  75. }}
  76. >
  77. <Image source={brandLogos[brand.name.toLowerCase()]} style={styles.logo} resizeMode="contain" />
  78. <Text style={styles.brandName}>{brand.name}</Text>
  79. </Pressable>
  80. );
  81. const renderAlphabetSection = ({ item: section }: { item: AlphabetSection }) => (
  82. <View>
  83. <View style={styles.letterHeader} className="h-9">
  84. <Text style={styles.letterText}>{section.letter}</Text>
  85. </View>
  86. <View style={styles.brandRow}>{section.brands.map((brand) => renderBrandItem({ item: brand }))}</View>
  87. </View>
  88. );
  89. return (
  90. <SafeAreaView className="flex-1 bg-white" edges={['top', 'right', 'left']}>
  91. <ScrollView showsVerticalScrollIndicator={false} className="flex-1 mx-[5%]">
  92. <View style={{ marginTop: 25 }}>
  93. <Pressable
  94. className="self-start"
  95. onPress={() => {
  96. if (router.canGoBack()) {
  97. router.back();
  98. } else {
  99. router.replace('/accountMainPage');
  100. }
  101. }}
  102. >
  103. <PreviousPageBlackSvg />
  104. </Pressable>
  105. <Text
  106. style={{
  107. fontSize: 30,
  108. marginTop: 25,
  109. marginBottom: 10
  110. }}
  111. >
  112. 選擇品牌
  113. </Text>
  114. </View>
  115. {loading ? (
  116. <View className="flex h-full items-center justify-center">
  117. <ActivityIndicator />
  118. </View>
  119. ) : (
  120. <View className="flex-1 min-h-[80vh]">
  121. <FlashList
  122. estimatedItemSize={100}
  123. data={processedCarData
  124. .sort((a, b) => a.name.localeCompare(b.name))
  125. .reduce((acc, brand) => {
  126. const letter = brand.name[0].toUpperCase();
  127. const existingSection = acc.find((section) => section.letter === letter);
  128. if (existingSection) {
  129. existingSection.brands.push(brand);
  130. } else {
  131. acc.push({ letter, brands: [brand] });
  132. }
  133. return acc;
  134. }, [] as AlphabetSection[])}
  135. renderItem={renderAlphabetSection}
  136. keyExtractor={(item) => item.letter}
  137. />
  138. </View>
  139. )}
  140. </ScrollView>
  141. </SafeAreaView>
  142. );
  143. };
  144. const styles = StyleSheet.create({
  145. letterHeader: {
  146. backgroundColor: '#E3F2F8',
  147. padding: 10,
  148. marginVertical: 10
  149. },
  150. letterText: {
  151. color: '#02677D',
  152. fontSize: 14,
  153. fontWeight: 'bold'
  154. },
  155. brandRow: {
  156. flexDirection: 'row',
  157. flexWrap: 'wrap'
  158. },
  159. brandItem: {
  160. width: '33.33%',
  161. alignItems: 'center',
  162. padding: 10
  163. },
  164. logo: {
  165. width: 80,
  166. height: 80
  167. },
  168. brandName: {
  169. marginTop: 5,
  170. textAlign: 'center'
  171. }
  172. });
  173. export default SetVehiclesOne;