index.tsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. import React, { Dispatch, SetStateAction, useCallback, useEffect, useState } from 'react';
  2. import { ActivityIndicator } from 'react-native';
  3. import { useNavigation } from '@react-navigation/native';
  4. import { FlashList } from '@shopify/flash-list';
  5. import {
  6. Header,
  7. HorizontalTabView,
  8. Loading,
  9. PageWrapper,
  10. WarningModal
  11. } from '../../../../components';
  12. import SeriesRankingItem from '../Components/SeriesRankingItem';
  13. import { useGetSeriesRanking } from '@api/series';
  14. import { useConnection } from 'src/contexts/ConnectionContext';
  15. import { NAVIGATION_PAGES } from 'src/types';
  16. import { StoreType, storage } from 'src/storage';
  17. import { Colors } from 'src/theme';
  18. import { SeriesRanking } from '../utils/types';
  19. const SeriesRankingListScreen = ({ route }: { route: any }) => {
  20. const name = route.params.name;
  21. const id = route.params.id;
  22. const series = route.params.series;
  23. const [index, setIndex] = useState(0);
  24. const [routes, setRoutes] = useState<{ key: string; title: string }[]>([]);
  25. const [loading, setLoading] = useState(true);
  26. const [modalType, setModalType] = useState<string | null>(null);
  27. useEffect(() => {
  28. if (series) {
  29. const parsedRoutes = series.map((item: { id: string; name: string }) => ({
  30. key: item.id,
  31. title: item.name
  32. }));
  33. setRoutes([{ key: id, title: ' All ' }, ...(parsedRoutes || [])]);
  34. }
  35. setLoading(false);
  36. }, [series]);
  37. if (loading) return <Loading />;
  38. return (
  39. <PageWrapper style={{ flex: 1 }}>
  40. <Header label={name} />
  41. {series ? (
  42. <HorizontalTabView
  43. index={index}
  44. setIndex={setIndex}
  45. routes={routes}
  46. renderScene={({ route }: { route: { key: string; title: string } }) => (
  47. <SeriesList groupId={+route.key} setModalType={setModalType} />
  48. )}
  49. lazy={true}
  50. />
  51. ) : (
  52. <SeriesList groupId={id} setModalType={setModalType} />
  53. )}
  54. {modalType && (
  55. <WarningModal type={modalType} isVisible={true} onClose={() => setModalType(null)} />
  56. )}
  57. </PageWrapper>
  58. );
  59. };
  60. const SeriesList = React.memo(
  61. ({
  62. groupId,
  63. setModalType
  64. }: {
  65. groupId: number;
  66. setModalType: Dispatch<SetStateAction<string | null>>;
  67. }) => {
  68. const [loading, setLoading] = useState(true);
  69. const [page, setPage] = useState(0);
  70. const { data } = useGetSeriesRanking(groupId, page, 50, true);
  71. const [allData, setAllData] = useState<SeriesRanking[]>([]);
  72. const netInfo = useConnection();
  73. const navigation = useNavigation();
  74. const token = storage.get('token', StoreType.STRING);
  75. const [isLoadingMore, setIsLoadingMore] = useState(false);
  76. useEffect(() => {
  77. if (data && data.result == 'OK') {
  78. setAllData((prevData) => [...prevData, ...data.data.ranking]);
  79. setLoading(false);
  80. setIsLoadingMore(false);
  81. }
  82. }, [data]);
  83. const handlePress = useCallback(
  84. (userId: number) => {
  85. if (!netInfo?.isInternetReachable) {
  86. setModalType('offline');
  87. } else if (!token) {
  88. setModalType('unauthorized');
  89. } else {
  90. navigation.navigate(...([NAVIGATION_PAGES.PUBLIC_PROFILE_VIEW, { userId }] as never));
  91. }
  92. },
  93. [netInfo, token, navigation, data]
  94. );
  95. const handleEndReached = useCallback(() => {
  96. if (
  97. data &&
  98. data.result === 'OK' &&
  99. page < data.data.max_pages &&
  100. isLoadingMore &&
  101. netInfo?.isInternetReachable
  102. ) {
  103. setIsLoadingMore(true);
  104. setPage((prevPage) => prevPage + 1);
  105. }
  106. }, [data, page, isLoadingMore, netInfo?.isInternetReachable]);
  107. const ListFooter = ({ isLoading }: { isLoading: boolean }) =>
  108. isLoading ? <ActivityIndicator size="large" color={Colors.DARK_BLUE} /> : null;
  109. if (loading) return <Loading />;
  110. return (
  111. <FlashList
  112. viewabilityConfig={{
  113. waitForInteraction: true,
  114. itemVisiblePercentThreshold: 50,
  115. minimumViewTime: 1000
  116. }}
  117. estimatedItemSize={50}
  118. contentContainerStyle={{ paddingVertical: 16 }}
  119. data={allData}
  120. showsVerticalScrollIndicator={false}
  121. keyExtractor={(item, index) => index.toString()}
  122. renderItem={({ item, index }: { item: SeriesRanking; index: number }) => (
  123. <SeriesRankingItem item={item} index={index} onPress={handlePress} />
  124. )}
  125. onEndReached={handleEndReached}
  126. onEndReachedThreshold={0.1}
  127. ListFooterComponent={<ListFooter isLoading={isLoadingMore} />}
  128. />
  129. );
  130. }
  131. );
  132. export default SeriesRankingListScreen;