From d52a049d25ca387b7feb161237433834110abdab Mon Sep 17 00:00:00 2001 From: "Kalle (Sendou)" <38327916+Sendouc@users.noreply.github.com> Date: Thu, 14 Jan 2021 15:37:51 +0200 Subject: [PATCH] leave team --- components/t/CreateNewTeamModal.tsx | 2 - components/t/TeamManagementModal.tsx | 50 +++++++++++++++++ lib/validators/team.ts | 14 +++++ pages/api/teams/code.ts | 4 +- pages/api/teams/{index.tsx => index.ts} | 0 pages/api/teams/leave.ts | 35 ++++++++++++ pages/t/[team].tsx | 71 +++++++++++++++++++++++-- prisma/queries/getTeam.ts | 1 + 8 files changed, 170 insertions(+), 7 deletions(-) create mode 100644 components/t/TeamManagementModal.tsx create mode 100644 lib/validators/team.ts rename pages/api/teams/{index.tsx => index.ts} (100%) create mode 100644 pages/api/teams/leave.ts diff --git a/components/t/CreateNewTeamModal.tsx b/components/t/CreateNewTeamModal.tsx index dd55e9f9c..db388c6c7 100644 --- a/components/t/CreateNewTeamModal.tsx +++ b/components/t/CreateNewTeamModal.tsx @@ -43,8 +43,6 @@ const CreateNewTeamModal = () => { setIsOpen(false); }; - console.log(getError()); - return ( <> + {isOpen && ( + setIsOpen(false)} size="xl"> + + + + Managing team + + + + {/* + + Team name + + setName(e.target.value)} + /> + {getError()} + */} + + + + + )} + + ); +}; + +export default TeamManagementModal; diff --git a/lib/validators/team.ts b/lib/validators/team.ts new file mode 100644 index 000000000..60a4822da --- /dev/null +++ b/lib/validators/team.ts @@ -0,0 +1,14 @@ +import * as z from "zod"; + +const TEAM_BIO_CHARACTER_LIMIT = 7000; +const TEAM_RECRUITING_POST_CHARACTER_LIMIT = 2000; + +export const teamSchema = z.object({ + twitterName: z.string().max(15).optional().nullable(), + bio: z.string().max(TEAM_BIO_CHARACTER_LIMIT).optional().nullable(), + recruitingPost: z + .string() + .max(TEAM_RECRUITING_POST_CHARACTER_LIMIT) + .optional() + .nullable(), +}); diff --git a/pages/api/teams/code.ts b/pages/api/teams/code.ts index 2dc99a53f..c11963447 100644 --- a/pages/api/teams/code.ts +++ b/pages/api/teams/code.ts @@ -3,7 +3,7 @@ import { getMySession } from "lib/getMySession"; import { NextApiRequest, NextApiResponse } from "next"; import prisma from "prisma/client"; -const handler = async (req: NextApiRequest, res: NextApiResponse) => { +const joinHandler = async (req: NextApiRequest, res: NextApiResponse) => { switch (req.method) { case "POST": await postHandler(req, res); @@ -50,4 +50,4 @@ async function postHandler(req: NextApiRequest, res: NextApiResponse) { res.status(200).end(); } -export default handler; +export default joinHandler; diff --git a/pages/api/teams/index.tsx b/pages/api/teams/index.ts similarity index 100% rename from pages/api/teams/index.tsx rename to pages/api/teams/index.ts diff --git a/pages/api/teams/leave.ts b/pages/api/teams/leave.ts new file mode 100644 index 000000000..c7f2be335 --- /dev/null +++ b/pages/api/teams/leave.ts @@ -0,0 +1,35 @@ +import { getMySession } from "lib/getMySession"; +import { NextApiRequest, NextApiResponse } from "next"; +import prisma from "prisma/client"; + +const leaveHandler = async (req: NextApiRequest, res: NextApiResponse) => { + switch (req.method) { + case "POST": + await postHandler(req, res); + break; + default: + res.status(405).end(); + } +}; + +async function postHandler(req: NextApiRequest, res: NextApiResponse) { + const user = await getMySession(req); + if (!user) return res.status(401).end(); + + const userFromDb = await prisma.user.findUnique({ + where: { id: user.id }, + include: { team: true }, + }); + if (!userFromDb?.team || userFromDb.team.captainId === user.id) { + return res.status(400).end(); + } + + await prisma.user.update({ + where: { id: user.id }, + data: { team: { disconnect: true } }, + }); + + res.status(200).end(); +} + +export default leaveHandler; diff --git a/pages/t/[team].tsx b/pages/t/[team].tsx index 47d8d468e..2ccf99b64 100644 --- a/pages/t/[team].tsx +++ b/pages/t/[team].tsx @@ -1,15 +1,80 @@ -import { Box } from "@chakra-ui/react"; +import { Box, Button, Heading, useToast } from "@chakra-ui/react"; +import { t, Trans } from "@lingui/macro"; +import MyContainer from "components/common/MyContainer"; +import TeamManagementModal from "components/t/TeamManagementModal"; +import { getEmojiFlag } from "countries-list"; +import { getToastOptions } from "lib/getToastOptions"; +import { sendData } from "lib/postData"; +import useUser from "lib/useUser"; import { GetStaticPaths, GetStaticProps } from "next"; import { getTeam, GetTeamData } from "prisma/queries/getTeam"; +import { useState } from "react"; +import { FiTrash } from "react-icons/fi"; interface Props { team: GetTeamData; } const TeamPage: React.FC = (props) => { + const [sending, setSending] = useState(false); + const [user] = useUser(); + const toast = useToast(); + const team = props.team!; - console.log({ team }); - return {team.name}; + + const leaveTeam = async () => { + if (!window.confirm(t`Leave the team?`)) { + return; + } + + setSending(true); + + const success = await sendData("POST", "/api/teams/leave"); + setSending(false); + if (!success) return; + + //mutate("/api/freeagents"); + + toast(getToastOptions(t`Left the team`, "success")); + }; + + return ( + + + {team.name} + + + {team.roster + .reduce((acc: [string, number][], cur) => { + if (!cur.profile?.country) return acc; + + const countryTuple = acc.find( + ([country]) => country === cur.profile?.country + ); + if (!countryTuple) acc.push([cur.profile.country, 1]); + else countryTuple[1]++; + + return acc; + }, []) + .sort((a, b) => b[1] - a[1]) + .map(([country]) => getEmojiFlag(country))} + + {user?.id === team.captainId && } + {user && + user.id !== team.captainId && + team.roster.some((teamMember) => user.id === teamMember.id) && ( + + )} + + ); }; export const getStaticPaths: GetStaticPaths = async () => { diff --git a/prisma/queries/getTeam.ts b/prisma/queries/getTeam.ts index a83c0d79b..f32c2d0ad 100644 --- a/prisma/queries/getTeam.ts +++ b/prisma/queries/getTeam.ts @@ -14,6 +14,7 @@ export const getTeam = async (nameForUrl: string) => captainId: true, roster: { select: { + id: true, discordId: true, discordAvatar: true, username: true,