sendou.ink/frontend-react/src/components/user/UserPage.tsx
2020-06-26 00:35:48 +03:00

223 lines
6.3 KiB
TypeScript

import { useQuery } from "@apollo/react-hooks"
import {
Badge,
Box,
Tab,
TabList,
TabPanel,
TabPanels,
Tabs,
} from "@chakra-ui/core"
import { Redirect, RouteComponentProps } from "@reach/router"
import React, { useContext } from "react"
import { Helmet } from "react-helmet-async"
import { FaTrophy, FaTshirt } from "react-icons/fa"
import { IconType } from "react-icons/lib/cjs"
import { PLAYER_INFO } from "../../graphql/queries/playerInfo"
import { SEARCH_FOR_BUILDS } from "../../graphql/queries/searchForBuilds"
import {
SearchForUserData,
SearchForUserVars,
SEARCH_FOR_USER,
} from "../../graphql/queries/searchForUser"
import { USER } from "../../graphql/queries/user"
import MyThemeContext from "../../themeContext"
import {
PlayerInfoData,
PlayerInfoVars,
SearchForBuildsData,
SearchForBuildsVars,
UserData,
} from "../../types"
import { weapons } from "../../utils/lists"
import Error from "../common/Error"
import Loading from "../common/Loading"
import Alert from "../elements/Alert"
import Markdown from "../elements/Markdown"
import AvatarWithInfo from "./AvatarWithInfo"
import BuildTab from "./BuildTab"
import XRankTab from "./XRankTab"
import { useTranslation, Trans } from "react-i18next"
interface Tab {
id: number
icon: IconType
title: JSX.Element
content: JSX.Element
}
interface UserPageProps {
id?: string
}
const UserPage: React.FC<RouteComponentProps & UserPageProps> = ({ id }) => {
const { t } = useTranslation()
const { data, error, loading } = useQuery<
SearchForUserData,
SearchForUserVars
>(SEARCH_FOR_USER, {
variables: isNaN(id as any) ? { custom_url: id } : { discord_id: id },
})
const { data: userData, error: userError, loading: userLoading } = useQuery<
UserData
>(USER)
const {
data: buildsData,
error: buildsError,
loading: buildsLoading,
} = useQuery<SearchForBuildsData, SearchForBuildsVars>(SEARCH_FOR_BUILDS, {
variables: { discord_id: data?.searchForUser?.discord_id as any },
skip: !data || !data.searchForUser,
})
const {
data: playerData,
error: playerError,
loading: playerLoading,
} = useQuery<PlayerInfoData, PlayerInfoVars>(PLAYER_INFO, {
variables: { twitter: data?.searchForUser?.twitter_name as any },
skip: !data || !data.searchForUser || !data.searchForUser.twitter_name,
})
const {
textColor,
themeColor,
themeColorWithShade,
grayWithShade,
} = useContext(MyThemeContext)
if (loading || userLoading || buildsLoading || playerLoading)
return <Loading />
if (error) return <Error errorMessage={error.message} />
if (userError) return <Error errorMessage={userError.message} />
if (buildsError) return <Error errorMessage={buildsError.message} />
if (playerError) return <Error errorMessage={playerError.message} />
if (!data || !data.searchForUser || !userData || !buildsData)
return <Redirect to="/404" />
const userLean = userData.user
const user = data.searchForUser
const builds = buildsData.searchForBuilds
const tabs: Tab[] = []
if (builds.length > 0 || userLean?.discord_id === user.discord_id) {
tabs.push({
id: 1,
icon: FaTshirt,
title: (
<>
{t("navigation;Builds")}{" "}
<Badge variantColor={themeColor} ml="0.5em">
{builds.length}
</Badge>
</>
),
content: (
<TabPanel key={1}>
<BuildTab
builds={builds.sort((a, b) => {
const weaponPool = user.weapons
if (weaponPool) {
if (
weaponPool.includes(a.weapon) &&
weaponPool.includes(b.weapon)
) {
return (
weaponPool.indexOf(a.weapon) - weaponPool.indexOf(b.weapon)
)
}
const poolComparision =
weaponPool.indexOf(b.weapon) - weaponPool.indexOf(a.weapon)
if (poolComparision !== 0) return poolComparision
}
return weapons.indexOf(a.weapon) - weapons.indexOf(b.weapon)
})}
canModifyBuilds={userLean?.discord_id === user.discord_id}
/>
</TabPanel>
),
})
}
if (playerData?.playerInfo?.placements) {
tabs.push({
id: 2,
icon: FaTrophy,
title: (
<>
{t("users;X Rank Top 500")}{" "}
<Badge variantColor={themeColor} ml="0.5em">
{playerData.playerInfo.placements.length}
</Badge>
</>
),
content: (
<TabPanel key={2}>
<XRankTab placements={playerData.playerInfo.placements} />
</TabPanel>
),
})
} else if (userLean?.discord_id === user.discord_id) {
tabs.push({
id: 2,
icon: FaTrophy,
title: <>{t("users;X Rank Top 500")}</>,
content: (
<TabPanel key={2}>
<Box color={grayWithShade}>
<Trans i18nKey="users;noPlacementsPrompt">
If you have reached Top 500 in a <b>finished</b> X Rank season you
can have it displayed here! Make sure your Twitter account is
verified on Discord to get it showing on your sendou.ink profile
and then contact Sendou#0043 on Discord with your in-game nick.
Once set up new results are added automatically and no further
action is needed unless you change your name on Twitter.
</Trans>
</Box>
</TabPanel>
),
})
}
return (
<>
<Helmet>
<title>
{user.username}#{user.discriminator} | sendou.ink
</title>
</Helmet>
<AvatarWithInfo
user={user}
canEdit={userLean?.discord_id === user.discord_id}
/>
{user.bio && (
<Box my="2em">
<Markdown value={user.bio} />
</Box>
)}
<Tabs isFitted variant="line" mt="2em" variantColor={themeColor}>
<TabList mb="1em">
{tabs.map((tabObj) => (
<Tab key={tabObj.id} color={textColor}>
<Box
as={tabObj.icon}
size="24px"
color={themeColorWithShade}
mr="7px"
/>{" "}
{tabObj.title}
</Tab>
))}
</TabList>
<TabPanels>{tabs.map((tabObj) => tabObj.content)}</TabPanels>
</Tabs>
</>
)
}
export default UserPage