index.tsx 4.8 KB

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