-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Dev #1434
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Dev #1434
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,29 +1,59 @@ | ||
| import React from 'react'; | ||
| import React, { useState } from 'react'; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Import React Router hooks and useEffect here. You need |
||
| import './App.css'; | ||
| import { getNumbers } from './utils'; | ||
| import { Pagination } from './components/Pagination'; | ||
|
|
||
| // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
| const items = getNumbers(1, 42).map(n => `Item ${n}`); | ||
| const totalItems = 42; | ||
| const items = getNumbers(1, totalItems).map(n => `Item ${n}`); | ||
|
|
||
| enum NumberPerPageItems { | ||
| THREE = 3, | ||
| FIVE = 5, | ||
| TEN = 10, | ||
| TWENTY = 20, | ||
| } | ||
|
|
||
| export const App: React.FC = () => { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The app currently doesn't persist |
||
| const [currentPage, setCurrentPage] = useState(1); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't initialize |
||
| const [perPage, setPerPage] = useState(NumberPerPageItems.FIVE); | ||
|
Comment on lines
+18
to
+19
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Initial There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same for |
||
|
|
||
| const startItem = currentPage * perPage - (perPage - 1); | ||
| const endItem = currentPage * perPage; | ||
|
|
||
| return ( | ||
| <div className="container"> | ||
| <h1>Items with Pagination</h1> | ||
|
|
||
| <p className="lead" data-cy="info"> | ||
| Page 1 (items 1 - 5 of 42) | ||
| Page {currentPage} (items {startItem} -{' '} | ||
| {endItem > totalItems ? totalItems : endItem} of {totalItems}) | ||
| </p> | ||
|
|
||
| <div className="form-group row"> | ||
| <div className="col-3 col-sm-2 col-xl-1"> | ||
| <select | ||
0-nira-0 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| data-cy="perPageSelector" | ||
| id="perPageSelector" | ||
| className="form-control"> | ||
| <option value="3">3</option> | ||
| <option value="5">5</option> | ||
| <option value="10">10</option> | ||
| <option value="20">20</option> | ||
| className="form-control" | ||
| onChange={e => { | ||
| setPerPage(Number(e.target.value)); | ||
| setCurrentPage(1); | ||
|
Comment on lines
+39
to
+41
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When the |
||
| }} | ||
| value={perPage} | ||
| > | ||
| <option value={NumberPerPageItems.THREE}> | ||
| {NumberPerPageItems.THREE} | ||
| </option> | ||
| <option value={NumberPerPageItems.FIVE}> | ||
| {NumberPerPageItems.FIVE} | ||
| </option> | ||
| <option value={NumberPerPageItems.TEN}> | ||
| {NumberPerPageItems.TEN} | ||
| </option> | ||
| <option value={NumberPerPageItems.TWENTY}> | ||
| {NumberPerPageItems.TWENTY} | ||
| </option> | ||
| </select> | ||
| </div> | ||
|
|
||
|
|
@@ -32,78 +62,22 @@ export const App: React.FC = () => { | |
| </label> | ||
| </div> | ||
|
|
||
| {/* Move this markup to Pagination */} | ||
| <ul className="pagination"> | ||
| <li className="page-item disabled"> | ||
| <a | ||
| data-cy="prevLink" | ||
| className="page-link" | ||
| href="#prev" | ||
| aria-disabled="true"> | ||
| « | ||
| </a> | ||
| </li> | ||
| <li className="page-item active"> | ||
| <a data-cy="pageLink" className="page-link" href="#1"> | ||
| 1 | ||
| </a> | ||
| </li> | ||
| <li className="page-item"> | ||
| <a data-cy="pageLink" className="page-link" href="#2"> | ||
| 2 | ||
| </a> | ||
| </li> | ||
| <li className="page-item"> | ||
| <a data-cy="pageLink" className="page-link" href="#3"> | ||
| 3 | ||
| </a> | ||
| </li> | ||
| <li className="page-item"> | ||
| <a data-cy="pageLink" className="page-link" href="#4"> | ||
| 4 | ||
| </a> | ||
| </li> | ||
| <li className="page-item"> | ||
| <a data-cy="pageLink" className="page-link" href="#5"> | ||
| 5 | ||
| </a> | ||
| </li> | ||
| <li className="page-item"> | ||
| <a data-cy="pageLink" className="page-link" href="#6"> | ||
| 6 | ||
| </a> | ||
| </li> | ||
| <li className="page-item"> | ||
| <a data-cy="pageLink" className="page-link" href="#7"> | ||
| 7 | ||
| </a> | ||
| </li> | ||
| <li className="page-item"> | ||
| <a data-cy="pageLink" className="page-link" href="#8"> | ||
| 8 | ||
| </a> | ||
| </li> | ||
| <li className="page-item"> | ||
| <a data-cy="pageLink" className="page-link" href="#9"> | ||
| 9 | ||
| </a> | ||
| </li> | ||
| <li className="page-item"> | ||
| <a | ||
| data-cy="nextLink" | ||
| className="page-link" | ||
| href="#next" | ||
| aria-disabled="false"> | ||
| » | ||
| </a> | ||
| </li> | ||
| </ul> | ||
| <Pagination | ||
| total={totalItems} // total number of items to paginate | ||
| perPage={perPage} // number of items per page | ||
| currentPage={currentPage} /* optional with 1 by default */ | ||
| onPageChange={page => { | ||
| if (currentPage !== page) { | ||
| setCurrentPage(page); | ||
|
Comment on lines
+69
to
+71
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
| } | ||
| }} | ||
|
Comment on lines
+69
to
+73
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When the user changes page via |
||
| /> | ||
| <ul> | ||
| <li data-cy="item">Item 1</li> | ||
| <li data-cy="item">Item 2</li> | ||
| <li data-cy="item">Item 3</li> | ||
| <li data-cy="item">Item 4</li> | ||
| <li data-cy="item">Item 5</li> | ||
| {items.slice(startItem - 1, endItem).map(i => ( | ||
| <li key={i} data-cy="item"> | ||
| {i} | ||
| </li> | ||
| ))} | ||
| </ul> | ||
| </div> | ||
| ); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,92 @@ | ||
| export const Pagination = () => {}; | ||
| import classNames from 'classnames'; | ||
|
|
||
| type Props = { | ||
| total: number; | ||
| perPage: number; | ||
| currentPage?: number; | ||
| onPageChange: (page: number) => void; | ||
| }; | ||
|
|
||
| export const Pagination: React.FC<Props> = ({ | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You use the |
||
| total, | ||
| perPage, | ||
| currentPage = 1, | ||
| onPageChange, | ||
| }) => { | ||
| const numberOfPage = Math.ceil(total / perPage); | ||
0-nira-0 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| const pagesList = Array.from( | ||
| { length: numberOfPage }, | ||
| (_, index) => index + 1, | ||
| ); | ||
|
|
||
| return ( | ||
| <ul className="pagination"> | ||
| <li | ||
| className={classNames('page-item', { | ||
| disabled: currentPage === 1, | ||
| })} | ||
| > | ||
| <a | ||
| data-cy="prevLink" | ||
| className={classNames('page-link', { | ||
| disabled: currentPage === 1, | ||
| })} | ||
| onClick={e => { | ||
| if (currentPage !== 1) { | ||
| onPageChange(currentPage - 1); | ||
| } | ||
|
|
||
| e.preventDefault(); | ||
| }} | ||
| aria-disabled={currentPage === 1} | ||
0-nira-0 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| > | ||
| « | ||
| </a> | ||
| </li> | ||
| {pagesList.map(i => ( | ||
| <li | ||
| key={i} | ||
| className={classNames('page-item', { active: i === currentPage })} | ||
| > | ||
| <a | ||
| data-cy="pageLink" | ||
| className="page-link" | ||
| href={`#${i}`} | ||
| onClick={e => { | ||
| if (currentPage !== i) { | ||
| onPageChange(i); | ||
| } | ||
|
|
||
| e.preventDefault(); | ||
| }} | ||
| > | ||
| {i} | ||
| </a> | ||
| </li> | ||
| ))} | ||
| <li | ||
| className={classNames('page-item', { | ||
| disabled: currentPage === numberOfPage, | ||
| })} | ||
| > | ||
| <a | ||
| data-cy="nextLink" | ||
| className={classNames('page-link', { | ||
| disabled: currentPage === numberOfPage, | ||
| })} | ||
| onClick={e => { | ||
| if (currentPage !== numberOfPage) { | ||
| onPageChange(currentPage + 1); | ||
| } | ||
|
|
||
| e.preventDefault(); | ||
| }} | ||
| aria-disabled={currentPage === numberOfPage} | ||
| > | ||
| » | ||
| </a> | ||
| </li> | ||
| </ul> | ||
| ); | ||
| }; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The app must read and write the
pageandperPagequery params via React Router so reloading restores the current view. Import and use appropriate router hooks (e.g.useSearchParamsin react-router-dom v6 oruseLocation/useHistoryin v5) anduseEffectto 1) read?pageand?perPageon mount and initialize state, and 2) update the URL whenevercurrentPageorperPagechange. This addresses the required behavior to save?page=2&perPage=7in the URL (checklist item #13).