From 34c93af273964fa12f4ddd6f8690950d6a026259 Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Mon, 21 Mar 2022 03:53:03 -0700 Subject: [PATCH] Add infinite scrolling to collections --- pages/[username].tsx | 101 +++++++++++++++++++++++++++-------------- pages/saved.tsx | 106 ++++++++++++++++++++++++++++--------------- pages/teams.tsx | 106 ++++++++++++++++++++++++++++--------------- 3 files changed, 206 insertions(+), 107 deletions(-) diff --git a/pages/[username].tsx b/pages/[username].tsx index f5ee56f1..9ee9d695 100644 --- a/pages/[username].tsx +++ b/pages/[username].tsx @@ -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() const [user, setUser] = useState(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 + }) + } + return (
@@ -224,23 +266,16 @@ const ProfileRoute: React.FC = () => {
- - { - parties.map((party, i) => { - return - }) - } - + 0) ? parties.length : 0} + next={ () => setCurrentPage(currentPage + 1) } + hasMore={totalPages > currentPage} + loader={

Loading...

}> + + { renderParties() } + +
+ { (parties.length == 0) ?

{ (loading) ? t('teams.loading') : t('teams.not_found') }

diff --git a/pages/saved.tsx b/pages/saved.tsx index 733aafc2..aaa982cf 100644 --- a/pages/saved.tsx +++ b/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() const [raid, setRaid] = useState() + // 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 + }) + } + return (
@@ -232,25 +274,15 @@ const SavedRoute: React.FC = () => {
- - { - parties.map((party, i) => { - return - }) - } - + 0) ? parties.length : 0} + next={ () => setCurrentPage(currentPage + 1) } + hasMore={totalPages > currentPage} + loader={

Loading...

}> + + { renderParties() } + +
{ (parties.length == 0) ?
diff --git a/pages/teams.tsx b/pages/teams.tsx index 8fbd8b01..a1d8bfb2 100644 --- a/pages/teams.tsx +++ b/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() const [raid, setRaid] = useState() + // 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 + }) + } + return (
@@ -234,25 +276,15 @@ const TeamsRoute: React.FC = () => {
- - { - parties.map((party, i) => { - return - }) - } - + 0) ? parties.length : 0} + next={ () => setCurrentPage(currentPage + 1) } + hasMore={totalPages > currentPage} + loader={

Loading...

}> + + { renderParties() } + +
{ (parties.length == 0) ?