sendou.ink/pages/xsearch/[[...slug]].tsx
2020-12-12 16:09:38 +02:00

191 lines
4.7 KiB
TypeScript

import { Radio, RadioGroup, Select, Stack } from "@chakra-ui/react";
import { t } from "@lingui/macro";
import { RankedMode } from "@prisma/client";
import Breadcrumbs from "components/common/Breadcrumbs";
import Top500Table from "components/top500/Top500Table";
import { getLocalizedMonthYearString } from "lib/strings";
import { GetStaticPaths, GetStaticProps } from "next";
import { useRouter } from "next/router";
import prisma from "prisma/client";
import {
getTop500PlacementsByMonth,
GetTop500PlacementsByMonthData,
} from "prisma/queries/getTop500PlacementsByMonth";
import { useEffect, useState } from "react";
interface Props {
placements: GetTop500PlacementsByMonthData;
monthOptions: { label: string; value: string }[];
}
const XSearchPage = ({ placements, monthOptions }: Props) => {
const [variables, setVariables] = useState<{
month: number;
year: number;
mode: RankedMode;
}>({
month: Number(monthOptions[0].value.split(",")[0]),
year: Number(monthOptions[0].value.split(",")[1]),
mode: "SZ" as RankedMode,
});
const router = useRouter();
useEffect(() => {
router.replace(
`/xsearch/${variables.year}/${variables.month}/${variables.mode}`
);
}, [variables]);
//TODO: layout can be persistent between route changes
return (
<>
<Breadcrumbs pages={[{ name: t`Top 500 Browser` }]} />
<Select
value={`${variables.month},${variables.year}`}
onChange={(e) => {
const [month, year] = e.target.value.split(",");
setVariables({
...variables,
month: Number(month),
year: Number(year),
});
}}
mt={8}
mb={4}
maxW={64}
>
{monthOptions.map((monthYear) => (
<option key={monthYear.value} value={monthYear.value}>
{monthYear.label}
</option>
))}
</Select>
<RadioGroup
value={variables.mode}
onChange={(value) =>
setVariables({ ...variables, mode: value as RankedMode })
}
mt={4}
mb={8}
>
<Stack direction="row">
<Radio value="SZ">{t`SZ`}</Radio>
<Radio value="TC">{t`TC`}</Radio>
<Radio value="RM">{t`RM`}</Radio>
<Radio value="CB">{t`CB`}</Radio>
</Stack>
</RadioGroup>
<Top500Table placements={placements} />
</>
);
};
export const getStaticPaths: GetStaticPaths = async () => {
const mostRecentResult = await prisma.xRankPlacement.findFirst({
orderBy: [{ year: "desc" }, { month: "desc" }],
});
if (!mostRecentResult) return { paths: [], fallback: false };
return {
paths: getMonthOptions(mostRecentResult.month, mostRecentResult.year)
.flatMap(({ month, year }) => [
{
params: {
slug: [year, month, "SZ"],
},
},
{
params: {
slug: [year, month, "TC"],
},
},
{
params: {
slug: [year, month, "RM"],
},
},
{
params: {
slug: [year, month, "CB"],
},
},
])
.concat({
params: {
slug: [],
},
}),
fallback: false,
};
};
export const getStaticProps: GetStaticProps<Props> = async ({ params }) => {
const mostRecentResult = await prisma.xRankPlacement.findFirst({
orderBy: [{ year: "desc" }, { month: "desc" }],
});
if (!mostRecentResult) throw Error("No X Rank Placements");
const slug = params!.slug
? (params!.slug as string[])
: [`${mostRecentResult.year}`, `${mostRecentResult.month}`, "SZ"];
if (slug.length !== 3) return { notFound: true };
const year = Number(slug[0]);
const month = Number(slug[1]);
if (isNaN(month) || isNaN(year)) return { notFound: true };
const placements = await getTop500PlacementsByMonth({
month,
year,
mode: slug[2] as RankedMode,
});
return {
props: {
placements,
monthOptions: getMonthOptions(
mostRecentResult.month,
mostRecentResult.year
),
},
notFound: !placements.length,
};
};
export function getMonthOptions(latestMonth: number, latestYear: number) {
const monthChoices = [];
let month = 5;
let year = 2018;
while (true) {
// TODO set language
const monthString = getLocalizedMonthYearString(month, year, "en");
monthChoices.push({
label: monthString,
value: `${month},${year}`,
month: `${month}`,
year: `${year}`,
});
if (month === latestMonth && year === latestYear) break;
month++;
if (month === 13) {
month = 1;
year++;
}
}
monthChoices.reverse();
return monthChoices;
}
export default XSearchPage;