Files
games-frontend-js/src/components/Pagination.tsx
T
john-okeefe 45dd783964 refactor(nav): migrate header, dashboard chrome and discovery UI to v3
- Header/MobileBar: MenuRoot/Positioner/Content + Portal + Tooltip
  shims, ghost icon buttons, 2rem padded user/settings menus, hover
  token gray.700; MobileBar drawer API (open/onOpenChange/finalFocusEl)
- FilterBar/ActiveFilters: DrawerRoot/CloseTrigger, Divider -> Separator,
  Tag shim, FixedSelect with typed handlers and width-preserving
  chakraStyles, blue active-filter pills untouched
- Pagination: NumberInputRoot/Field + NativeSelect shims, first/last
  arrows back to double chevrons (LuChevronsLeft/Right), single chevrons
  kept for prev/next
- Search/SearchModal, Home, NoGames, LoadingModal, DashboardLoadingModal:
  Dialog/Toaster-era props, gap/align/textAlign renames; App.test target
  content updated accordingly
2026-09-06 10:30:21 -04:00

214 lines
7.5 KiB
TypeScript

import React from 'react'
import {
Flex,
Grid,
GridItem,
IconButton,
Text,
Portal,
} from '@chakra-ui/react'
import {NumberInputRoot, NumberInputField} from './ui/number-input'
import { NativeSelect } from '@chakra-ui/react'
import { LuChevronLeft, LuChevronRight, LuChevronsLeft, LuChevronsRight } from 'react-icons/lu'
import {Tooltip} from './ui/tooltip'
import { useHookstate } from '@hookstate/core'
import { gameDashboardState } from '../stateManagement/gameState'
import { loadingState } from '../stateManagement/loadingState'
import { adminMode } from '../stateManagement/userState'
import getWithFilters from '../componentUtils/getWithFilters'
import { ratingState, steamRatingState } from "../stateManagement/ratingState";
import {useColorModeValue} from "./ui/color-mode";
import {useMediaQuery} from "@chakra-ui/react";
export default function Pagination() {
const gamesState = useHookstate(gameDashboardState)
const games = gamesState.get()
const admin = useHookstate(adminMode).get()
const loadedState = useHookstate(loadingState)
const pageIndex = games.count.currentPage
const pageSize = games.count.limit
const pageCount = games.count.pages
const bg = useColorModeValue('gray.50', 'transparent')
const useRatingState = useHookstate(ratingState).get()
const useSteamRatingState = useHookstate(steamRatingState).get()
const [isSmallerThan768] = useMediaQuery(['(max-width: 768px)'])
const setPageSize = async (limit: number) => await getWithFilters(
gamesState,
loadedState,
admin,
games.count.currentPage,
limit,
games.searchParams,
games.filters,
useRatingState,
useSteamRatingState
)
const gotoPage = async (page: number) => await getWithFilters(
gamesState,
loadedState,
admin,
page,
games.count.limit,
games.searchParams,
games.filters,
useRatingState,
useSteamRatingState
)
const previousPage = async () => await getWithFilters(
gamesState,
loadedState,
admin,
games.pagination.prev.page,
games.count.limit,
games.searchParams,
games.filters,
useRatingState,
useSteamRatingState
)
const nextPage = async () => await getWithFilters(
gamesState,
loadedState,
admin,
games.pagination.next.page,
games.count.limit,
games.searchParams,
games.filters,
useRatingState,
useSteamRatingState
)
return (
<Grid mb={'6'} justifyItems={{
base: 'center'
}} alignItems={{
base: 'center'
}} templateAreas={{
base: `
"backArrows pageNumber forwardArrows"
"backArrows countPerPage forwardArrows"
"backArrows gamesFound forwardArrows"
`,
md: `"backArrows pageNumber goToPage countPerPage gamesFound forwardArrows"`
}}>
<GridItem area={"backArrows"}>
<Flex>
<Tooltip content="First Page">
<IconButton
aria-label={'First Page'}
onMouseDown={() => gotoPage(0)}
disabled={pageIndex <= 1}
mr={4}
>
<LuChevronsLeft />
</IconButton>
</Tooltip>
<Tooltip content="Previous Page">
<IconButton
aria-label={'Previous Page'}
onMouseDown={previousPage}
disabled={pageIndex <= 1}
>
<LuChevronLeft />
</IconButton>
</Tooltip>
</Flex>
</GridItem>
<GridItem area={"pageNumber"}>
<Text mr={{ md: 8 }}>
Page{' '}
<Text fontWeight="bold" as="span">
{pageIndex}
</Text>{' '}
of{' '}
<Text fontWeight="bold" as="span">
{pageCount}
</Text>
</Text>
</GridItem>
{!isSmallerThan768 &&
<GridItem area={"goToPage"}>
<Text mb={'1'}>Go to Page:</Text>
<NumberInputRoot
bg={bg}
rounded={'md'}
w={{ base: 20, md: 28 }}
min={1}
max={pageCount}
value={String(pageIndex)}
onValueChange={(e) => {
const page = e.value ? Number(e.value) : 1
gotoPage(page)
}}
>
<NumberInputField
borderWidth="1px"
borderStyle="solid"
borderColor={{ base: "gray.500", _invalid: "red.500" }}
/>
</NumberInputRoot>
</GridItem>
}
<GridItem area={"countPerPage"}>
<Text mb={'1'}>Count Per Page:</Text>
<NativeSelect.Root
ml={{
base: '4',
md: '0'
}}
w={{ base: 20, md: 32 }}
>
<NativeSelect.Field
rounded={'md'}
borderWidth={'1px'}
borderStyle={'solid'}
borderColor={'gray.500'}
bg={bg}
value={pageSize}
onChange={(e: any) => {
setPageSize(Number(e.target.value))
}}
>
{[10, 20, 30, 40, 50].map((pageSize) => (
<option key={pageSize} value={pageSize}>
{pageSize}
</option>
))}
</NativeSelect.Field>
<NativeSelect.Indicator />
</NativeSelect.Root>
</GridItem>
<GridItem area={'gamesFound'}>
<Text>Games Found: {games.count.totalGames}</Text>
</GridItem>
<GridItem area={"forwardArrows"}>
<Flex justifySelf={'end'}>
<Tooltip content="Next Page">
<IconButton
aria-label={'Next Page'}
onMouseDown={nextPage}
disabled={pageIndex >= pageCount}
>
<LuChevronRight />
</IconButton>
</Tooltip>
<Tooltip content="Last Page">
<IconButton
aria-label={'Last Page'}
onMouseDown={() => gotoPage(pageCount)}
disabled={pageIndex >= pageCount}
ml={4}
>
<LuChevronsRight />
</IconButton>
</Tooltip>
</Flex>
</GridItem>
</Grid>
)
}