setVehiclesOne.tsx 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  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. data={processedCarData
  123. .sort((a, b) => a.name.localeCompare(b.name))
  124. .reduce((acc, brand) => {
  125. const letter = brand.name[0].toUpperCase();
  126. const existingSection = acc.find((section) => section.letter === letter);
  127. if (existingSection) {
  128. existingSection.brands.push(brand);
  129. } else {
  130. acc.push({ letter, brands: [brand] });
  131. }
  132. return acc;
  133. }, [] as AlphabetSection[])}
  134. renderItem={renderAlphabetSection}
  135. keyExtractor={(item) => item.letter}
  136. />
  137. </View>
  138. )}
  139. </ScrollView>
  140. </SafeAreaView>
  141. );
  142. };
  143. const styles = StyleSheet.create({
  144. letterHeader: {
  145. backgroundColor: '#E3F2F8',
  146. padding: 10,
  147. marginVertical: 10
  148. },
  149. letterText: {
  150. color: '#02677D',
  151. fontSize: 14,
  152. fontWeight: 'bold'
  153. },
  154. brandRow: {
  155. flexDirection: 'row',
  156. flexWrap: 'wrap'
  157. },
  158. brandItem: {
  159. width: '33.33%',
  160. alignItems: 'center',
  161. padding: 10
  162. },
  163. logo: {
  164. width: 80,
  165. height: 80
  166. },
  167. brandName: {
  168. marginTop: 5,
  169. textAlign: 'center'
  170. }
  171. });
  172. export default SetVehiclesOne;