Skip to content

Commit

Permalink
Convert Pagination to infinite scroll (#1627)
Browse files Browse the repository at this point in the history
* Infinite scroll experiment on artifacts page

* convert all pagination to infinite scroll

* add inf scroll to art exclusion
  • Loading branch information
frzyc authored Mar 8, 2024
1 parent 57d3a8f commit e322213
Show file tree
Hide file tree
Showing 12 changed files with 367 additions and 379 deletions.
92 changes: 38 additions & 54 deletions apps/frontend/src/app/Components/Artifact/ArtifactSwapModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import {
useForceUpdate,
useMediaQueryUp,
} from '@genshin-optimizer/common/react-util'
import { clamp, filterFunction } from '@genshin-optimizer/common/util'
import { useOnScreen } from '@genshin-optimizer/common/ui'
import { filterFunction } from '@genshin-optimizer/common/util'
import { imgAssets } from '@genshin-optimizer/gi/assets'
import type { ArtifactSlotKey } from '@genshin-optimizer/gi/consts'
import { useDatabase } from '@genshin-optimizer/gi/db-ui'
Expand All @@ -24,7 +25,6 @@ import {
useEffect,
useMemo,
useReducer,
useRef,
useState,
} from 'react'
import { useTranslation } from 'react-i18next'
Expand All @@ -39,7 +39,7 @@ import CloseButton from '../CloseButton'
import CompareBuildButton from '../CompareBuildButton'
import ImgIcon from '../Image/ImgIcon'
import ModalWrapper from '../ModalWrapper'
import PageAndSortOptionSelect from '../PageAndSortOptionSelect'
import ShowingAndSortOptionSelect from '../ShowingAndSortOptionSelect'

const numToShowMap = { xs: 2 * 3, sm: 2 * 3, md: 3 * 3, lg: 4 * 3, xl: 4 * 3 }
const ArtifactEditor = lazy(() => import('../../PageArtifact/ArtifactEditor'))
Expand Down Expand Up @@ -86,53 +86,42 @@ export default function ArtifactSwapModal({
}, [database, forceUpdate])

const brPt = useMediaQueryUp()
const maxNumArtifactsToDisplay = numToShowMap[brPt]

const [pageIdex, setpageIdex] = useState(0)
const invScrollRef = useRef<HTMLDivElement>(null)

const filterConfigs = useMemo(() => artifactFilterConfigs(), [])
const totalArtNum = database.arts.values.filter(
(s) => s.slotKey === filterOption.slotKeys[0]
).length
const artIdList = useMemo(() => {

const artifactIds = useMemo(() => {
const filterFunc = filterFunction(filterOption, filterConfigs)
return (
dbDirty && database.arts.values.filter(filterFunc).map((art) => art.id)
)
}, [dbDirty, database, filterConfigs, filterOption])

const { artifactIdsToShow, numPages, currentPageIndex } = useMemo(() => {
const numPages = Math.ceil(artIdList.length / maxNumArtifactsToDisplay)
const currentPageIndex = clamp(pageIdex, 0, numPages - 1)
return {
artifactIdsToShow: artIdList.slice(
currentPageIndex * maxNumArtifactsToDisplay,
(currentPageIndex + 1) * maxNumArtifactsToDisplay
),
numPages,
currentPageIndex,
}
}, [artIdList, pageIdex, maxNumArtifactsToDisplay])
const [numShow, setNumShow] = useState(numToShowMap[brPt])
// reset the numShow when artifactIds changes
useEffect(() => {
artifactIds && setNumShow(numToShowMap[brPt])
}, [artifactIds, brPt])

// for pagination
const totalShowing =
artIdList.length !== totalArtNum
? `${artIdList.length}/${totalArtNum}`
: `${totalArtNum}`
const setPage = useCallback(
(e, value) => {
invScrollRef.current?.scrollIntoView({ behavior: 'smooth' })
setpageIdex(value - 1)
},
[setpageIdex, invScrollRef]
const [element, setElement] = useState<HTMLElement | undefined>()
const trigger = useOnScreen(element)
const shouldIncrease = trigger && numShow < artifactIds.length
useEffect(() => {
if (!shouldIncrease) return
setNumShow((num) => num + numToShowMap[brPt])
}, [shouldIncrease, brPt])

const artifactIdsToShow = useMemo(
() => artifactIds.slice(0, numShow),
[artifactIds, numShow]
)

const paginationProps = {
count: numPages,
page: currentPageIndex + 1,
onChange: setPage,
}
const totalShowing =
artifactIds.length !== totalArtNum
? `${artifactIds.length}/${totalArtNum}`
: `${totalArtNum}`

const showingTextProps = {
numShowing: artifactIdsToShow.length,
Expand Down Expand Up @@ -181,7 +170,7 @@ export default function ArtifactSwapModal({
<ArtifactFilterDisplay
filterOption={filterOption}
filterOptionDispatch={filterOptionDispatch}
filteredIds={artIdList}
filteredIds={artifactIds}
disableSlotFilter
/>
</Suspense>
Expand All @@ -195,10 +184,7 @@ export default function ArtifactSwapModal({
alignItems="flex-end"
flexWrap="wrap"
>
<PageAndSortOptionSelect
paginationProps={paginationProps}
showingTextProps={showingTextProps}
/>
<ShowingAndSortOptionSelect showingTextProps={showingTextProps} />
</Box>
<Button
fullWidth
Expand Down Expand Up @@ -227,19 +213,17 @@ export default function ArtifactSwapModal({
</Grid>
</Suspense>
</Box>
{numPages > 1 && (
<Box
pt={2}
display="flex"
justifyContent="space-between"
alignItems="center"
flexWrap="wrap"
>
<PageAndSortOptionSelect
paginationProps={paginationProps}
showingTextProps={showingTextProps}
/>
</Box>
{artifactIds.length !== artifactIdsToShow.length && (
<Skeleton
ref={(node) => {
if (!node) return
setElement(node)
}}
sx={{ borderRadius: 1, mt: 1 }}
variant="rectangular"
width="100%"
height={100}
/>
)}
</CardContent>
</CardDark>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
import { Pagination, Typography } from '@mui/material'
import { Typography } from '@mui/material'
import type { TFunction } from 'i18next'
import { Trans } from 'react-i18next'
import SortByButton from '../Components/SortByButton'

type PaginationProps = {
count: number
page: number
onChange: (_: any, value: number) => void
}
import SortByButton from './SortByButton'

type ShowingItemProps = {
numShowing: number
Expand All @@ -24,31 +18,22 @@ type SortByButtonProps = {
onChangeAsc: (value: boolean) => void
}

export default function PageAndSortOptionSelect({
paginationProps,
export default function ShowingAndSortOptionSelect({
showingTextProps,
displaySort = false,
sortByButtonProps = undefined,
}: {
paginationProps: PaginationProps
showingTextProps: ShowingItemProps
displaySort?: boolean
sortByButtonProps?: SortByButtonProps
}) {
return (
<>
<Pagination
count={paginationProps.count}
page={paginationProps.page}
onChange={paginationProps.onChange}
/>
<ShowingItem
numShowing={showingTextProps.numShowing}
total={showingTextProps.total}
t={showingTextProps.t}
namespace={showingTextProps.namespace}
/>
{displaySort && sortByButtonProps && (
{sortByButtonProps && (
<SortByButton
sortKeys={sortByButtonProps.sortKeys}
value={sortByButtonProps.value}
Expand Down
89 changes: 35 additions & 54 deletions apps/frontend/src/app/Components/Weapon/WeaponSwapModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,8 @@ import {
useForceUpdate,
useMediaQueryUp,
} from '@genshin-optimizer/common/react-util'
import {
clamp,
filterFunction,
sortFunction,
} from '@genshin-optimizer/common/util'
import { useOnScreen } from '@genshin-optimizer/common/ui'
import { filterFunction, sortFunction } from '@genshin-optimizer/common/util'
import { imgAssets } from '@genshin-optimizer/gi/assets'
import type {
RarityKey,
Expand All @@ -24,6 +21,7 @@ import {
CardContent,
Divider,
Grid,
Skeleton,
TextField,
ToggleButton,
Typography,
Expand All @@ -35,7 +33,6 @@ import {
useDeferredValue,
useEffect,
useMemo,
useRef,
useState,
} from 'react'
import { useTranslation } from 'react-i18next'
Expand All @@ -52,7 +49,7 @@ import CloseButton from '../CloseButton'
import CompareBuildButton from '../CompareBuildButton'
import ImgIcon from '../Image/ImgIcon'
import ModalWrapper from '../ModalWrapper'
import PageAndSortOptionSelect from '../PageAndSortOptionSelect'
import ShowingAndSortOptionSelect from '../ShowingAndSortOptionSelect'
import SolidToggleButtonGroup from '../SolidToggleButtonGroup'
import WeaponSelectionModal from './WeaponSelectionModal'

Expand Down Expand Up @@ -101,16 +98,12 @@ export default function WeaponSwapModal({
)

const brPt = useMediaQueryUp()
const maxNumWeaponsToDisplay = numToShowMap[brPt]

const [pageIndex, setpageIndex] = useState(0)
const invScrollRef = useRef<HTMLDivElement>(null)

const [rarity, setRarity] = useState<RarityKey[]>([5, 4, 3])
const [searchTerm, setSearchTerm] = useState('')
const deferredSearchTerm = useDeferredValue(searchTerm)

const weaponIdList = useMemo(
const weaponIds = useMemo(
() =>
(dbDirty &&
database.weapons.values
Expand All @@ -132,34 +125,27 @@ export default function WeaponSwapModal({
[dbDirty, database, rarity, weaponTypeKey, deferredSearchTerm]
)

const { weaponIdsToShow, numPages, currentPageIndex } = useMemo(() => {
const numPages = Math.ceil(weaponIdList.length / maxNumWeaponsToDisplay)
const currentPageIndex = clamp(pageIndex, 0, numPages - 1)
return {
weaponIdsToShow: weaponIdList.slice(
currentPageIndex * maxNumWeaponsToDisplay,
(currentPageIndex + 1) * maxNumWeaponsToDisplay
),
numPages,
currentPageIndex,
}
}, [weaponIdList, pageIndex, maxNumWeaponsToDisplay])
const [numShow, setNumShow] = useState(numToShowMap[brPt])
// reset the numShow when artifactIds changes
useEffect(() => {
weaponIds && setNumShow(numToShowMap[brPt])
}, [weaponIds, brPt])

// for pagination
const totalShowing = `${weaponIdList.length}`
const setPage = useCallback(
(e, value) => {
invScrollRef.current?.scrollIntoView({ behavior: 'smooth' })
setpageIndex(value - 1)
},
[setpageIndex, invScrollRef]
const [element, setElement] = useState<HTMLElement | undefined>()
const trigger = useOnScreen(element)
const shouldIncrease = trigger && numShow < weaponIds.length
useEffect(() => {
if (!shouldIncrease) return
setNumShow((num) => num + numToShowMap[brPt])
}, [shouldIncrease, brPt])

const weaponIdsToShow = useMemo(
() => weaponIds.slice(0, numShow),
[weaponIds, numShow]
)

const paginationProps = {
count: numPages,
page: currentPageIndex + 1,
onChange: setPage,
}
// for pagination
const totalShowing = `${weaponIds.length}`

const showingTextProps = {
numShowing: weaponIdsToShow.length,
Expand Down Expand Up @@ -247,10 +233,7 @@ export default function WeaponSwapModal({
alignItems="center"
flexWrap="wrap"
>
<PageAndSortOptionSelect
paginationProps={paginationProps}
showingTextProps={showingTextProps}
/>
<ShowingAndSortOptionSelect showingTextProps={showingTextProps} />
</Box>
<Button
fullWidth
Expand All @@ -271,19 +254,17 @@ export default function WeaponSwapModal({
</Grid>
))}
</Grid>
{numPages > 1 && (
<Box
pt={1}
display="flex"
justifyContent="space-between"
alignItems="center"
flexWrap="wrap"
>
<PageAndSortOptionSelect
paginationProps={paginationProps}
showingTextProps={showingTextProps}
/>
</Box>
{weaponIds.length !== weaponIdsToShow.length && (
<Skeleton
ref={(node) => {
if (!node) return
setElement(node)
}}
sx={{ borderRadius: 1 }}
variant="rectangular"
width="100%"
height={100}
/>
)}
</CardContent>
</CardDark>
Expand Down
Loading

0 comments on commit e322213

Please sign in to comment.