salmon run player pages

This commit is contained in:
Kalle (Sendou) 2021-01-11 18:22:03 +02:00
parent 5e88655615
commit 23e4f7b720
6 changed files with 287 additions and 35 deletions

View File

@ -0,0 +1,29 @@
import { IconButton } from "@chakra-ui/react";
import { FiLink, FiTwitter, FiYoutube } from "react-icons/fi";
const LinkButton = ({ link }: { link: string }) => {
return (
<a key={link} href={link}>
<IconButton
aria-label={`Link to ${link}`}
icon={<LinkIcon link={link} />}
isRound
variant="ghost"
/>
</a>
);
};
function LinkIcon({ link }: { link: string }) {
if (link.includes("youtube") || link.includes("youtu.be")) {
return <FiYoutube />;
}
if (link.includes("twitter")) {
return <FiTwitter />;
}
return <FiLink />;
}
export default LinkButton;

View File

@ -5,6 +5,7 @@ const Section: React.FC<BoxProps> = (props) => {
const { secondaryBgColor } = useMyTheme();
return (
<Box
as="section"
bg={secondaryBgColor}
boxShadow="0px 0px 16px 6px rgba(0,0,0,0.1)"
p="1.5rem"

View File

@ -17,10 +17,10 @@ import { countries, getEmojiFlag } from "countries-list";
import { getFullUsername } from "lib/strings";
import { useMyTheme } from "lib/useMyTheme";
import useUser from "lib/useUser";
import Image from "next/image";
import { GetUserByIdentifierData } from "prisma/queries/getUserByIdentifier";
import { FaGamepad, FaTwitch, FaTwitter, FaYoutube } from "react-icons/fa";
import { FiInfo } from "react-icons/fi";
import { RiFileTextLine, RiTrophyLine } from "react-icons/ri";
interface AvatarWithInfoProps {
user: NonNullable<GetUserByIdentifierData>;
@ -199,12 +199,14 @@ const AvatarWithInfo: React.FC<AvatarWithInfoProps> = ({
href={`/player/${user.player?.switchAccountId}`}
prefetch={true}
>
<Button
leftIcon={<RiTrophyLine />}
variant="outline"
mx={2}
>
<Trans>View results</Trans>
<Button variant="outline" mx={2} size="lg" w={24}>
<Image
src="/layout/xsearch.png"
height={48}
width={48}
alt="SR"
priority
/>
</Button>
</MyLink>
)}
@ -213,12 +215,27 @@ const AvatarWithInfo: React.FC<AvatarWithInfoProps> = ({
href={`/freeagents?id=${user.freeAgentPost.id}`}
prefetch={true}
>
<Button
leftIcon={<RiFileTextLine />}
variant="outline"
mx={2}
>
<Trans>View free agent post</Trans>
<Button variant="outline" mx={2} size="lg" w={24}>
<Image
src="/layout/freeagents.png"
height={48}
width={48}
alt="SR"
priority
/>
</Button>
</MyLink>
)}
{true && (
<MyLink href={`/sr/player/${user.id}`} prefetch={true}>
<Button variant="outline" mx={2} size="lg" w={24}>
<Image
src="/layout/sr.png"
height={48}
width={48}
alt="SR"
priority
/>
</Button>
</MyLink>
)}

View File

@ -7,7 +7,6 @@ import {
Checkbox,
CheckboxGroup,
Flex,
IconButton,
Radio,
RadioGroup,
Select,
@ -17,6 +16,7 @@ import { Plural, t, Trans } from "@lingui/macro";
import { useLingui } from "@lingui/react";
import { SalmonRunRecordCategory } from "@prisma/client";
import Breadcrumbs from "components/common/Breadcrumbs";
import LinkButton from "components/common/LinkButton";
import {
Table,
TableBody,
@ -32,7 +32,6 @@ import { salmonRunStages } from "lib/lists/stages";
import { getRankingString } from "lib/strings";
import Image from "next/image";
import Link from "next/link";
import { FiLink, FiTwitter, FiYoutube } from "react-icons/fi";
import { salmonRunCategoryToNatural } from "./new";
const SalmonRunLeaderboardsPage = ({}) => {
@ -232,14 +231,7 @@ const SalmonRunLeaderboardsPage = ({}) => {
<TableCell textAlign="center">
{record.links.map((link) => (
<a key={link} href={link}>
<IconButton
aria-label={`Link to ${link}`}
icon={<LinkIcon link={link} />}
isRound
variant="ghost"
/>
</a>
<LinkButton key={link} link={link} />
))}
</TableCell>
</TableRow>
@ -255,16 +247,4 @@ const SalmonRunLeaderboardsPage = ({}) => {
);
};
function LinkIcon({ link }: { link: string }) {
if (link.includes("youtube") || link.includes("youtu.be")) {
return <FiYoutube />;
}
if (link.includes("twitter")) {
return <FiTwitter />;
}
return <FiLink />;
}
export default SalmonRunLeaderboardsPage;

182
pages/sr/player/[id].tsx Normal file
View File

@ -0,0 +1,182 @@
import { Box, Flex, Heading, Wrap, WrapItem } from "@chakra-ui/react";
import { t, Trans } from "@lingui/macro";
import Breadcrumbs from "components/common/Breadcrumbs";
import LinkButton from "components/common/LinkButton";
import MyContainer from "components/common/MyContainer";
import MyLink from "components/common/MyLink";
import Section from "components/common/Section";
import SubText from "components/common/SubText";
import UserAvatar from "components/common/UserAvatar";
import WeaponImage from "components/common/WeaponImage";
import { salmonRunStages } from "lib/lists/stages";
import { useMyTheme } from "lib/useMyTheme";
import { GetStaticPaths, GetStaticProps } from "next";
import Image from "next/image";
import { salmonRunCategoryToNatural } from "pages/sr/leaderboards/new";
import {
getUsersSalmonRunRecords,
GetUsersSalmonRunRecordsData,
} from "prisma/queries/getUsersSalmonRunRecords";
interface Props {
user: GetUsersSalmonRunRecordsData;
}
const SalmonRunPlayerPage = (props: Props) => {
const { gray } = useMyTheme();
const user = props.user!;
return (
<MyContainer>
<Breadcrumbs
pages={[
{ name: t`Salmon Run` },
{ name: `${user.username}#${user.discriminator}` },
]}
/>
<Flex align="center">
<UserAvatar user={user} size="xl" mr={4} />
<Box>
<Box
fontSize="2rem"
fontWeight="bold
"
>
{user.username}#{user.discriminator}
</Box>
<SubText ml="1px" mt="-6px">
<Trans>Salmon Run Records</Trans>
</SubText>
</Box>
</Flex>
<Box>
{Object.keys(salmonRunCategoryToNatural)
.filter((key) =>
user.salmonRunRecords.some((record) => record.category === key)
)
.map((category) => {
return (
<Box key={category} mt={4}>
<Heading as="h2" size="md" fontFamily="'Rubik', sans-serif">
{/* @ts-ignore */}
{salmonRunCategoryToNatural[category]}
</Heading>
<Wrap spacing={4} mt={4}>
{salmonRunStages
.filter((stage) =>
user.salmonRunRecords.some(
(record) =>
record.category === category &&
record.rotation.stage === stage
)
)
.map(
(stage) =>
user.salmonRunRecords.find(
(record) =>
record.category === category &&
record.rotation.stage === stage
)!
)
.map((record) => (
<WrapItem key={record.id}>
<Section>
<SubText mb={2} mt={2}>
{record.rotation.stage}
</SubText>
<Box color={gray} fontSize="sm" my={2}>
{new Date(
record.rotation.startTime
).toLocaleDateString()}{" "}
-{" "}
{new Date(
record.rotation.endTime
).toLocaleDateString()}
</Box>
<Flex align="center" my={2}>
<Box mr={1} fontSize="1.25rem" fontWeight="bold">
{record.goldenEggCount}
</Box>
<Image
src="/layout/sr.png"
height={30}
width={30}
alt="SR"
priority
/>
</Flex>
<Flex my={2}>
{record.rotation.weapons.map((wpn, i) => (
<Box key={i} mr={1}>
<WeaponImage size={32} name={wpn} />
</Box>
))}
</Flex>
{record.roster.length > 1 && (
<Flex my={2}>
{record.roster
.filter(
(rosterUser) =>
rosterUser.discordId !== user.discordId
)
.map((user) => (
<Box key={user.discordId} mr={1}>
<MyLink href={`/u/${user.discordId}`}>
<UserAvatar user={user} isSmall mr={1} />
</MyLink>
</Box>
))}
</Flex>
)}
<Flex mt={2}>
{record.links.map((link) => (
<LinkButton link={link} />
))}
</Flex>
</Section>
</WrapItem>
))}
</Wrap>
</Box>
);
})}
</Box>
</MyContainer>
);
};
export const getStaticPaths: GetStaticPaths = async () => {
return {
paths: [],
fallback: "blocking",
};
};
export const getStaticProps: GetStaticProps<Props> = async ({ params }) => {
const user = await getUsersSalmonRunRecords(parseInt(params!.id as string));
if (!user || !user.salmonRunRecords.length) return { notFound: true };
const categoryStages = new Set<string>();
user.salmonRunRecords = user.salmonRunRecords
.sort((a, b) => b.goldenEggCount - a.goldenEggCount)
.filter((record) => {
if (!record.approved) return false;
const id = record.category + record.rotation.stage;
if (categoryStages.has(id)) return false;
categoryStages.add(id);
return true;
});
return {
props: {
user: JSON.parse(JSON.stringify(user)),
},
revalidate: 1,
};
};
export default SalmonRunPlayerPage;

View File

@ -0,0 +1,43 @@
import { Prisma } from "@prisma/client";
import prisma from "prisma/client";
export type GetUsersSalmonRunRecordsData = Prisma.PromiseReturnType<
typeof getUsersSalmonRunRecords
>;
export const getUsersSalmonRunRecords = async (id: number) =>
prisma.user.findUnique({
where: { id },
select: {
discordId: true,
discordAvatar: true,
username: true,
discriminator: true,
salmonRunRecords: {
select: {
id: true,
category: true,
goldenEggCount: true,
links: true,
approved: true,
rotation: {
select: {
grizzcoWeapon: true,
stage: true,
startTime: true,
endTime: true,
weapons: true,
},
},
roster: {
select: {
discordId: true,
discordAvatar: true,
username: true,
discriminator: true,
},
},
},
},
},
});