Skip to content

Commit

Permalink
Merge pull request #6977 from fjordllc/feature/enable-react-paginatio…
Browse files Browse the repository at this point in the history
…n-to-use-browser-back-and-forward-button

ページネーションの戻る、進むボタンの有効化
  • Loading branch information
komagata authored Oct 23, 2023
2 parents 50514e2 + 332390f commit c8f1423
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 98 deletions.
23 changes: 5 additions & 18 deletions app/javascript/components/AdminCompanies.jsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
import React, { useState, useEffect } from 'react'
import queryString from 'query-string'
import React from 'react'
import useSWR from 'swr'
import fetcher from '../fetcher'
import Pagination from './Pagination'
import usePage from './hooks/usePage'

export default function AdminCompanies() {
const per = 20
const neighbours = 4
const defaultPage = parseInt(queryString.parse(location.search).page) || 1
const [page, setPage] = useState(defaultPage)

useEffect(() => {
setPage(page)
}, [page])
const { page, setPage } = usePage()

const { data, error } = useSWR(
`/api/admin/companies.json?page=${page}&per=${per}`,
Expand All @@ -21,20 +15,14 @@ export default function AdminCompanies() {
if (error) return <>An error has occurred.</>
if (!data) return <>Loading...</>

const handlePaginate = (p) => {
setPage(p)
window.history.pushState(null, null, `/admin/companies?page=${p}`)
}

return (
<div data-testid="admin-companies">
{data.total_pages > 1 && (
<Pagination
sum={data.total_pages * per}
per={per}
neighbours={neighbours}
page={page}
onChange={(e) => handlePaginate(e.page)}
setPage={setPage}
/>
)}
<div className="admin-table">
Expand All @@ -60,9 +48,8 @@ export default function AdminCompanies() {
<Pagination
sum={data.total_pages * per}
per={per}
neighbours={neighbours}
page={page}
onChange={(e) => handlePaginate(e.page)}
setPage={setPage}
/>
)}
</div>
Expand Down
23 changes: 5 additions & 18 deletions app/javascript/components/Bookmarks.jsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,21 @@
import React, { useState, useEffect } from 'react'
import queryString from 'query-string'
import React, { useState } from 'react'
import useSWR, { useSWRConfig } from 'swr'
import fetcher from '../fetcher'
import Bootcamp from '../bootcamp'
import UserIcon from './UserIcon'
import Pagination from './Pagination'
import usePage from './hooks/usePage'

export default function Bookmarks() {
const [editable, setEditable] = useState(false)
const per = 20
const neighbours = 4
const defaultPage = parseInt(queryString.parse(location.search).page) || 1
const [page, setPage] = useState(defaultPage)
const { page, setPage } = usePage()
const bookmarksUrl = `/api/bookmarks.json?page=${page}&per=${per}`

useEffect(() => {
setPage(page)
}, [page])

const { data, error } = useSWR(bookmarksUrl, fetcher)
if (error) return <>エラーが発生しました。</>
if (!data) return <>ロード中…</>

const handlePaginate = (p) => {
setPage(p)
window.history.pushState(null, null, `/current_user/bookmarks?page=${p}`)
}

if (data.totalPages === 0) {
return <NoBookmarks />
} else {
Expand Down Expand Up @@ -64,9 +53,8 @@ export default function Bookmarks() {
<Pagination
sum={data.totalPages * per}
per={per}
neighbours={neighbours}
page={page}
onChange={(e) => handlePaginate(e.page)}
setPage={setPage}
/>
)}
<div className="card-list a-card">
Expand All @@ -88,9 +76,8 @@ export default function Bookmarks() {
<Pagination
sum={data.totalPages * per}
per={per}
neighbours={neighbours}
page={page}
onChange={(e) => handlePaginate(e.page)}
setPage={setPage}
/>
)}
</div>
Expand Down
23 changes: 5 additions & 18 deletions app/javascript/components/Events.jsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,17 @@
import React, { useState, useEffect } from 'react'
import queryString from 'query-string'
import React from 'react'
import useSWR from 'swr'
import Pagination from './Pagination'
import LoadingListPlaceholder from './LoadingListPlaceholder'
import UserIcon from './UserIcon'
import fetcher from '../fetcher'
import usePage from './hooks/usePage'

export default function Events() {
const per = 20
const neighbours = 4
const defaultPage = parseInt(queryString.parse(location.search).page) || 1
const [page, setPage] = useState(defaultPage)

useEffect(() => {
setPage(page)
}, [page])
const { page, setPage } = usePage()

const { data, error } = useSWR(`/api/events?page=${page}`, fetcher)

const handlePaginate = (p) => {
setPage(p)
window.history.pushState(null, null, `/events?page=${p}`)
}

if (error) return <>エラーが発生しました。</>
if (!data) {
return (
Expand All @@ -41,9 +30,8 @@ export default function Events() {
<Pagination
sum={data.total_pages * per}
per={per}
neighbours={neighbours}
page={page}
onChange={(e) => handlePaginate(e.page)}
setPage={setPage}
/>
)}
<ul className="card-list a-card">
Expand All @@ -55,9 +43,8 @@ export default function Events() {
<Pagination
sum={data.total_pages * per}
per={per}
neighbours={neighbours}
page={page}
onChange={(e) => handlePaginate(e.page)}
setPage={setPage}
/>
)}
</div>
Expand Down
76 changes: 44 additions & 32 deletions app/javascript/components/Pagination.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useRef, useEffect } from 'react'
import React from 'react'

const createRange = (a, z) => {
const items = []
Expand All @@ -16,104 +16,116 @@ const createNumbers = (current, neighbours, max) => {
return createRange(first, last)
}

const Pagination = (props) => {
const isFirstRender = useRef(true)
const [page, setPage] = useState(props.page)
const [numbers, setNumbers] = useState([])
const totalPage = Math.ceil(props.sum / props.per)

useEffect(() => {
setNumbers(createNumbers(page, props.neighbours, totalPage))

// 初回レンダリング時はスキップし、変数を更新する
if (isFirstRender.current) {
isFirstRender.current = false
return
const Pagination = ({ sum, per, neighbours = 4, page, setPage }) => {
const totalPage = Math.ceil(sum / per)
const numbers = createNumbers(page, neighbours, totalPage)
const handlePaginate = (pageNumber) => {
setPage(pageNumber)
const url = new URL(location)
if (pageNumber > 1) {
url.searchParams.set('page', pageNumber)
} else {
url.searchParams.delete('page')
}

props.onChange({ page: page })
}, [page])
window.history.pushState(null, null, url)
window.scrollTo(0, 0)
}

return (
<nav className="pagination">
{totalPage !== 0 && (
<ul className="pagination__items">
<First page={page} setPage={setPage} />
<Prev page={page} setPage={setPage} />
<First page={page} handlePaginate={handlePaginate} />
<Prev page={page} handlePaginate={handlePaginate} />
{numbers[0] > 1 && <ThreeDots />}
{numbers.map((i) => {
return <Number key={i} page={page} setPage={setPage} i={i} />
return (
<Number
key={i}
page={page}
handlePaginate={handlePaginate}
i={i}
/>
)
})}
{numbers[numbers.length - 1] < totalPage && <ThreeDots />}
<Next page={page} setPage={setPage} totalPage={totalPage} />
<Last page={page} setPage={setPage} totalPage={totalPage} />
<Next
page={page}
handlePaginate={handlePaginate}
totalPage={totalPage}
/>
<Last
page={page}
handlePaginate={handlePaginate}
totalPage={totalPage}
/>
</ul>
)}
</nav>
)
}

const First = ({ setPage, page }) => {
const First = ({ page, handlePaginate }) => {
const disabled = page === 1 ? ' is-disabled' : ''

return (
<li className={'pagination__item is-prev' + disabled}>
<button
onClick={() => setPage(1)}
onClick={() => handlePaginate(1)}
className={'pagination__item-link' + disabled}>
<i className="fas fa-angle-double-left" />
</button>
</li>
)
}

const Prev = ({ page, setPage }) => {
const Prev = ({ page, handlePaginate }) => {
const disabled = page === 1 ? ' is-disabled' : ''

return (
<li className={'pagination__item is-prev' + disabled}>
<button
onClick={() => page !== 1 && setPage(page - 1)}
onClick={() => page !== 1 && handlePaginate(page - 1)}
className={'pagination__item-link' + disabled}>
<i className="fas fa-angle-left" />
</button>
</li>
)
}

const Number = ({ page, setPage, i }) => {
const Number = ({ page, handlePaginate, i }) => {
return (
<li className="pagination__item">
<button
onClick={() => setPage(i)}
onClick={() => handlePaginate(i)}
className={'pagination__item-link' + (i === page ? ' is-active' : '')}>
{i}
</button>
</li>
)
}

const Next = ({ page, setPage, totalPage }) => {
const Next = ({ page, handlePaginate, totalPage }) => {
const disabled = page === totalPage ? ' is-disabled' : ''

return (
<li className={'pagination__item is-next' + disabled}>
<button
onClick={() => page !== totalPage && setPage(page + 1)}
onClick={() => page !== totalPage && handlePaginate(page + 1)}
className={'pagination__item-link' + disabled}>
<i className="fas fa-angle-right" />
</button>
</li>
)
}

const Last = ({ page, setPage, totalPage }) => {
const Last = ({ page, handlePaginate, totalPage }) => {
const disabled = page === totalPage ? ' is-disabled' : ''

return (
<li className={'pagination__item is-next' + disabled}>
<button
onClick={() => setPage(totalPage)}
onClick={() => handlePaginate(totalPage)}
className={'pagination__item-link' + disabled}>
<i className="fas fa-angle-double-right" />
</button>
Expand Down
16 changes: 4 additions & 12 deletions app/javascript/components/Reports.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import React, { useState, useEffect } from 'react'
import useSWR from 'swr'
import queryString from 'query-string'
import fetcher from '../fetcher'
import LoadingListPlaceholder from './LoadingListPlaceholder'
import Report from './Report'
import Pagination from './Pagination'
import PracticeFilterDropdown from './PracticeFilterDropdown'
import UnconfirmedLink from './UnconfirmedLink'
import usePage from './hooks/usePage'

export default function Reports({
all = false,
Expand All @@ -19,15 +19,9 @@ export default function Reports({
displayPagination = true
}) {
const per = 20
const neighbours = 4
const defaultPage = parseInt(queryString.parse(location.search).page) || 1
const [page, setPage] = useState(defaultPage)
const { page, setPage } = usePage()
const [userPracticeId, setUserPracticeId] = useState('')

useEffect(() => {
setPage(page)
}, [page])

useEffect(() => {
setUserPracticeId(userPracticeId)
}, [userPracticeId])
Expand Down Expand Up @@ -92,9 +86,8 @@ export default function Reports({
<Pagination
sum={data.totalPages * per}
per={per}
neighbours={neighbours}
page={page}
onChange={(e) => setPage(e.page)}
setPage={setPage}
/>
)}
<div className="card-list a-card">
Expand All @@ -118,9 +111,8 @@ export default function Reports({
<Pagination
sum={data.totalPages * per}
per={per}
neighbours={neighbours}
page={page}
onChange={(e) => setPage(e.page)}
setPage={setPage}
/>
)}
</div>
Expand Down
25 changes: 25 additions & 0 deletions app/javascript/components/hooks/usePage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { useEffect, useState } from 'react'
import queryString from 'query-string'

const usePage = () => {
const defaultPage = parseInt(queryString.parse(location.search).page) || 1
const [page, setPage] = useState(defaultPage)

const getPageQueryParam = () => {
return parseInt(queryString.parse(location.search).page) || 1
}

useEffect(() => {
const handlePopstate = () => {
setPage(getPageQueryParam())
}
window.addEventListener('popstate', handlePopstate)
return () => {
window.removeEventListener('popstate', handlePopstate)
}
}, [])

return { page, setPage }
}

export default usePage
Loading

0 comments on commit c8f1423

Please sign in to comment.