leave team

This commit is contained in:
Kalle (Sendou)
2021-01-14 15:37:51 +02:00
parent 3f41e45132
commit d52a049d25
8 changed files with 170 additions and 7 deletions

View File

@@ -43,8 +43,6 @@ const CreateNewTeamModal = () => {
setIsOpen(false);
};
console.log(getError());
return (
<>
<Button onClick={() => setIsOpen(true)}>

View File

@@ -0,0 +1,50 @@
import {
Button,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalHeader,
ModalOverlay,
} from "@chakra-ui/react";
import { Trans } from "@lingui/macro";
import { useState } from "react";
import { FiUsers } from "react-icons/fi";
const TeamManagementModal = ({}) => {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<Button leftIcon={<FiUsers />} onClick={() => setIsOpen(true)}>
<Trans>Manage team</Trans>
</Button>
{isOpen && (
<Modal isOpen onClose={() => setIsOpen(false)} size="xl">
<ModalOverlay>
<ModalContent>
<ModalHeader>
<Trans>Managing team</Trans>
</ModalHeader>
<ModalCloseButton borderRadius="50%" />
<ModalBody pb={6}>
{/* <FormControl isInvalid={!!getError() && buttonClicked}>
<FormLabel htmlFor="teamName">
<Trans>Team name</Trans>
</FormLabel>
<Input
name="teamName"
value={name}
onChange={(e) => setName(e.target.value)}
/>
<FormErrorMessage>{getError()}</FormErrorMessage>
</FormControl> */}
</ModalBody>
</ModalContent>
</ModalOverlay>
</Modal>
)}
</>
);
};
export default TeamManagementModal;

14
lib/validators/team.ts Normal file
View File

@@ -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(),
});

View File

@@ -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;

35
pages/api/teams/leave.ts Normal file
View File

@@ -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;

View File

@@ -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> = (props) => {
const [sending, setSending] = useState(false);
const [user] = useUser();
const toast = useToast();
const team = props.team!;
console.log({ team });
return <Box>{team.name}</Box>;
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 (
<MyContainer>
<Heading fontFamily="'Rubik', sans-serif" textAlign="center">
{team.name}
</Heading>
<Box textAlign="center">
{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))}
</Box>
{user?.id === team.captainId && <TeamManagementModal />}
{user &&
user.id !== team.captainId &&
team.roster.some((teamMember) => user.id === teamMember.id) && (
<Button
leftIcon={<FiTrash />}
variant="outline"
colorScheme="red"
onClick={leaveTeam}
isLoading={sending}
>
<Trans>Leave team</Trans>
</Button>
)}
</MyContainer>
);
};
export const getStaticPaths: GetStaticPaths = async () => {

View File

@@ -14,6 +14,7 @@ export const getTeam = async (nameForUrl: string) =>
captainId: true,
roster: {
select: {
id: true,
discordId: true,
discordAvatar: true,
username: true,