registerChooseVehiclesOne.tsx 6.0 KB

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