mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-09-14 23:26:15 -05:00
kick team members
This commit is contained in:
@@ -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
32
pages/api/teams/[id].ts
Normal 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
41
pages/api/teams/kick.ts
Normal 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;
|
||||
@@ -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 };
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user