index.tsx 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. import React, { useCallback, useEffect, useState } from 'react';
  2. import { View, Text, FlatList, Image, TouchableOpacity } from 'react-native';
  3. import { useNavigation } from '@react-navigation/native';
  4. import { Header, PageWrapper, HorizontalTabView, Loading, WarningModal } from 'src/components';
  5. import { useGetSeriesGroups, useGetSeriesWithGroup } from '@api/series';
  6. import { useFocusEffect } from '@react-navigation/native';
  7. import { API_HOST } from 'src/constants';
  8. import { StoreType, storage } from 'src/storage';
  9. import { styles } from './styles';
  10. import { NAVIGATION_PAGES } from 'src/types';
  11. import AddSvg from 'assets/icons/travels-section/add.svg';
  12. import { SafeAreaView } from 'react-native-safe-area-context';
  13. interface SeriesGroup {
  14. key: string;
  15. title: string;
  16. }
  17. interface SeriesList {
  18. id: number;
  19. name: string;
  20. icon: string;
  21. count: number;
  22. new: number;
  23. score: number;
  24. icon_png: string;
  25. count2: number;
  26. }
  27. const SeriesScreen = () => {
  28. const token = storage.get('token', StoreType.STRING) as string;
  29. const [isLoading, setIsLoading] = useState(true);
  30. const [index, setIndex] = useState(0);
  31. const [routes, setRoutes] = useState<SeriesGroup[]>([]);
  32. const [warningVisible, setWarningVisible] = useState(false);
  33. const { data } = useGetSeriesGroups(true);
  34. const navigation = useNavigation();
  35. useFocusEffect(
  36. useCallback(() => {
  37. const fetchGroups = async () => {
  38. let staticGroups = [
  39. {
  40. key: '-1',
  41. title: 'Top of the tops'
  42. },
  43. {
  44. key: '-2',
  45. title: 'Milestones'
  46. },
  47. {
  48. key: 'all',
  49. title: 'All series'
  50. }
  51. ];
  52. const routesData = data?.data?.map((item) => ({
  53. key: item.id.toString(),
  54. title: item.name
  55. }));
  56. routesData && staticGroups.push(...routesData);
  57. setRoutes(staticGroups);
  58. setIsLoading(false);
  59. };
  60. if (data && data.data) {
  61. fetchGroups();
  62. }
  63. }, [data])
  64. );
  65. if (isLoading) return <Loading />;
  66. return (
  67. <SafeAreaView style={{ height: '100%' }} edges={['top']}>
  68. <View style={{ marginLeft: '5%', marginRight: '5%' }}>
  69. <Header
  70. label={'Series'}
  71. rightElement={
  72. <TouchableOpacity
  73. onPress={() => {
  74. if (token) {
  75. navigation.navigate(NAVIGATION_PAGES.SUGGEST_SERIES as never);
  76. } else {
  77. setWarningVisible(true);
  78. }
  79. }}
  80. >
  81. <AddSvg />
  82. </TouchableOpacity>
  83. }
  84. />
  85. </View>
  86. <HorizontalTabView
  87. index={index}
  88. setIndex={setIndex}
  89. routes={routes}
  90. maxTabHeight={50}
  91. renderScene={({ route }: { route: SeriesGroup }) => (
  92. <SeriesList groupId={route.key} navigation={navigation} />
  93. )}
  94. />
  95. <WarningModal
  96. type="unauthorized"
  97. isVisible={warningVisible}
  98. onClose={() => setWarningVisible(false)}
  99. />
  100. </SafeAreaView>
  101. );
  102. };
  103. const SeriesList = React.memo(({ groupId, navigation }: { groupId: string; navigation: any }) => {
  104. const [seriesData, setSeriesData] = useState<SeriesList[]>([]);
  105. const [isLoading, setIsLoading] = useState(true);
  106. const token = storage.get('token', StoreType.STRING) as string;
  107. const { mutateAsync } = useGetSeriesWithGroup();
  108. useEffect(() => {
  109. const fetchSeriesData = async () => {
  110. try {
  111. await mutateAsync(
  112. { group: groupId, token: String(token) },
  113. {
  114. onSuccess: (data) => {
  115. setSeriesData(data.data);
  116. }
  117. }
  118. );
  119. } catch (error) {
  120. console.error('Failed to fetch series data', error);
  121. } finally {
  122. setIsLoading(false);
  123. }
  124. };
  125. fetchSeriesData();
  126. }, [groupId]);
  127. if (isLoading) return <Loading />;
  128. const renderItem = ({ item }: { item: SeriesList }) => {
  129. return (
  130. <TouchableOpacity
  131. style={styles.itemContainer}
  132. onPress={() =>
  133. navigation.navigate(NAVIGATION_PAGES.SERIES_ITEM, { id: item.id, name: item.name, token })
  134. }
  135. >
  136. <Image style={styles.icon} source={{ uri: API_HOST + item.icon_png }} />
  137. <View style={styles.infoContainer}>
  138. <View style={styles.titleContainer}>
  139. <Text style={styles.title}>{item.name}</Text>
  140. {item.new === 1 && <Text style={styles.textNew}>NEW</Text>}
  141. </View>
  142. <View style={styles.detailsContainer}>
  143. <Text style={styles.details}>Total objects: {item.count}</Text>
  144. <Text style={styles.count}>
  145. {token ? item.score : 0} / {item.count}
  146. </Text>
  147. </View>
  148. </View>
  149. </TouchableOpacity>
  150. );
  151. };
  152. return (
  153. <FlatList
  154. horizontal={false}
  155. data={seriesData}
  156. renderItem={renderItem}
  157. keyExtractor={(item) => item.id.toString()}
  158. showsVerticalScrollIndicator={false}
  159. />
  160. );
  161. });
  162. export default SeriesScreen;