From 9628130287b5a5cf7925c2867af1e75dd659bac4 Mon Sep 17 00:00:00 2001 From: minhd-vu Date: Wed, 28 Feb 2024 02:35:47 -0500 Subject: [PATCH] add mode selector --- app/api/party/route.ts | 50 ++++++++++++++++++++++++++ components/JoinParty.tsx | 6 ++-- components/NameForm.tsx | 6 ++-- components/Party.tsx | 7 +++- components/PartyCard.tsx | 12 +++---- components/Player.tsx | 20 +++++------ components/SelectMode.tsx | 76 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 154 insertions(+), 23 deletions(-) create mode 100644 components/SelectMode.tsx diff --git a/app/api/party/route.ts b/app/api/party/route.ts index 588836c..3b56b7f 100644 --- a/app/api/party/route.ts +++ b/app/api/party/route.ts @@ -77,3 +77,53 @@ export async function POST() { return Response.json(res); } + +type PartyPatchBody = { + mode?: Mode; +}; + +export async function PATCH(req: Request) { + const session = await getServerSession(); + if (!session?.user?.email) { + return Response.json("User is not authenticated", { status: 401 }); + } + + const user = await prisma.user.findUniqueOrThrow({ + where: { + email: session.user.email, + }, + include: { + party: true, + }, + }); + + if (!user.party) { + return Response.json("User is not in a party", { + status: 400, + }); + } + + if (user.party.adminId !== user.id) { + return Response.json("User must be the admin to adjust party settings", { + status: 403, + }); + } + + const body: PartyPatchBody = await req.json(); + if (!body.mode) { + return Response.json("Party mode is required", { + status: 400, + }); + } + + const party = await prisma.party.update({ + where: { + id: user.party.id, + }, + data: { + mode: body.mode, + }, + }); + + return Response.json(party); +} diff --git a/components/JoinParty.tsx b/components/JoinParty.tsx index 43cbc34..d00db32 100644 --- a/components/JoinParty.tsx +++ b/components/JoinParty.tsx @@ -50,11 +50,11 @@ export default function JoinParty() { width="24" height="24" viewBox="0 0 24 24" - stroke-width="1.5" + strokeWidth="1.5" stroke="currentColor" fill="none" - stroke-linecap="round" - stroke-linejoin="round" + strokeLinecap="round" + strokeLinejoin="round" > diff --git a/components/NameForm.tsx b/components/NameForm.tsx index cac5953..63e8ad2 100644 --- a/components/NameForm.tsx +++ b/components/NameForm.tsx @@ -51,11 +51,11 @@ export default function NameForm() { width="24" height="24" viewBox="0 0 24 24" - stroke-width="1.5" + strokeWidth="1.5" stroke="currentColor" fill="none" - stroke-linecap="round" - stroke-linejoin="round" + strokeLinecap="round" + strokeLinejoin="round" > diff --git a/components/Party.tsx b/components/Party.tsx index 8c0f622..120ed9d 100644 --- a/components/Party.tsx +++ b/components/Party.tsx @@ -19,6 +19,7 @@ import { StartGame, StopGame, } from "./Button"; +import SelectMode from "./SelectMode"; export default function Party() { const fetcher: Fetcher = (url) => @@ -119,7 +120,11 @@ export default function Party() { return ( {party.winner &&

{`Last Round's Winner: ${party.winner.name}`}

} -

Mode: {_.startCase(_.toLower(party.mode))}

+ {isAdmin ? ( + + ) : ( +

Mode: {_.startCase(_.toLower(party.mode))}

+ )} {!isAdmin && (

Waiting for party leader to start the party{" "} diff --git a/components/PartyCard.tsx b/components/PartyCard.tsx index 60e91ff..e4bc4c5 100644 --- a/components/PartyCard.tsx +++ b/components/PartyCard.tsx @@ -29,11 +29,11 @@ export default function PartyCard({ width="24" height="24" viewBox="0 0 24 24" - stroke-width="1.5" + strokeWidth="1.5" stroke="currentColor" fill="none" - stroke-linecap="round" - stroke-linejoin="round" + strokeLinecap="round" + strokeLinejoin="round" > @@ -47,11 +47,11 @@ export default function PartyCard({ width="24" height="24" viewBox="0 0 24 24" - stroke-width="1.5" + strokeWidth="1.5" stroke="currentColor" fill="none" - stroke-linecap="round" - stroke-linejoin="round" + strokeLinecap="round" + strokeLinejoin="round" > diff --git a/components/Player.tsx b/components/Player.tsx index 2117707..7769706 100644 --- a/components/Player.tsx +++ b/components/Player.tsx @@ -13,11 +13,11 @@ export function AdminIcon() { width="24" height="24" viewBox="0 0 24 24" - stroke-width="1.5" + strokeWidth="1.5" stroke="currentColor" fill="none" - stroke-linecap="round" - stroke-linejoin="round" + strokeLinecap="round" + strokeLinejoin="round" > @@ -35,16 +35,16 @@ export function AliveIcon() { width="24" height="24" viewBox="0 0 24 24" - stroke-width="1.5" + strokeWidth="1.5" stroke="currentColor" fill="none" - stroke-linecap="round" - stroke-linejoin="round" + strokeLinecap="round" + strokeLinejoin="round" > @@ -61,11 +61,11 @@ export function DeadIcon() { width="24" height="24" viewBox="0 0 24 24" - stroke-width="1.5" + strokeWidth="1.5" stroke="currentColor" fill="none" - stroke-linecap="round" - stroke-linejoin="round" + strokeLinecap="round" + strokeLinejoin="round" > diff --git a/components/SelectMode.tsx b/components/SelectMode.tsx new file mode 100644 index 0000000..11fe74a --- /dev/null +++ b/components/SelectMode.tsx @@ -0,0 +1,76 @@ +"use client"; + +import { Mode } from "@prisma/client"; +import { useContext, useState } from "react"; +import { ErrorContext } from "./App"; +import { useSWRConfig } from "swr"; + +export default function SelectMode({ mode }: { mode: Mode }) { + const modes = Object.values(Mode); + const { setError } = useContext(ErrorContext); + const { mutate } = useSWRConfig(); + const [isLoading, setLoading] = useState( + Object.fromEntries(Object.values(Mode).map((m) => [m, false])), + ); + + async function onClick(e: Mode) { + setLoading((prev) => ({ ...prev, [e]: true })); + + const res = await fetch("/api/party", { + method: "PATCH", + headers: { + "Content-type": "application/json", + }, + body: JSON.stringify({ mode: e }), + }); + + setLoading((prev) => ({ ...prev, [e]: false })); + + if (!res.ok) { + setError(await res.json()); + return; + } + + mutate("/api/user"); + } + + return ( +

+ Mode: +
+
+ {mode} + + + +
+
    + {modes.map((e) => ( +
  • + +
  • + ))} +
+
+
+ ); +}