Add infinite scrolling to collections
This commit is contained in:
parent
e1dfb73544
commit
34c93af273
3 changed files with 206 additions and 107 deletions
|
|
@ -5,8 +5,10 @@ import { useCookies } from 'react-cookie'
|
|||
import { queryTypes, useQueryState } from 'next-usequerystate'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import InfiniteScroll from 'react-infinite-scroll-component'
|
||||
|
||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
||||
import clonedeep from 'lodash.clonedeep'
|
||||
|
||||
import api from '~utils/api'
|
||||
import { elements, allElement } from '~utils/Element'
|
||||
|
|
@ -30,9 +32,7 @@ const ProfileRoute: React.FC = () => {
|
|||
// Set up cookies
|
||||
const [cookies] = useCookies(['account'])
|
||||
const headers = (cookies.account) ? {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${cookies.account.access_token}`
|
||||
}
|
||||
'Authorization': `Bearer ${cookies.account.access_token}`
|
||||
} : {}
|
||||
|
||||
// Set up router
|
||||
|
|
@ -54,6 +54,11 @@ const ProfileRoute: React.FC = () => {
|
|||
const [raid, setRaid] = useState<Raid>()
|
||||
const [user, setUser] = useState<User>(emptyUser)
|
||||
|
||||
// Set up infinite scrolling-related states
|
||||
const [recordCount, setRecordCount] = useState(0)
|
||||
const [currentPage, setCurrentPage] = useState(1)
|
||||
const [totalPages, setTotalPages] = useState(1)
|
||||
|
||||
// Set up filter-specific query states
|
||||
// Recency is in seconds
|
||||
const [element, setElement] = useQueryState("element", {
|
||||
|
|
@ -100,17 +105,18 @@ const ProfileRoute: React.FC = () => {
|
|||
}
|
||||
}, [])
|
||||
|
||||
const fetchProfile = useCallback(() => {
|
||||
const fetchProfile = useCallback(({ replace }: { replace: boolean }) => {
|
||||
const filters = {
|
||||
params: {
|
||||
element: (element != -1) ? element : undefined,
|
||||
raid: (raid) ? raid.id : undefined,
|
||||
recency: (recency != -1) ? recency : undefined
|
||||
recency: (recency != -1) ? recency : undefined,
|
||||
page: currentPage
|
||||
}
|
||||
}
|
||||
|
||||
if (username && !Array.isArray(username))
|
||||
api.endpoints.users.getOne({ id: username , params: {...filters, ...headers} })
|
||||
api.endpoints.users.getOne({ id: username , params: {...filters, ...{ headers: headers }}})
|
||||
.then(response => {
|
||||
setUser({
|
||||
id: response.data.user.id,
|
||||
|
|
@ -120,15 +126,32 @@ const ProfileRoute: React.FC = () => {
|
|||
private: response.data.user.private
|
||||
})
|
||||
|
||||
const parties: Party[] = response.data.user.parties
|
||||
setParties(parties.sort((a, b) => (a.created_at > b.created_at) ? -1 : 1))
|
||||
setTotalPages(response.data.parties.total_pages)
|
||||
setRecordCount(response.data.parties.count)
|
||||
|
||||
if (replace)
|
||||
replaceResults(response.data.parties.count, response.data.parties.results)
|
||||
else
|
||||
appendResults(response.data.parties.results)
|
||||
})
|
||||
.then(() => {
|
||||
setFound(true)
|
||||
setLoading(false)
|
||||
})
|
||||
.catch(error => handleError(error))
|
||||
}, [element, raid, recency])
|
||||
}, [currentPage, parties, element, raid, recency])
|
||||
|
||||
function replaceResults(count: number, list: Party[]) {
|
||||
if (count > 0) {
|
||||
setParties(list.sort((a, b) => (a.created_at > b.created_at) ? -1 : 1))
|
||||
} else {
|
||||
setParties([])
|
||||
}
|
||||
}
|
||||
|
||||
function appendResults(list: Party[]) {
|
||||
setParties([...parties, ...list])
|
||||
}
|
||||
|
||||
// Fetch all raids on mount, then find the raid in the URL if present
|
||||
useEffect(() => {
|
||||
|
|
@ -149,16 +172,19 @@ const ProfileRoute: React.FC = () => {
|
|||
// When the element, raid or recency filter changes,
|
||||
// fetch all teams again.
|
||||
useEffect(() => {
|
||||
if (!raidsLoading) fetchProfile()
|
||||
if (!raidsLoading) {
|
||||
setCurrentPage(1)
|
||||
fetchProfile({ replace: true })
|
||||
}
|
||||
}, [element, raid, recency])
|
||||
|
||||
// On first mount only, disable loading if we are fetching all teams
|
||||
useEffect(() => {
|
||||
if (raidSlug === 'all') {
|
||||
setRaidsLoading(false)
|
||||
fetchProfile()
|
||||
}
|
||||
}, [])
|
||||
// Current page changed
|
||||
if (currentPage > 1)
|
||||
fetchProfile({ replace: false })
|
||||
else if (currentPage == 1)
|
||||
fetchProfile({ replace: true })
|
||||
}, [currentPage])
|
||||
|
||||
// Receive filters from the filter bar
|
||||
function receiveFilters({ element, raidSlug, recency }: {element?: number, raidSlug?: string, recency?: number}) {
|
||||
|
|
@ -190,6 +216,22 @@ const ProfileRoute: React.FC = () => {
|
|||
|
||||
// TODO: Add save functions
|
||||
|
||||
function renderParties() {
|
||||
return parties.map((party, i) => {
|
||||
return <GridRep
|
||||
id={party.id}
|
||||
shortcode={party.shortcode}
|
||||
name={party.name}
|
||||
createdAt={new Date(party.created_at)}
|
||||
raid={party.raid}
|
||||
grid={party.weapons}
|
||||
favorited={party.favorited}
|
||||
key={`party-${i}`}
|
||||
onClick={goTo}
|
||||
/>
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div id="Profile">
|
||||
<Head>
|
||||
|
|
@ -224,23 +266,16 @@ const ProfileRoute: React.FC = () => {
|
|||
</FilterBar>
|
||||
|
||||
<section>
|
||||
<GridRepCollection loading={loading}>
|
||||
{
|
||||
parties.map((party, i) => {
|
||||
return <GridRep
|
||||
id={party.id}
|
||||
shortcode={party.shortcode}
|
||||
name={party.name}
|
||||
createdAt={new Date(party.created_at)}
|
||||
raid={party.raid}
|
||||
grid={party.weapons}
|
||||
favorited={party.favorited}
|
||||
key={`party-${i}`}
|
||||
onClick={goTo}
|
||||
/>
|
||||
})
|
||||
}
|
||||
</GridRepCollection>
|
||||
<InfiniteScroll
|
||||
dataLength={ (parties && parties.length > 0) ? parties.length : 0}
|
||||
next={ () => setCurrentPage(currentPage + 1) }
|
||||
hasMore={totalPages > currentPage}
|
||||
loader={ <div id="NotFound"><h2>Loading...</h2></div> }>
|
||||
<GridRepCollection loading={loading}>
|
||||
{ renderParties() }
|
||||
</GridRepCollection>
|
||||
</InfiniteScroll>
|
||||
|
||||
{ (parties.length == 0) ?
|
||||
<div id="NotFound">
|
||||
<h2>{ (loading) ? t('teams.loading') : t('teams.not_found') }</h2>
|
||||
|
|
|
|||
106
pages/saved.tsx
106
pages/saved.tsx
|
|
@ -5,6 +5,7 @@ import { useCookies } from 'react-cookie'
|
|||
import { queryTypes, useQueryState } from 'next-usequerystate'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import InfiniteScroll from 'react-infinite-scroll-component'
|
||||
|
||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
||||
import clonedeep from 'lodash.clonedeep'
|
||||
|
|
@ -20,9 +21,7 @@ const SavedRoute: React.FC = () => {
|
|||
// Set up cookies
|
||||
const [cookies] = useCookies(['account'])
|
||||
const headers = (cookies.account) ? {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${cookies.account.access_token}`
|
||||
}
|
||||
'Authorization': `Bearer ${cookies.account.access_token}`
|
||||
} : {}
|
||||
|
||||
// Set up router
|
||||
|
|
@ -41,6 +40,11 @@ const SavedRoute: React.FC = () => {
|
|||
const [raids, setRaids] = useState<Raid[]>()
|
||||
const [raid, setRaid] = useState<Raid>()
|
||||
|
||||
// Set up infinite scrolling-related states
|
||||
const [recordCount, setRecordCount] = useState(0)
|
||||
const [currentPage, setCurrentPage] = useState(1)
|
||||
const [totalPages, setTotalPages] = useState(1)
|
||||
|
||||
// Set up filter-specific query states
|
||||
// Recency is in seconds
|
||||
const [element, setElement] = useQueryState("element", {
|
||||
|
|
@ -87,26 +91,43 @@ const SavedRoute: React.FC = () => {
|
|||
}
|
||||
}, [])
|
||||
|
||||
const fetchTeams = useCallback(() => {
|
||||
const fetchTeams = useCallback(({ replace }: { replace: boolean }) => {
|
||||
const filters = {
|
||||
params: {
|
||||
element: (element != -1) ? element : undefined,
|
||||
raid: (raid) ? raid?.id : undefined,
|
||||
recency: (recency != -1) ? recency : undefined
|
||||
raid: (raid) ? raid.id : undefined,
|
||||
recency: (recency != -1) ? recency : undefined,
|
||||
page: currentPage
|
||||
}
|
||||
}
|
||||
|
||||
api.savedTeams({...filters, ...headers})
|
||||
api.savedTeams({...filters, ...{ headers: headers }})
|
||||
.then(response => {
|
||||
const parties: Party[] = response.data
|
||||
setParties(parties.map((p: any) => p.party)
|
||||
.sort((a, b) => (a.created_at > b.created_at) ? -1 : 1))
|
||||
setTotalPages(response.data.total_pages)
|
||||
setRecordCount(response.data.count)
|
||||
|
||||
if (replace)
|
||||
replaceResults(response.data.count, response.data.results)
|
||||
else
|
||||
appendResults(response.data.results)
|
||||
})
|
||||
.then(() => {
|
||||
setLoading(false)
|
||||
})
|
||||
.catch(error => handleError(error))
|
||||
}, [element, raid, recency])
|
||||
}, [currentPage, parties, element, raid, recency])
|
||||
|
||||
function replaceResults(count: number, list: Party[]) {
|
||||
if (count > 0) {
|
||||
setParties(list)
|
||||
} else {
|
||||
setParties([])
|
||||
}
|
||||
}
|
||||
|
||||
function appendResults(list: Party[]) {
|
||||
setParties([...parties, ...list])
|
||||
}
|
||||
|
||||
// Fetch all raids on mount, then find the raid in the URL if present
|
||||
useEffect(() => {
|
||||
|
|
@ -127,16 +148,19 @@ const SavedRoute: React.FC = () => {
|
|||
// When the element, raid or recency filter changes,
|
||||
// fetch all teams again.
|
||||
useEffect(() => {
|
||||
if (!raidsLoading) fetchTeams()
|
||||
if (!raidsLoading) {
|
||||
setCurrentPage(1)
|
||||
fetchTeams({ replace: true })
|
||||
}
|
||||
}, [element, raid, recency])
|
||||
|
||||
// On first mount only, disable loading if we are fetching all teams
|
||||
useEffect(() => {
|
||||
if (raidSlug === 'all') {
|
||||
setRaidsLoading(false)
|
||||
fetchTeams()
|
||||
}
|
||||
}, [])
|
||||
// Current page changed
|
||||
if (currentPage > 1)
|
||||
fetchTeams({ replace: false })
|
||||
else if (currentPage == 1)
|
||||
fetchTeams({ replace: true })
|
||||
}, [currentPage])
|
||||
|
||||
// Receive filters from the filter bar
|
||||
function receiveFilters({ element, raidSlug, recency }: {element?: number, raidSlug?: string, recency?: number}) {
|
||||
|
|
@ -208,6 +232,24 @@ const SavedRoute: React.FC = () => {
|
|||
router.push(`/p/${shortcode}`)
|
||||
}
|
||||
|
||||
function renderParties() {
|
||||
return parties.map((party, i) => {
|
||||
return <GridRep
|
||||
id={party.id}
|
||||
shortcode={party.shortcode}
|
||||
name={party.name}
|
||||
createdAt={new Date(party.created_at)}
|
||||
raid={party.raid}
|
||||
grid={party.weapons}
|
||||
user={party.user}
|
||||
favorited={party.favorited}
|
||||
key={`party-${i}`}
|
||||
displayUser={true}
|
||||
onClick={goTo}
|
||||
onSave={toggleFavorite} />
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div id="Teams">
|
||||
<Head>
|
||||
|
|
@ -232,25 +274,15 @@ const SavedRoute: React.FC = () => {
|
|||
</FilterBar>
|
||||
|
||||
<section>
|
||||
<GridRepCollection loading={loading}>
|
||||
{
|
||||
parties.map((party, i) => {
|
||||
return <GridRep
|
||||
id={party.id}
|
||||
shortcode={party.shortcode}
|
||||
name={party.name}
|
||||
createdAt={new Date(party.created_at)}
|
||||
raid={party.raid}
|
||||
grid={party.weapons}
|
||||
user={party.user}
|
||||
favorited={party.favorited}
|
||||
key={`party-${i}`}
|
||||
displayUser={true}
|
||||
onClick={goTo}
|
||||
onSave={toggleFavorite} />
|
||||
})
|
||||
}
|
||||
</GridRepCollection>
|
||||
<InfiniteScroll
|
||||
dataLength={ (parties && parties.length > 0) ? parties.length : 0}
|
||||
next={ () => setCurrentPage(currentPage + 1) }
|
||||
hasMore={totalPages > currentPage}
|
||||
loader={ <div id="NotFound"><h2>Loading...</h2></div> }>
|
||||
<GridRepCollection loading={loading}>
|
||||
{ renderParties() }
|
||||
</GridRepCollection>
|
||||
</InfiniteScroll>
|
||||
|
||||
{ (parties.length == 0) ?
|
||||
<div id="NotFound">
|
||||
|
|
|
|||
106
pages/teams.tsx
106
pages/teams.tsx
|
|
@ -2,9 +2,10 @@ import React, { useCallback, useEffect, useState } from 'react'
|
|||
import Head from 'next/head'
|
||||
|
||||
import { useCookies } from 'react-cookie'
|
||||
import { useQueryState, queryTypes } from 'next-usequerystate'
|
||||
import { queryTypes, useQueryState } from 'next-usequerystate'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import InfiniteScroll from 'react-infinite-scroll-component'
|
||||
|
||||
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
|
||||
import clonedeep from 'lodash.clonedeep'
|
||||
|
|
@ -20,9 +21,7 @@ const TeamsRoute: React.FC = () => {
|
|||
// Set up cookies
|
||||
const [cookies] = useCookies(['account'])
|
||||
const headers = (cookies.account) ? {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${cookies.account.access_token}`
|
||||
}
|
||||
'Authorization': `Bearer ${cookies.account.access_token}`
|
||||
} : {}
|
||||
|
||||
// Set up router
|
||||
|
|
@ -41,6 +40,11 @@ const TeamsRoute: React.FC = () => {
|
|||
const [raids, setRaids] = useState<Raid[]>()
|
||||
const [raid, setRaid] = useState<Raid>()
|
||||
|
||||
// Set up infinite scrolling-related states
|
||||
const [recordCount, setRecordCount] = useState(0)
|
||||
const [currentPage, setCurrentPage] = useState(1)
|
||||
const [totalPages, setTotalPages] = useState(1)
|
||||
|
||||
// Set up filter-specific query states
|
||||
// Recency is in seconds
|
||||
const [element, setElement] = useQueryState("element", {
|
||||
|
|
@ -87,26 +91,43 @@ const TeamsRoute: React.FC = () => {
|
|||
}
|
||||
}, [])
|
||||
|
||||
const fetchTeams = useCallback(() => {
|
||||
const fetchTeams = useCallback(({ replace }: { replace: boolean }) => {
|
||||
const filters = {
|
||||
params: {
|
||||
element: (element != -1) ? element : undefined,
|
||||
raid: (raid) ? raid.id : undefined,
|
||||
recency: (recency != -1) ? recency : undefined
|
||||
recency: (recency != -1) ? recency : undefined,
|
||||
page: currentPage
|
||||
}
|
||||
}
|
||||
|
||||
api.endpoints.parties.getAll({...filters, ...headers})
|
||||
api.endpoints.parties.getAll({...filters, ...{ headers: headers }})
|
||||
.then(response => {
|
||||
const parties: Party[] = response.data
|
||||
setParties(parties.map((p: any) => p.party)
|
||||
.sort((a, b) => (a.created_at > b.created_at) ? -1 : 1))
|
||||
setTotalPages(response.data.total_pages)
|
||||
setRecordCount(response.data.count)
|
||||
|
||||
if (replace)
|
||||
replaceResults(response.data.count, response.data.results)
|
||||
else
|
||||
appendResults(response.data.results)
|
||||
})
|
||||
.then(() => {
|
||||
setLoading(false)
|
||||
})
|
||||
.catch(error => handleError(error))
|
||||
}, [element, raid, recency])
|
||||
}, [currentPage, parties, element, raid, recency])
|
||||
|
||||
function replaceResults(count: number, list: Party[]) {
|
||||
if (count > 0) {
|
||||
setParties(list.sort((a, b) => (a.created_at > b.created_at) ? -1 : 1))
|
||||
} else {
|
||||
setParties([])
|
||||
}
|
||||
}
|
||||
|
||||
function appendResults(list: Party[]) {
|
||||
setParties([...parties, ...list])
|
||||
}
|
||||
|
||||
// Fetch all raids on mount, then find the raid in the URL if present
|
||||
useEffect(() => {
|
||||
|
|
@ -127,16 +148,19 @@ const TeamsRoute: React.FC = () => {
|
|||
// When the element, raid or recency filter changes,
|
||||
// fetch all teams again.
|
||||
useEffect(() => {
|
||||
if (!raidsLoading) fetchTeams()
|
||||
if (!raidsLoading) {
|
||||
setCurrentPage(1)
|
||||
fetchTeams({ replace: true })
|
||||
}
|
||||
}, [element, raid, recency])
|
||||
|
||||
// On first mount only, disable loading if we are fetching all teams
|
||||
useEffect(() => {
|
||||
if (raidSlug === 'all') {
|
||||
setRaidsLoading(false)
|
||||
fetchTeams()
|
||||
}
|
||||
}, [])
|
||||
// Current page changed
|
||||
if (currentPage > 1)
|
||||
fetchTeams({ replace: false })
|
||||
else if (currentPage == 1)
|
||||
fetchTeams({ replace: true })
|
||||
}, [currentPage])
|
||||
|
||||
// Receive filters from the filter bar
|
||||
function receiveFilters({ element, raidSlug, recency }: {element?: number, raidSlug?: string, recency?: number}) {
|
||||
|
|
@ -208,6 +232,24 @@ const TeamsRoute: React.FC = () => {
|
|||
router.push(`/p/${shortcode}`)
|
||||
}
|
||||
|
||||
function renderParties() {
|
||||
return parties.map((party, i) => {
|
||||
return <GridRep
|
||||
id={party.id}
|
||||
shortcode={party.shortcode}
|
||||
name={party.name}
|
||||
createdAt={new Date(party.created_at)}
|
||||
raid={party.raid}
|
||||
grid={party.weapons}
|
||||
user={party.user}
|
||||
favorited={party.favorited}
|
||||
key={`party-${i}`}
|
||||
displayUser={true}
|
||||
onClick={goTo}
|
||||
onSave={toggleFavorite} />
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div id="Teams">
|
||||
<Head>
|
||||
|
|
@ -234,25 +276,15 @@ const TeamsRoute: React.FC = () => {
|
|||
</FilterBar>
|
||||
|
||||
<section>
|
||||
<GridRepCollection loading={loading}>
|
||||
{
|
||||
parties.map((party, i) => {
|
||||
return <GridRep
|
||||
id={party.id}
|
||||
shortcode={party.shortcode}
|
||||
name={party.name}
|
||||
createdAt={new Date(party.created_at)}
|
||||
raid={party.raid}
|
||||
grid={party.weapons}
|
||||
user={party.user}
|
||||
favorited={party.favorited}
|
||||
key={`party-${i}`}
|
||||
displayUser={true}
|
||||
onClick={goTo}
|
||||
onSave={toggleFavorite} />
|
||||
})
|
||||
}
|
||||
</GridRepCollection>
|
||||
<InfiniteScroll
|
||||
dataLength={ (parties && parties.length > 0) ? parties.length : 0}
|
||||
next={ () => setCurrentPage(currentPage + 1) }
|
||||
hasMore={totalPages > currentPage}
|
||||
loader={ <div id="NotFound"><h2>Loading...</h2></div> }>
|
||||
<GridRepCollection loading={loading}>
|
||||
{ renderParties() }
|
||||
</GridRepCollection>
|
||||
</InfiniteScroll>
|
||||
|
||||
{ (parties.length == 0) ?
|
||||
<div id="NotFound">
|
||||
|
|
|
|||
Loading…
Reference in a new issue