From 1365e4c95ce5861794be67a8f6423ba3600db1bb Mon Sep 17 00:00:00 2001 From: Justin Edmund Date: Mon, 7 Mar 2022 02:43:21 -0800 Subject: [PATCH] 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. --- components/FilterBar/index.tsx | 28 ++++---- components/RaidDropdown/index.tsx | 4 +- pages/teams.tsx | 103 +++++++++++++++++++++--------- types/TeamElement.d.ts | 7 ++ utils/Element.tsx | 59 +++++++++++++++++ 5 files changed, 156 insertions(+), 45 deletions(-) create mode 100644 types/TeamElement.d.ts create mode 100644 utils/Element.tsx diff --git a/components/FilterBar/index.tsx b/components/FilterBar/index.tsx index adadaf48..cf3f93ca 100644 --- a/components/FilterBar/index.tsx +++ b/components/FilterBar/index.tsx @@ -8,6 +8,7 @@ import RaidDropdown from '~components/RaidDropdown' import { appState } from '~utils/appState' import './index.scss' +import { raidGroups } from '~utils/raidGroups' interface Props { children: React.ReactNode @@ -15,7 +16,7 @@ interface Props { element?: number raidSlug?: string recency?: number - onFilter: (element?: number, raid?: string, recency?: number) => void + onFilter: ({element, raid, recency} : { element?: number, raid?: Raid, recency?: number}) => void } const FilterBar = (props: Props) => { @@ -36,25 +37,26 @@ const FilterBar = (props: Props) => { 'shadow': props.scrolled }) - function selectChanged(event: React.ChangeEvent) { + function elementSelectChanged() { const elementValue = (elementSelect.current) ? parseInt(elementSelect.current.value) : -1 + props.onFilter({ element: elementValue }) + } + + function recencySelectChanged() { const recencyValue = (recencySelect.current) ? parseInt(recencySelect.current.value) : -1 - let raidValue = '' + props.onFilter({ recency: recencyValue }) + } - if (app.raids) { - const raid = app.raids.find((raid: Raid) => raid.slug === raidSelect.current?.value) - raidValue = (raid) ? raid.id : '' - } - - props.onFilter(elementValue, raidValue, recencyValue) + function raidSelectChanged(raid?: Raid) { + props.onFilter({ raid: raid }) } return (
{props.children} - - + @@ -64,10 +66,10 @@ const FilterBar = (props: Props) => { - diff --git a/components/RaidDropdown/index.tsx b/components/RaidDropdown/index.tsx index 03872993..76b37b7c 100644 --- a/components/RaidDropdown/index.tsx +++ b/components/RaidDropdown/index.tsx @@ -11,7 +11,7 @@ import './index.scss' interface Props { showAllRaidsOption: boolean currentRaid?: string - onChange?: (event: React.ChangeEvent) => void + onChange?: (raid?: Raid) => void onBlur?: (event: React.ChangeEvent) => void } @@ -75,7 +75,7 @@ const RaidDropdown = React.forwardRef(function useFiel function handleChange(event: React.ChangeEvent) { if (raids) { const raid = raids.find(raid => raid.slug === event.target.value) - if (props.onChange) props.onChange(event) + if (props.onChange) props.onChange(raid) setCurrentRaid(raid) } } diff --git a/pages/teams.tsx b/pages/teams.tsx index 2a513939..c745ba50 100644 --- a/pages/teams.tsx +++ b/pages/teams.tsx @@ -3,39 +3,77 @@ 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 = () => { - const router = useRouter() - const { t } = useTranslation('common') - - // Cookies + // 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([]) + const [raid, setRaid] = useState() - // Filter states - const [element, setElement] = useState(null) - const [raidId, setRaidId] = useState(null) - const [recencyInSeconds, setRecencyInSeconds] = useState(null) + // 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); @@ -52,12 +90,14 @@ const TeamsRoute: React.FC = () => { const fetchTeams = useCallback(() => { const filters = { params: { - element: element, - raid: raidId, - recency: recencyInSeconds + 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}` @@ -77,27 +117,24 @@ const TeamsRoute: React.FC = () => { setLoading(false) }) .catch(error => handleError(error)) - }, [element, raidId, recencyInSeconds, cookies.account, handleError]) + }, [element, raid, recency, cookies.account, handleError]) useEffect(() => { - fetchTeams() + fetchTeams() }, [fetchTeams]) - function receiveFilters(element?: number, raid?: string, recency?: number) { - if (element != null && element >= 0) + function receiveFilters({ element, raid, recency }: {element?: number, raid?: Raid, recency?: number}) { + if (element == 0) + setElement(0) + else if (element) setElement(element) - else - setElement(null) + + if (raid) { + setRaid(raid) + setRaidSlug(raid.slug) + } - if (raid && raid != '0') - setRaidId(raid) - else - setRaidId(null) - - if (recency && recency > 0) - setRecencyInSeconds(recency) - else - setRecencyInSeconds(null) + if (recency) setRecency(recency) } function toggleFavorite(teamId: string, favorited: boolean) { @@ -167,8 +204,14 @@ const TeamsRoute: React.FC = () => { - -

{t('teams.title')}

+ + +

{t('teams.title')}

diff --git a/types/TeamElement.d.ts b/types/TeamElement.d.ts new file mode 100644 index 00000000..7ccd3f90 --- /dev/null +++ b/types/TeamElement.d.ts @@ -0,0 +1,7 @@ +interface TeamElement { + id: number, + name: { + en: string, + ja: string + } +} \ No newline at end of file diff --git a/utils/Element.tsx b/utils/Element.tsx new file mode 100644 index 00000000..28f23674 --- /dev/null +++ b/utils/Element.tsx @@ -0,0 +1,59 @@ +export const allElement: TeamElement = { + id: -1, + name: { + en: "All", + ja: "全s" + } +} + +export const elements: TeamElement[] = [ + { + id: 0, + name: { + en: "Null", + ja: "無" + } + }, + { + id: 1, + name: { + en: "Wind", + ja: "風" + } + }, + { + id: 2, + name: { + en: "Fire", + ja: "火" + } + }, + { + id: 3, + name: { + en: "Water", + ja: "水" + } + }, + { + id: 4, + name: { + en: "Earth", + ja: "土" + } + }, + { + id: 5, + name: { + en: "Dark", + ja: "闇" + } + }, + { + id: 6, + name: { + en: "Light", + ja: "光" + } + } +] \ No newline at end of file