From d3ff78a9d0c65b20788056a16e8be7f83b8f1e52 Mon Sep 17 00:00:00 2001 From: "Kalle (Sendou)" <38327916+Sendouc@users.noreply.github.com> Date: Fri, 6 Nov 2020 14:15:22 +0200 Subject: [PATCH] profile page fetch from db --- graphql/schema/user.ts | 2 +- ...tLocalizedMontYearString.ts => strings.ts} | 16 +++ pages/top500.tsx | 2 +- pages/u/[identifier].tsx | 103 ++++++++++++------ prisma/queries/getUserByIdentifier.ts | 37 +++++++ scenes/Profile/components/AvatarWithInfo.tsx | 18 ++- scenes/Profile/index.tsx | 17 --- 7 files changed, 138 insertions(+), 57 deletions(-) rename lib/{getLocalizedMontYearString.ts => strings.ts} (51%) create mode 100644 prisma/queries/getUserByIdentifier.ts diff --git a/graphql/schema/user.ts b/graphql/schema/user.ts index 077b40a43..052886e06 100644 --- a/graphql/schema/user.ts +++ b/graphql/schema/user.ts @@ -7,7 +7,7 @@ import { stringArg, } from "@nexus/schema"; import { getMySession } from "lib/getMySession"; -import { profileSchemaBackend } from "validators/profile"; +import { profileSchemaBackend } from "lib/validators/profile"; export const User = objectType({ name: "User", diff --git a/lib/getLocalizedMontYearString.ts b/lib/strings.ts similarity index 51% rename from lib/getLocalizedMontYearString.ts rename to lib/strings.ts index 022a4ab79..cd262144e 100644 --- a/lib/getLocalizedMontYearString.ts +++ b/lib/strings.ts @@ -12,3 +12,19 @@ export const getLocalizedMonthYearString = ( year: "numeric", }); }; + +export const getFullUsername = ({ + username, + discriminator, +}: { + username: string; + discriminator: string; +}) => `${username}#${discriminator}`; + +export const getDiscordAvatarUrl = ({ + discordId, + discordAvatar, +}: { + discordId: string; + discordAvatar: string; +}) => `https://cdn.discordapp.com/avatars/${discordId}/${discordAvatar}.jpg`; diff --git a/pages/top500.tsx b/pages/top500.tsx index 0183c36de..1ebf66829 100644 --- a/pages/top500.tsx +++ b/pages/top500.tsx @@ -10,7 +10,7 @@ import { useGetXRankPlacementsQuery, } from "generated/graphql"; import { initializeApollo } from "lib/apollo"; -import { getLocalizedMonthYearString } from "lib/getLocalizedMontYearString"; +import { getLocalizedMonthYearString } from "lib/strings"; import { GetStaticProps } from "next"; import { useState } from "react"; import XSearch from "scenes/Top500"; diff --git a/pages/u/[identifier].tsx b/pages/u/[identifier].tsx index 1a4c34280..bff0d0da3 100644 --- a/pages/u/[identifier].tsx +++ b/pages/u/[identifier].tsx @@ -1,59 +1,96 @@ +import { Box, Button, Divider } from "@chakra-ui/core"; +import { t, Trans } from "@lingui/macro"; import { PrismaClient } from "@prisma/client"; -import { - GetUserByIdentifierDocument, - useGetUserByIdentifierQuery, -} from "generated/graphql"; -import { initializeApollo } from "lib/apollo"; +import Breadcrumbs from "components/Breadcrumbs"; +import Markdown from "components/Markdown"; +import { getFullUsername } from "lib/strings"; +import useUser from "lib/useUser"; import { GetStaticPaths, GetStaticProps } from "next"; -import { useRouter } from "next/router"; -import Profile from "scenes/Profile"; +import { + getUserByIdentifier, + GetUserByIdentifierData, +} from "prisma/queries/getUserByIdentifier"; +import { useEffect, useState } from "react"; +import AvatarWithInfo from "scenes/Profile/components/AvatarWithInfo"; const prisma = new PrismaClient(); // FIXME: should try to make it so that /u/Sendou and /u/234234298348 point to the same page export const getStaticPaths: GetStaticPaths = async () => { - const users = await prisma.user.findMany({}); + const users = await prisma.user.findMany({ include: { profile: true } }); return { - paths: users.map((u) => ({ params: { identifier: u.discordId } })), + paths: users.flatMap((u) => + u.profile?.customUrlPath + ? [ + { params: { identifier: u.discordId } }, + { params: { identifier: u.profile.customUrlPath } }, + ] + : { params: { identifier: u.discordId } } + ), fallback: true, }; }; -export const getStaticProps: GetStaticProps = async ({ params }) => { - const apolloClient = initializeApollo(null, { prisma: new PrismaClient() }); +interface Props { + user: GetUserByIdentifierData; +} - await apolloClient.query({ - query: GetUserByIdentifierDocument, - variables: { - // FIXME: why ! needed? - identifier: params!.identifier, - }, - }); +export const getStaticProps: GetStaticProps = async ({ params }) => { + const user = await getUserByIdentifier(prisma, "tester"); + + //const isCustomUrl = isNaN(Number(params!.identifier)) return { props: { - initialApolloState: apolloClient.cache.extract(), - identifier: params!.identifier, + user, }, revalidate: 1, + notFound: !user, + //redirect: isCustomUrl ? { destination: "" } : undefined, }; }; -const ProfilePage = ({ identifier }: { identifier: string }) => { - const { data } = useGetUserByIdentifierQuery({ - variables: { identifier }, - }); - const router = useRouter(); +const ProfilePage = (props: Props) => { + const [user, setUser] = useState(props.user); + const [showModal, setShowModal] = useState(false); - // FIXME: handle fallback - const getUserByIdentifier = data?.getUserByIdentifier; - if (!getUserByIdentifier && typeof window !== "undefined") { - router.push("/404"); - } + useEffect(() => { + setUser(user); + }, [user]); - return getUserByIdentifier ? ( - - ) : null; + const [loggedInUser] = useUser(); + + // same as router.isFallback + if (!user) return null; + + return ( + <> + + + {loggedInUser?.id === user.id && ( + + )} + {/* {showModal && ( + setShowModal(false)} + existingProfile={user.profile} + /> + )} */} + + {user.profile?.bio && ( + + + + )} + + ); }; export default ProfilePage; diff --git a/prisma/queries/getUserByIdentifier.ts b/prisma/queries/getUserByIdentifier.ts new file mode 100644 index 000000000..59c04c861 --- /dev/null +++ b/prisma/queries/getUserByIdentifier.ts @@ -0,0 +1,37 @@ +import { PrismaClient } from "@prisma/client"; + +type Unwrap = T extends Promise + ? U + : T extends (...args: any) => Promise + ? U + : T extends (...args: any) => infer U + ? U + : T; + +export type GetUserByIdentifierData = Unwrap< + ReturnType +>; + +export const getUserByIdentifier = async ( + prisma: PrismaClient, + identifier: string +) => { + return prisma.user.findFirst({ + where: { + // this is ok because the values are mutually exclusive: customUrlPath can't contain only numbers etc. + OR: [ + { + discordId: identifier, + }, + { + profile: { + customUrlPath: identifier.toLowerCase(), + }, + }, + ], + }, + include: { + profile: true, + }, + }); +}; diff --git a/scenes/Profile/components/AvatarWithInfo.tsx b/scenes/Profile/components/AvatarWithInfo.tsx index c7db3b37e..92f5c36b2 100644 --- a/scenes/Profile/components/AvatarWithInfo.tsx +++ b/scenes/Profile/components/AvatarWithInfo.tsx @@ -1,13 +1,14 @@ import { Avatar, Box, Flex, Heading, IconButton } from "@chakra-ui/core"; import WeaponImage from "components/WeaponImage"; import { getEmojiFlag } from "countries-list"; -import { GetUserByIdentifierQuery } from "generated/graphql"; +import { getDiscordAvatarUrl, getFullUsername } from "lib/strings"; import { useTranslation } from "lib/useMockT"; import { useMyTheme } from "lib/useMyTheme"; +import { GetUserByIdentifierData } from "prisma/queries/getUserByIdentifier"; import { FaGamepad, FaTwitch, FaTwitter, FaYoutube } from "react-icons/fa"; interface AvatarWithInfoProps { - user: NonNullable; + user: NonNullable; } const AvatarWithInfo: React.FC = ({ user }) => { @@ -40,15 +41,22 @@ const AvatarWithInfo: React.FC = ({ user }) => { > - {user.fullUsername} + {getFullUsername(user)} {user.profile?.country && ( diff --git a/scenes/Profile/index.tsx b/scenes/Profile/index.tsx index b31724044..2df9d3b17 100644 --- a/scenes/Profile/index.tsx +++ b/scenes/Profile/index.tsx @@ -40,23 +40,6 @@ const Profile: React.FC = ({ user, identifier }) => { )} - {/*FIXME: - - - {tabs.map((tabObj) => ( - - {" "} - {tabObj.title} - - ))} - - {tabs.map((tabObj) => tabObj.content)} - */} ); };