All files / src/view/pages/EpisodesPage EpisodesPage.tsx

100% Statements 89/89
66.66% Branches 14/21
50% Functions 2/4
100% Lines 89/89

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 103 104 105  1x 1x 1x 1x 1x 1x 1x   1x 1x   1x   1x 14x 14x   14x   14x 14x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 6x   6x 5x 5x 6x 1x 1x 8x 8x 1x 1x 8x 8x 8x 8x 8x 14x 14x   14x 7x 14x   14x 14x 14x   14x 14x 14x 14x 14x 14x 14x   14x 14x 14x 14x 14x 14x 14x 14x   14x 14x 14x 10x 10x 10x 10x 10x 10x 10x 14x 14x 14x   14x 14x 14x 14x 14x 14x 14x 14x   14x   1x  
import { IParams } from '@/core/services/http/http.models';
import AutoComplete from '@/shared/components/AutoComplete/AutoComplete';
import Card from '@/shared/components/Card/Card';
import Paginator from '@/shared/components/Paginator/Paginator';
import { setTableParams } from '@/shared/utils/table-utils';
import { useCallback, useEffect, useState } from 'react';
import { apiEpisodes, getEpisodes } from './EpisodesPage.service';
import { catchError, of, tap } from 'rxjs';
import { IEpisode } from '@/shared/types/character';
import { format } from 'date-fns/format';
import { DATE_TIME_FORMAT } from '@/shared/enums/date-time-formats';
import { ILazyState } from '@/shared/types/lazyParams';
import { useToast } from '@/hooks/useToast';
 
const EpisodesPage: React.FC = () => {
  const [data, setData] = useState<IEpisode[]>([]);
  const [params, setParams] = useState<IParams>({ page: 1 });
 
  const toast = useToast();
 
  const getData = useCallback(
    (event?: ILazyState) => {
      const baseParams = { ...setTableParams(event as ILazyState) };
      if (!baseParams?.page) return;
      const fullParams = {
        ...baseParams,
      };
      setParams(fullParams);
      if (fullParams?.pageSize) delete fullParams.pageSize;
      const { pages, ...rest } = fullParams || {};
      const subscription = getEpisodes(rest)
        .pipe(
          tap((res) => {
            const { results = [], info = {} } = res || {};
 
            if (results.length) {
              setParams((prevParams) => ({ ...prevParams, pages: info.pages }));
              setData(results ?? []);
            } else {
              toast.showError('Error fetching episodes');
            }
          }),
          catchError((error) => {
            console.error('Failed to fetch episodes.', error);
            return of({});
          })
        )
        .subscribe();
      return () => subscription.unsubscribe();
    },
    [params]
  );
 
  useEffect(() => {
    getData(params);
  }, []);
 
  return (
    <div className="main-page-container">
      <h2 className="page-title">Episodes</h2>
 
      <AutoComplete
        url={apiEpisodes}
        queryVal={(params?.name as string) ?? ''}
        paramName="name"
        onSelect={(name) => getData({ ...params, page: 1, filters: { ['name']: { value: name, matchMode: 'contains' } } })}
        className="py-3"
      />
 
      <div className="paginator-top">
        <Paginator
          currentPage={typeof params.page === 'number' ? params.page : 1}
          totalPages={typeof params.pages === 'number' ? params.pages : 1}
          onPageChange={(newPage) => getData({ ...params, page: newPage })}
          maxVisiblePages={3}
        />
      </div>
 
      <div className="page-layout-one-col">
        <div className="card-grid">
          {data?.map((item, i) => (
            <Card key={`card-main-${i}`} name={item.name} image={null}>
              <div className="main-card-content">
                <div className="card-footer">
                  <span>Created: {format(new Date(item.created as string), DATE_TIME_FORMAT.FNS_DATE)}</span>
                </div>
              </div>
            </Card>
          ))}
        </div>
      </div>
 
      <div className="paginator-bottom">
        <Paginator
          currentPage={typeof params.page === 'number' ? params.page : 1}
          totalPages={typeof params.pages === 'number' ? params.pages : 1}
          onPageChange={(newPage) => getData({ ...params, page: newPage })}
        />
      </div>
    </div>
  );
};
 
export default EpisodesPage;