From c9e5d65faec6287976cd7058e8430f3d786fccd2 Mon Sep 17 00:00:00 2001 From: Oleh Prokopenko Date: Thu, 25 Jun 2026 16:41:18 +0300 Subject: [PATCH 1/2] add tusk solution --- README.md | 26 ++-- src/App.tsx | 129 ++++++++---------- src/components/Pagination/Pagination.tsx | 1 - src/components/notFoundPage/index.js | 1 + src/components/notFoundPage/notFoundPage.tsx | 13 ++ src/components/paganation/Pagination.tsx | 75 ++++++++++ .../{Pagination => paganation}/index.ts | 0 src/index.tsx | 12 +- 8 files changed, 169 insertions(+), 88 deletions(-) delete mode 100644 src/components/Pagination/Pagination.tsx create mode 100644 src/components/notFoundPage/index.js create mode 100644 src/components/notFoundPage/notFoundPage.tsx create mode 100644 src/components/paganation/Pagination.tsx rename src/components/{Pagination => paganation}/index.ts (100%) diff --git a/README.md b/README.md index be8a8c6b6..0b24dd728 100644 --- a/README.md +++ b/README.md @@ -2,29 +2,29 @@ > Here is the [working version](https://mate-academy.github.io/react_pagination/) -You a given a list of items and markup for the `Pagination`. Implement the +You a given a list of items and markup for the `Pagination`. Implement the `Pagination` as a stateless component to show only the items for a current page. 1. The `Pagination` should be used with the next props: - ```jsx harmony - { ... }} - /> - ``` + ```jsx harmony + { ... }} + /> + ``` 1. Keep the HTML stucture `data-cy` attributes; 1. Show all the existing pages considering `total` and `perPage` 1. Current page should be highlighted with `li.active`; 1. `onPageChange` callback should be triggered only if page was changed; 1. The `App` should listen to the `onPageChange` and save a new page; 1. `«` and `»` links should open the prev and the next pages accordingly - - disable each of them if it is already the first or the last page (use `li.disabled` and `a[aria-disabled="true"]`) + - disable each of them if it is already the first or the last page (use `li.disabled` and `a[aria-disabled="true"]`) 1. Show the pagination info inside `data-cy="info"` in the next format `Page 1 (items 1 - 5 of 42)`; 1. Implement the ` + className="form-control" + value={perPage} + onChange={selectHandler} + > @@ -33,77 +72,21 @@ export const App: React.FC = () => { {/* Move this markup to Pagination */} - + +
    -
  • Item 1
  • -
  • Item 2
  • -
  • Item 3
  • -
  • Item 4
  • -
  • Item 5
  • + {items + .slice((currentPage - 1) * perPage, currentPage * perPage) + .map(item => ( +
  • + {item} +
  • + ))}
); diff --git a/src/components/Pagination/Pagination.tsx b/src/components/Pagination/Pagination.tsx deleted file mode 100644 index e417a09fc..000000000 --- a/src/components/Pagination/Pagination.tsx +++ /dev/null @@ -1 +0,0 @@ -export const Pagination = () => {}; diff --git a/src/components/notFoundPage/index.js b/src/components/notFoundPage/index.js new file mode 100644 index 000000000..a391d0afb --- /dev/null +++ b/src/components/notFoundPage/index.js @@ -0,0 +1 @@ +export * from './notFoundPage'; diff --git a/src/components/notFoundPage/notFoundPage.tsx b/src/components/notFoundPage/notFoundPage.tsx new file mode 100644 index 000000000..3378ecc20 --- /dev/null +++ b/src/components/notFoundPage/notFoundPage.tsx @@ -0,0 +1,13 @@ +/* eslint-disable import/no-extraneous-dependencies */ +import { Link } from 'react-router-dom'; + +export const NotFoundPage = () => { + return ( +
+

Not Found Page

+ + + +
+ ); +}; diff --git a/src/components/paganation/Pagination.tsx b/src/components/paganation/Pagination.tsx new file mode 100644 index 000000000..d0564e7bd --- /dev/null +++ b/src/components/paganation/Pagination.tsx @@ -0,0 +1,75 @@ +import React from 'react'; +import cn from 'classnames'; + +type Props = { + total: number; + perPage: number; + currentPage?: number; + onPageChange: (page: number) => void; +}; + +export const Pagination: React.FC = ({ + total, + perPage, + currentPage = 1, + onPageChange, +}) => { + const totalPages = Math.ceil(total / perPage); + + const pageNumbers = Array.from({ length: totalPages }, (_, i) => i + 1); + + return ( + + ); +}; diff --git a/src/components/Pagination/index.ts b/src/components/paganation/index.ts similarity index 100% rename from src/components/Pagination/index.ts rename to src/components/paganation/index.ts diff --git a/src/index.tsx b/src/index.tsx index 226f3f4bd..963282e99 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,5 +1,15 @@ +/* eslint-disable import/no-extraneous-dependencies */ import { createRoot } from 'react-dom/client'; import { App } from './App'; +import { createBrowserRouter, RouterProvider } from 'react-router-dom'; +import { NotFoundPage } from './components/notFoundPage'; -createRoot(document.getElementById('root') as HTMLElement).render(); +const router = createBrowserRouter([ + { path: '/', element: }, + { path: '*', element: }, +]); + +createRoot(document.getElementById('root') as HTMLElement).render( + , +); From cf3148317f0fa78d18f56f89ece61ec1a52b834d Mon Sep 17 00:00:00 2001 From: Oleh Prokopenko Date: Thu, 25 Jun 2026 16:54:24 +0300 Subject: [PATCH 2/2] add guard update check --- src/App.tsx | 4 +++- src/components/paganation/Pagination.tsx | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 10e1d1021..b2ffde732 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -24,7 +24,9 @@ export const App: React.FC = () => { }); const handlePageChange = (page: number) => { - setCurrentPage(page); + if (page !== currentPage) { + setCurrentPage(page); + } }; const selectHandler = (e: React.ChangeEvent) => { diff --git a/src/components/paganation/Pagination.tsx b/src/components/paganation/Pagination.tsx index d0564e7bd..88b92cd76 100644 --- a/src/components/paganation/Pagination.tsx +++ b/src/components/paganation/Pagination.tsx @@ -47,7 +47,9 @@ export const Pagination: React.FC = ({ href={`#${page}`} onClick={e => { e.preventDefault(); - onPageChange(page); + if (page !== currentPage) { + onPageChange(page); + } }} > {page}