registerChooseVehiclesOne.tsx 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  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 } 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 [carData, setCarData] = useState();
  15. const [extractedCarNameAndImgUrl, setExtractedCarNameAndImgUrl] = useState('');
  16. const [processedCarData, setProcessedCarData] = useState([]);
  17. const {
  18. vehicleBrand,
  19. vehicleModel,
  20. BrandID,
  21. ModelID,
  22. licensePlate,
  23. setVehicleBrand,
  24. setVehicleModel,
  25. setBrandID,
  26. setModelID,
  27. setLicensePlate
  28. } = useVehicleStore();
  29. //this uses getCarBrand to create an array of object with 2 keys: name and img_url
  30. useEffect(() => {
  31. const fetchCarBrand = async () => {
  32. try {
  33. const response = await chargeStationService.fetchCarBrand();
  34. if (response) {
  35. const processedData = await Promise.all(
  36. response.data.map(async (car) => ({
  37. ...car,
  38. logo: await chargeStationService.getProcessedCarImageUrl(car.img_url)
  39. }))
  40. );
  41. setProcessedCarData(processedData);
  42. }
  43. } catch (error) {
  44. console.log(error);
  45. }
  46. };
  47. fetchCarBrand();
  48. }, []);
  49. useEffect(() => {
  50. console.log('Zustand VehicleBrand', vehicleBrand);
  51. console.log('Zustand BrandID', BrandID);
  52. console.log('Zustand VehicleModel', vehicleModel);
  53. console.log('Zustand ModelID', ModelID);
  54. }, [processedCarData]);
  55. const renderBrandItem = ({ item: brand }: { item }) => (
  56. <Pressable
  57. style={styles.brandItem}
  58. onPress={() => {
  59. setVehicleBrand(brand.name);
  60. setBrandID(brand.id);
  61. router.push({
  62. pathname: 'registerChooseVehiclesTwo',
  63. params: {
  64. brandId: brand.id.toString(),
  65. brandName: brand.name,
  66. carTypes: JSON.stringify(brand.car_types)
  67. }
  68. });
  69. }}
  70. >
  71. <Image source={{ uri: brand.logo }} style={styles.logo} resizeMode="contain" />
  72. <Text style={styles.brandName}>{brand.name}</Text>
  73. </Pressable>
  74. );
  75. const renderAlphabetSection = ({ item: section }: { item: AlphabetSection }) => (
  76. <View>
  77. <View style={styles.letterHeader} className="h-9">
  78. <Text style={styles.letterText}>{section.letter}</Text>
  79. </View>
  80. <View style={styles.brandRow}>{section.brands.map((brand) => renderBrandItem({ item: brand }))}</View>
  81. </View>
  82. );
  83. return (
  84. <SafeAreaView className="flex-1 bg-white" edges={['top', 'right', 'left']}>
  85. <ScrollView showsVerticalScrollIndicator={false} className="flex-1 mx-[5%]">
  86. <View style={{ marginTop: 25 }}>
  87. <Pressable
  88. className="self-start"
  89. onPress={() => {
  90. if (router.canGoBack()) {
  91. router.back();
  92. } else {
  93. router.replace('/accountMainPage');
  94. }
  95. }}
  96. >
  97. <PreviousPageBlackSvg />
  98. </Pressable>
  99. <Text
  100. style={{
  101. fontSize: 30,
  102. marginTop: 25,
  103. marginBottom: 10
  104. }}
  105. >
  106. 選擇品牌
  107. </Text>
  108. </View>
  109. <View className="flex-1">
  110. <FlashList
  111. estimatedItemSize={100}
  112. data={processedCarData.reduce((acc, brand) => {
  113. const letter = brand.name[0].toUpperCase();
  114. const existingSection = acc.find((section) => section.letter === letter);
  115. if (existingSection) {
  116. existingSection.brands.push(brand);
  117. } else {
  118. acc.push({ letter, brands: [brand] });
  119. }
  120. return acc;
  121. }, [] as AlphabetSection[])}
  122. renderItem={renderAlphabetSection}
  123. keyExtractor={(item) => item.letter}
  124. />
  125. </View>
  126. </ScrollView>
  127. </SafeAreaView>
  128. );
  129. };
  130. const styles = StyleSheet.create({
  131. letterHeader: {
  132. backgroundColor: '#E3F2F8',
  133. padding: 10,
  134. marginVertical: 10
  135. },
  136. letterText: {
  137. color: '#02677D',
  138. fontSize: 14,
  139. fontWeight: 'bold'
  140. },
  141. brandRow: {
  142. flexDirection: 'row',
  143. flexWrap: 'wrap'
  144. },
  145. brandItem: {
  146. width: '33.33%',
  147. alignItems: 'center',
  148. padding: 10
  149. },
  150. logo: {
  151. width: 80,
  152. height: 80
  153. },
  154. brandName: {
  155. marginTop: 5,
  156. textAlign: 'center'
  157. }
  158. });
  159. export default RegisterChooseVehiclesOne;