All files / pages TopPosts.tsx

0% Statements 0/20
0% Branches 0/13
0% Functions 0/5
0% Lines 0/20

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102                                                                                                                                                                                                           
import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useSearchParams } from 'react-router-dom';
import { FormattedMessage } from 'react-intl';
import { Box, Typography, CircularProgress, Alert } from '@mui/material';
import { fetchTopPosts } from '@/store/reducers/posts/posts-actions';
import {
  selectTopPosts,
  selectPostsLoading,
  selectPostsError,
  selectCurrentPage,
  selectTotalPages,
} from '@/store/reducers/posts/posts-selectors';
import { selectViewMode } from '@/store/reducers/settings/settings-selectors';
import { ViewMode } from '@/enums/settings';
import PostListItem from '@/components/posts/PostListItem/PostListItem';
import PostGridItem from '@/components/posts/PostGridItem/PostGridItem';
import Pagination from '@/components/posts/Pagination/Pagination';
import { getPageFromUrl } from '@/helpers/urlHelper';
import { calculateStartRank } from '@/helpers/paginationHelper';
import { getPostsPerPage } from '@/helpers/configHelper';
 
const POSTS_PER_PAGE = getPostsPerPage();
 
function TopPosts() {
  const dispatch = useDispatch();
  const [searchParams, setSearchParams] = useSearchParams();
  const posts = useSelector(selectTopPosts);
  const loading = useSelector(selectPostsLoading);
  const error = useSelector(selectPostsError);
  const currentPage = useSelector(selectCurrentPage);
  const totalPages = useSelector(selectTotalPages);
  const viewMode = useSelector(selectViewMode);
 
  const pageFromUrl = getPageFromUrl(searchParams);
 
  useEffect(() => {
    dispatch(fetchTopPosts({ page: pageFromUrl }));
  }, [dispatch, pageFromUrl]);
 
  const handlePageChange = (page: number) => {
    setSearchParams({ page: page.toString() });
    dispatch(fetchTopPosts({ page }));
    window.scrollTo({ top: 0, behavior: 'smooth' });
  };
 
  const startRank = calculateStartRank(currentPage, POSTS_PER_PAGE);
 
  return (
    <Box sx={{ maxWidth: '1200px', margin: '0 auto', p: 3 }}>
      <Typography variant="h4" component="h1" gutterBottom>
        <FormattedMessage id="topPosts.title" />
      </Typography>
 
      {loading && (
        <Box sx={{ display: 'flex', justifyContent: 'center', my: 4 }}>
          <CircularProgress />
        </Box>
      )}
 
      {error && (
        <Alert severity="error" sx={{ mb: 2 }}>
          {error}
        </Alert>
      )}
 
      {!loading && !error && posts.length === 0 && (
        <Typography variant="body1" color="text.secondary">
          No posts found.
        </Typography>
      )}
 
      {!loading && posts.length > 0 && (
        <>
          {viewMode === ViewMode.List ? (
            <>
              {posts.map((post, index) => (
                <PostListItem key={post.id} item={post} rank={startRank + index} />
              ))}
            </>
          ) : (
            <Box
              sx={{
                display: 'grid',
                gridTemplateColumns: { xs: '1fr', sm: 'repeat(2, 1fr)', md: 'repeat(3, 1fr)' },
                gap: 2,
              }}
            >
              {posts.map((post, index) => (
                <PostGridItem key={post.id} item={post} rank={startRank + index} />
              ))}
            </Box>
          )}
          <Pagination currentPage={currentPage} totalPages={totalPages} onPageChange={handlePageChange} />
        </>
      )}
    </Box>
  );
}
 
export default TopPosts;