kick team members

This commit is contained in:
Kalle (Sendou)
2021-01-14 20:09:03 +02:00
parent d52a049d25
commit e67ac39139
5 changed files with 176 additions and 21 deletions

View File

@@ -1,18 +1,54 @@
import {
Box,
Button,
Grid,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalHeader,
ModalOverlay,
useToast,
} from "@chakra-ui/react";
import { Trans } from "@lingui/macro";
import { t, Trans } from "@lingui/macro";
import UserAvatar from "components/common/UserAvatar";
import { getToastOptions } from "lib/getToastOptions";
import { sendData } from "lib/postData";
import { GetTeamData } from "prisma/queries/getTeam";
import { useState } from "react";
import { FiUsers } from "react-icons/fi";
import { FiTrash, FiUsers } from "react-icons/fi";
import { mutate } from "swr";
const TeamManagementModal = ({}) => {
interface Props {
roster: NonNullable<GetTeamData>["roster"];
teamId: number;
}
const TeamManagementModal: React.FC<Props> = ({ roster, teamId }) => {
const toast = useToast();
const [isOpen, setIsOpen] = useState(false);
const [sending, setSending] = useState(false);
const onDelete = async () => {
console.log("bye");
};
const kickTeamMember = async (id: number, name: string) => {
if (!window.confirm(`Kick ${name}?`)) return;
setSending(true);
const success = await sendData("POST", "/api/teams/kick", { id });
setSending(false);
if (!success) return;
mutate(`/api/teams/${teamId}`);
toast(getToastOptions(t`User kicked`, "success"));
setIsOpen(false);
};
return (
<>
<Button leftIcon={<FiUsers />} onClick={() => setIsOpen(true)}>
@@ -27,17 +63,53 @@ const TeamManagementModal = ({}) => {
</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> */}
<Button
leftIcon={<FiTrash />}
variant="outline"
colorScheme="red"
mb={6}
isDisabled={sending}
onClick={async () => {
if (window.confirm(t`Delete the team?`)) await onDelete();
}}
>
<Trans>Delete team</Trans>
</Button>
<Grid
templateColumns="repeat(4, 1fr)"
gridRowGap={4}
gridColumnGap={2}
placeItems="center"
>
{roster.map((user) => (
<>
<UserAvatar user={user} />
<Box>
{user.username}#{user.discriminator}
</Box>
<Button
colorScheme="red"
variant="outline"
isDisabled={sending}
onClick={() =>
kickTeamMember(
user.id,
`${user.username}#${user.discriminator}`
)
}
>
<Trans>Kick</Trans>
</Button>
<Button
colorScheme="red"
variant="outline"
isDisabled={sending}
>
<Trans>Make owner</Trans>
</Button>
</>
))}
</Grid>
</ModalBody>
</ModalContent>
</ModalOverlay>

32
pages/api/teams/[id].ts Normal file
View File

@@ -0,0 +1,32 @@
import { NextApiRequest, NextApiResponse } from "next";
import { getTeam, GetTeamData } from "prisma/queries/getTeam";
const teamByIdHandler = async (
req: NextApiRequest,
res: NextApiResponse<GetTeamData>
) => {
switch (req.method) {
case "GET":
await getHandler(req, res);
break;
default:
res.status(405).end();
}
};
async function getHandler(
req: NextApiRequest,
res: NextApiResponse<GetTeamData>
) {
if (typeof req.query.id !== "string") return res.status(400).end();
const id = parseInt(req.query.id);
if (Number.isNaN(id)) return res.status(400).end();
const team = await getTeam({ id });
if (!team) return res.status(400).end();
res.status(200).json(team);
}
export default teamByIdHandler;

41
pages/api/teams/kick.ts Normal file
View File

@@ -0,0 +1,41 @@
import { getMySession } from "lib/getMySession";
import { NextApiRequest, NextApiResponse } from "next";
import prisma from "prisma/client";
const kickHandler = 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();
if (typeof req.body.id !== "number") return res.status(400).end();
const userToKick = await prisma.user.findUnique({
where: { id: req.body.id },
include: { team: true },
});
if (
!userToKick ||
!userToKick.team ||
userToKick.team.captainId !== user.id
) {
return res.status(400).end();
}
await prisma.user.update({
where: { id: req.body.id },
data: { team: { disconnect: true } },
});
res.status(200).end();
}
export default kickHandler;

View File

@@ -10,18 +10,22 @@ import { GetStaticPaths, GetStaticProps } from "next";
import { getTeam, GetTeamData } from "prisma/queries/getTeam";
import { useState } from "react";
import { FiTrash } from "react-icons/fi";
import useSWR, { mutate } from "swr";
interface Props {
team: GetTeamData;
}
const TeamPage: React.FC<Props> = (props) => {
const { data } = useSWR<GetTeamData>(`/api/teams/${props.team!.id}`, {
initialData: props.team!,
});
const team = data!;
const [sending, setSending] = useState(false);
const [user] = useUser();
const toast = useToast();
const team = props.team!;
const leaveTeam = async () => {
if (!window.confirm(t`Leave the team?`)) {
return;
@@ -33,7 +37,7 @@ const TeamPage: React.FC<Props> = (props) => {
setSending(false);
if (!success) return;
//mutate("/api/freeagents");
mutate(`/api/teams/${props.team!.id}`);
toast(getToastOptions(t`Left the team`, "success"));
};
@@ -59,7 +63,12 @@ const TeamPage: React.FC<Props> = (props) => {
.sort((a, b) => b[1] - a[1])
.map(([country]) => getEmojiFlag(country))}
</Box>
{user?.id === team.captainId && <TeamManagementModal />}
{user?.id === team.captainId && (
<TeamManagementModal
roster={team.roster.filter((teamMember) => teamMember.id !== user.id)}
teamId={team.id}
/>
)}
{user &&
user.id !== team.captainId &&
team.roster.some((teamMember) => user.id === teamMember.id) && (
@@ -85,7 +94,7 @@ export const getStaticPaths: GetStaticPaths = async () => {
};
export const getStaticProps: GetStaticProps<Props> = async ({ params }) => {
const team = await getTeam(params!.team as string);
const team = await getTeam({ nameForUrl: params!.team as string });
if (!team) return { notFound: true };

View File

@@ -3,10 +3,11 @@ import prisma from "prisma/client";
export type GetTeamData = Prisma.PromiseReturnType<typeof getTeam>;
export const getTeam = async (nameForUrl: string) =>
export const getTeam = async (where: { nameForUrl: string } | { id: number }) =>
prisma.team.findUnique({
where: { nameForUrl },
where,
select: {
id: true,
bio: true,
recruitingPost: true,
twitterName: true,