hensei-web/pages/teams.tsx
Justin Edmund 1365e4c95c Get query states working on teams page
This changes the URL to show query params for our three filters, making it easy for people to link to very specific subsets of raids.
2022-03-07 02:43:21 -08:00

258 lines
No EOL
8.3 KiB
TypeScript

import React, { useCallback, useEffect, useState } from 'react'
import Head from 'next/head'
import { useRouter } from 'next/router'
import { useCookies } from 'react-cookie'
import { queryTypes, useQueryState } from 'next-usequerystate'
import { useTranslation } from 'next-i18next'
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
import clonedeep from 'lodash.clonedeep'
import api from '~utils/api'
import { elements, allElement } from '~utils/Element'
import GridRep from '~components/GridRep'
import GridRepCollection from '~components/GridRepCollection'
import FilterBar from '~components/FilterBar'
const TeamsRoute: React.FC = () => {
// Set up cookies
const [cookies] = useCookies(['account'])
const headers = (cookies.account != null) ? {
'Authorization': `Bearer ${cookies.account.access_token}`
} : {}
// const { raids } = useSnapshot(appState)
// Get the information we need from the router
const router = useRouter()
// Import translations
const { t } = useTranslation('common')
// Set up app-specific states
const [loading, setLoading] = useState(true)
const [scrolled, setScrolled] = useState(false)
// Set up page-specific states
const [parties, setParties] = useState<Party[]>([])
const [raid, setRaid] = useState<Raid>()
// Set up filter-specific query states
// Recency is in seconds
const [element, setElement] = useQueryState("element", {
defaultValue: -1,
parse: (query: string) => parseElement(query),
serialize: value => serializeElement(value)
})
const [raidSlug, setRaidSlug] = useQueryState("raid", { defaultValue: "all" })
const [recency, setRecency] = useQueryState("recency", queryTypes.integer.withDefault(-1))
// Define transformers for element and raid
function parseElement(query: string) {
let element: TeamElement | undefined =
(query === 'all') ?
allElement : elements.find(element => element.name.en.toLowerCase() === query)
return (element) ? element.id : -1
}
function serializeElement(value: number | undefined) {
let name = ''
if (value != undefined) {
if (value == -1) {
name = allElement.name.en.toLowerCase()
} else {
console.log(value)
name = elements[value].name.en.toLowerCase()
}
}
return name
}
// Add scroll event listener for shadow on FilterBar
useEffect(() => {
window.addEventListener("scroll", handleScroll)
return () => window.removeEventListener("scroll", handleScroll);
}, [])
const handleError = useCallback((error: any) => {
if (error.response != null) {
console.error(error)
} else {
console.error("There was an error.")
}
}, [])
const fetchTeams = useCallback(() => {
const filters = {
params: {
element: (element != -1) ? element : undefined,
raid: (raidSlug !== "all") ? raid?.id : undefined,
recency: (recency != -1) ? recency : undefined
}
}
console.log(filters)
const headers = (cookies.account) ? {
headers: {
'Authorization': `Bearer ${cookies.account.access_token}`
}
} : {}
const params = {...filters, ...headers}
setLoading(true)
api.endpoints.parties.getAll(params)
.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))
})
.then(() => {
setLoading(false)
})
.catch(error => handleError(error))
}, [element, raid, recency, cookies.account, handleError])
useEffect(() => {
fetchTeams()
}, [fetchTeams])
function receiveFilters({ element, raid, recency }: {element?: number, raid?: Raid, recency?: number}) {
if (element == 0)
setElement(0)
else if (element)
setElement(element)
if (raid) {
setRaid(raid)
setRaidSlug(raid.slug)
}
if (recency) setRecency(recency)
}
function toggleFavorite(teamId: string, favorited: boolean) {
if (favorited)
unsaveFavorite(teamId)
else
saveFavorite(teamId)
}
function saveFavorite(teamId: string) {
api.saveTeam({ id: teamId, params: headers })
.then((response) => {
if (response.status == 201) {
const index = parties.findIndex(p => p.id === teamId)
const party = parties[index]
party.favorited = true
let clonedParties = clonedeep(parties)
clonedParties[index] = party
setParties(clonedParties)
}
})
}
function unsaveFavorite(teamId: string) {
api.unsaveTeam({ id: teamId, params: headers })
.then((response) => {
if (response.status == 200) {
const index = parties.findIndex(p => p.id === teamId)
const party = parties[index]
party.favorited = false
let clonedParties = clonedeep(parties)
clonedParties[index] = party
setParties(clonedParties)
}
})
}
function handleScroll() {
if (window.pageYOffset > 90)
setScrolled(true)
else
setScrolled(false)
}
function goTo(shortcode: string) {
router.push(`/p/${shortcode}`)
}
return (
<div id="Teams">
<Head>
<title>{ t('teams.title') }</title>
<meta property="og:title" content="Discover Teams" />
<meta property="og:description" content="Find different Granblue Fantasy teams by raid, element or recency" />
<meta property="og:url" content="https://app.granblue.team/teams" />
<meta property="og:type" content="website" />
<meta name="twitter:card" content="summary_large_image" />
<meta property="twitter:domain" content="app.granblue.team" />
<meta name="twitter:title" content="Discover Teams" />
<meta name="twitter:description" content="Find different Granblue Fantasy teams by raid, element or recency" />
</Head>
<FilterBar
onFilter={receiveFilters}
scrolled={scrolled}
element={element}
raidSlug={raidSlug}
recency={recency}>
<h1>{t('teams.title')}</h1>
</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>
{ (parties.length == 0) ?
<div id="NotFound">
<h2>{ (loading) ? t('teams.loading') : t('teams.not_found') }</h2>
</div>
: '' }
</section>
</div>
)
}
export async function getStaticProps({ locale }: { locale: string }) {
return {
props: {
...(await serverSideTranslations(locale, ['common'])),
// Will be passed to the page component as props
},
}
}
export default TeamsRoute