132 lines
4.3 KiB
TypeScript
132 lines
4.3 KiB
TypeScript
import { PaginationWithPageNumbers } from 'components/Pagination'
|
|
import { MAX_GAMES_PER_PAGE } from 'constants.ts'
|
|
import { useDidMount, useGames, useNDKContext } from 'hooks'
|
|
import { useMemo, useRef, useState } from 'react'
|
|
import { GameCard } from '../components/GameCard'
|
|
import '../styles/pagination.css'
|
|
import '../styles/search.css'
|
|
import '../styles/styles.css'
|
|
import { createSearchParams, useNavigate } from 'react-router-dom'
|
|
import { appRoutes } from 'routes'
|
|
import { scrollIntoView } from 'utils'
|
|
import { SearchInput } from 'components/SearchInput'
|
|
|
|
export const GamesPage = () => {
|
|
const scrollTargetRef = useRef<HTMLDivElement>(null)
|
|
const navigate = useNavigate()
|
|
const { fetchMods } = useNDKContext()
|
|
const searchTermRef = useRef<HTMLInputElement>(null)
|
|
const games = useGames()
|
|
const [gamesWithMods, setGamesWithMods] = useState<string[]>([])
|
|
const [currentPage, setCurrentPage] = useState(1)
|
|
|
|
useDidMount(() => {
|
|
fetchMods({ limit: 100, source: window.location.host }).then((mods) => {
|
|
mods.sort((a, b) => b.published_at - a.published_at)
|
|
|
|
const gameNames = new Set<string>()
|
|
|
|
mods.map((mod) => gameNames.add(mod.game))
|
|
setGamesWithMods(Array.from(gameNames))
|
|
})
|
|
})
|
|
|
|
const sortedGames = useMemo(() => {
|
|
// Create a map for the order array, assigning each game name a rank based on its index.
|
|
const orderMap = new Map<string, number>()
|
|
gamesWithMods.forEach((gameName, index) => {
|
|
orderMap.set(gameName, index)
|
|
})
|
|
|
|
const gamesArray = [...games]
|
|
|
|
return gamesArray.sort((a, b) => {
|
|
const indexA = orderMap.get(a['Game Name'])
|
|
const indexB = orderMap.get(b['Game Name'])
|
|
|
|
// Games that are not in the order array should go after those that are in the array.
|
|
if (indexA !== undefined && indexB !== undefined) {
|
|
return indexA - indexB
|
|
} else if (indexA !== undefined) {
|
|
return -1 // a comes before b
|
|
} else if (indexB !== undefined) {
|
|
return 1 // b comes before a
|
|
} else {
|
|
return 0 // keep original order if neither is in the array
|
|
}
|
|
})
|
|
}, [games, gamesWithMods])
|
|
|
|
// Pagination logic
|
|
const totalGames = sortedGames.length
|
|
const totalPages = Math.ceil(totalGames / MAX_GAMES_PER_PAGE)
|
|
const startIndex = (currentPage - 1) * MAX_GAMES_PER_PAGE
|
|
const endIndex = startIndex + MAX_GAMES_PER_PAGE
|
|
const currentGames = sortedGames.slice(startIndex, endIndex)
|
|
|
|
const handlePageChange = (page: number) => {
|
|
if (page >= 1 && page <= totalPages) {
|
|
scrollIntoView(scrollTargetRef.current)
|
|
setCurrentPage(page)
|
|
}
|
|
}
|
|
|
|
const handleSearch = () => {
|
|
const value = searchTermRef.current?.value || '' // Access the input value from the ref
|
|
if (value !== '') {
|
|
const searchParams = createSearchParams({
|
|
q: value,
|
|
kind: 'Games'
|
|
})
|
|
navigate({ pathname: appRoutes.search, search: `?${searchParams}` })
|
|
}
|
|
}
|
|
|
|
// Handle "Enter" key press inside the input
|
|
const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
|
|
if (event.key === 'Enter') {
|
|
handleSearch()
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className='InnerBodyMain'>
|
|
<div className='ContainerMain'>
|
|
<div
|
|
className='IBMSecMainGroup IBMSecMainGroupAlt'
|
|
ref={scrollTargetRef}
|
|
>
|
|
<div className='IBMSecMain'>
|
|
<div className='SearchMainWrapper'>
|
|
<div className='IBMSMTitleMain'>
|
|
<h2 className='IBMSMTitleMainHeading'>Games</h2>
|
|
</div>
|
|
<SearchInput
|
|
ref={searchTermRef}
|
|
handleKeyDown={handleKeyDown}
|
|
handleSearch={handleSearch}
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div className='IBMSecMain IBMSMListWrapper'>
|
|
<div className='IBMSMList IBMSMListFeaturedAlt'>
|
|
{currentGames.map((game) => (
|
|
<GameCard
|
|
key={game['Game Name']}
|
|
title={game['Game Name']}
|
|
imageUrl={game['Boxart image']}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
<PaginationWithPageNumbers
|
|
currentPage={currentPage}
|
|
totalPages={totalPages}
|
|
handlePageChange={handlePageChange}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|