From 7d528c6eb1f5fc19ab0b06b7dc60d1ed4c78488a Mon Sep 17 00:00:00 2001 From: ItaloMedici <59889993+ItaloMedici@users.noreply.github.com> Date: Sat, 27 Jul 2024 22:31:57 -0300 Subject: [PATCH 01/20] fix: adjust reveal event key --- context/board.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/context/board.tsx b/context/board.tsx index b1592d4..4c4cdf1 100644 --- a/context/board.tsx +++ b/context/board.tsx @@ -9,6 +9,7 @@ import { leaveBoardKey, playerChoiceKey, resetBoardKey, + revealCardsKey, } from "@/use-cases/event-keys/board"; import { useRouter } from "next/navigation"; import { @@ -167,7 +168,7 @@ export const BoardProvider = ({ ); }); - const revealCardsEventKey = playerChoiceKey(self.boardId); + const revealCardsEventKey = revealCardsKey(self.boardId); socket.on(revealCardsEventKey, (message) => { console.log(`[${revealCardsEventKey}] for ${self.name}:`, message); From e3b08b7cf1ecd78c60d11573c02bf5ee1729553f Mon Sep 17 00:00:00 2001 From: ItaloMedici <59889993+ItaloMedici@users.noreply.github.com> Date: Sat, 27 Jul 2024 22:32:12 -0300 Subject: [PATCH 02/20] chore: adjust db push script --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5bc0994..5bcaa03 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "start": "next start", "lint": "next lint", "postinstall": "npx prisma generate", - "db:push": "prisma db push --preview-feature" + "db:push": "npx prisma db push" }, "dependencies": { "@hookform/resolvers": "^3.3.4", From f1d8ade39aa2db9e1714cda92cfbc52b956b6993 Mon Sep 17 00:00:00 2001 From: ItaloMedici <59889993+ItaloMedici@users.noreply.github.com> Date: Sat, 17 Aug 2024 07:37:29 -0300 Subject: [PATCH 03/20] feat: migrate all pages routes for api folder --- app/api/[roomId]/board/leave/route.ts | 22 ++++++++ app/api/[roomId]/board/reset/route.ts | 31 +++++++++++ app/api/[roomId]/board/reveal/route.ts | 21 ++++++++ app/api/[roomId]/board/status/route.ts | 72 +++++++++++++++++++++++++ app/api/[roomId]/make-choice/route.ts | 25 +++++++++ app/api/[roomId]/player/notify/route.ts | 22 ++++++++ 6 files changed, 193 insertions(+) create mode 100644 app/api/[roomId]/board/leave/route.ts create mode 100644 app/api/[roomId]/board/reset/route.ts create mode 100644 app/api/[roomId]/board/reveal/route.ts create mode 100644 app/api/[roomId]/board/status/route.ts create mode 100644 app/api/[roomId]/make-choice/route.ts create mode 100644 app/api/[roomId]/player/notify/route.ts diff --git a/app/api/[roomId]/board/leave/route.ts b/app/api/[roomId]/board/leave/route.ts new file mode 100644 index 0000000..25d3cd0 --- /dev/null +++ b/app/api/[roomId]/board/leave/route.ts @@ -0,0 +1,22 @@ +import { leaveBoard } from "@/use-cases/board/leave-board"; + +export async function POST( + request: Request, + { params }: { params: { roomId: string } } +) { + try { + const { roomId } = params; + const { playerId } = await request.json(); + + if (!playerId || !roomId) { + return Response.json({ message: "Invalid input" }, { status: 400 }); + } + + await leaveBoard({ roomId, playerId }); + + return Response.json({ message: "Succefully leave board" }); + } catch (error: any) { + console.error(error); + return Response.json({ message: error?.message }, { status: 500 }); + } +} diff --git a/app/api/[roomId]/board/reset/route.ts b/app/api/[roomId]/board/reset/route.ts new file mode 100644 index 0000000..e193f09 --- /dev/null +++ b/app/api/[roomId]/board/reset/route.ts @@ -0,0 +1,31 @@ +import { resetBoard } from "@/use-cases/board/reset-board"; +import { getServerSession } from "next-auth"; + +export async function POST(request: Request) { + try { + const { boardId } = await request.json(); + + const session = await getServerSession(); + + if (!session?.user) { + return Response.json({ message: "Unauthorized" }, { status: 401 }); + } + + if (!boardId) { + return Response.json({ message: "Invalid input" }, { status: 400 }); + } + + const result = await resetBoard({ boardId }); + + if (!result.count) + return Response.json( + { message: "Error while reseting board" }, + { status: 404 } + ); + + return Response.json({ message: "Succefully reset the board" }); + } catch (error: any) { + console.error(error); + return Response.json({ message: error?.message }, { status: 500 }); + } +} diff --git a/app/api/[roomId]/board/reveal/route.ts b/app/api/[roomId]/board/reveal/route.ts new file mode 100644 index 0000000..78d0ab6 --- /dev/null +++ b/app/api/[roomId]/board/reveal/route.ts @@ -0,0 +1,21 @@ +import { toggleRevealBoard } from "@/use-cases/board/revel-board"; + +export async function POST( + _: Request, + { params }: { params: { roomId: string } } +) { + try { + const { roomId } = params; + + if (!roomId) { + return Response.json({ message: "Invalid input" }, { status: 400 }); + } + + await toggleRevealBoard({ roomId }); + + return Response.json({ message: "Board updated" }); + } catch (error: any) { + console.error(error); + return Response.json({ message: error?.message }, { status: 500 }); + } +} diff --git a/app/api/[roomId]/board/status/route.ts b/app/api/[roomId]/board/status/route.ts new file mode 100644 index 0000000..28d8275 --- /dev/null +++ b/app/api/[roomId]/board/status/route.ts @@ -0,0 +1,72 @@ +import { BoardStatus } from "@/types/board-status"; +import { createBoard } from "@/use-cases/board/create-board"; +import { getBoard } from "@/use-cases/board/get-board"; +import { getOthersPlayersOnBoard } from "@/use-cases/player/get-others-players-on-board"; +import { getUserPlayer } from "@/use-cases/player/get-user-player"; +import { joinBoardAndValidateLimit } from "@/use-cases/player/join-board-and-validate-limit"; +import { getUserRoom } from "@/use-cases/room"; +import { getServerSession } from "next-auth"; + +export async function GET( + _: Response, + { params }: { params: { roomId: string } } +) { + try { + const session = await getServerSession(); + + if (!session?.user) { + return Response.json({ message: "Unauthorized" }, { status: 401 }); + } + + const { roomId } = params; + + if (!roomId) { + return Response.json({ message: "Invalid input" }, { status: 400 }); + } + + const userRoom = await getUserRoom({ roomId, user: session.user }); + + if (!userRoom) { + return Response.json({ message: "User not in room" }, { status: 403 }); + } + + let board = await getBoard({ roomId }); + + if (!board) { + board = await createBoard({ roomId }); + } + + let player = await getUserPlayer({ boardId: board.id, user: session.user }); + + if (!player) { + player = await joinBoardAndValidateLimit({ + boardId: board.id, + user: session.user, + }); + } + + const others = await getOthersPlayersOnBoard({ + boardId: board.id, + userPlayerId: player.id, + }); + + const othersWithHiddenChoice = others.map((other) => ({ + ...other, + choice: !other.choice + ? other.choice + : Buffer.from(other.choice).toString("base64"), + })); + + const boardStatus: BoardStatus = { + boardId: board.id, + self: player, + others: othersWithHiddenChoice, + reveal: board.reveal, + }; + + return Response.json(boardStatus); + } catch (error: any) { + console.error(error); + return Response.json({ message: error?.message }, { status: 500 }); + } +} diff --git a/app/api/[roomId]/make-choice/route.ts b/app/api/[roomId]/make-choice/route.ts new file mode 100644 index 0000000..010239e --- /dev/null +++ b/app/api/[roomId]/make-choice/route.ts @@ -0,0 +1,25 @@ +import { makeChoice } from "@/use-cases/player/make-choice"; + +export async function POST(request: Request) { + try { + const { choice, playerId } = await request.json(); + + if (!choice) { + return Response.json({ message: "Choice is required" }, { status: 400 }); + } + + if (!playerId) { + return Response.json( + { message: "Player ID is required" }, + { status: 400 } + ); + } + + await makeChoice({ playerId, choice }); + + return Response.json({ message: "Choice made" }); + } catch (error: any) { + console.error(error); + return Response.json({ message: error?.message }, { status: 500 }); + } +} diff --git a/app/api/[roomId]/player/notify/route.ts b/app/api/[roomId]/player/notify/route.ts new file mode 100644 index 0000000..c4eb560 --- /dev/null +++ b/app/api/[roomId]/player/notify/route.ts @@ -0,0 +1,22 @@ +import { notifyPlayer } from "@/use-cases/player/notify"; + +export async function POST( + request: Request, + { params }: { params: { roomId: string } } +) { + try { + const { roomId } = params; + const { playerId, notification } = await request.json(); + + if (!playerId || !roomId) { + return Response.json({ message: "Invalid input" }, { status: 400 }); + } + + await notifyPlayer({ playerId, notification }); + + return Response.json({ message: "Succefully send notification to user" }); + } catch (error: any) { + console.error(error); + return Response.json({ message: error?.message }, { status: 500 }); + } +} From 0fbc20bafac4d1e8a3a16f0e3aa84e0ccc3c461f Mon Sep 17 00:00:00 2001 From: ItaloMedici <59889993+ItaloMedici@users.noreply.github.com> Date: Sat, 17 Aug 2024 07:39:29 -0300 Subject: [PATCH 04/20] break: remove socket --- package.json | 2 -- pages/api/join-board.ts | 58 ----------------------------------- pages/api/leave-board.ts | 43 -------------------------- pages/api/make-choice.ts | 47 ---------------------------- pages/api/reset-board.ts | 49 ----------------------------- pages/api/reveal-cards.ts | 37 ---------------------- pages/api/socket.ts | 26 ---------------- types/response-with-socket.ts | 11 ------- use-cases/event-keys/board.ts | 9 ------ 9 files changed, 282 deletions(-) delete mode 100644 pages/api/join-board.ts delete mode 100644 pages/api/leave-board.ts delete mode 100644 pages/api/make-choice.ts delete mode 100644 pages/api/reset-board.ts delete mode 100644 pages/api/reveal-cards.ts delete mode 100644 pages/api/socket.ts delete mode 100644 types/response-with-socket.ts delete mode 100644 use-cases/event-keys/board.ts diff --git a/package.json b/package.json index 5bcaa03..4c1f180 100644 --- a/package.json +++ b/package.json @@ -33,8 +33,6 @@ "react": "^18", "react-dom": "^18", "react-hook-form": "^7.50.1", - "socket.io": "^4.7.5", - "socket.io-client": "^4.7.5", "sonner": "^1.4.0", "tailwind-merge": "^2.2.1", "tailwindcss-animate": "^1.0.7", diff --git a/pages/api/join-board.ts b/pages/api/join-board.ts deleted file mode 100644 index d0c3070..0000000 --- a/pages/api/join-board.ts +++ /dev/null @@ -1,58 +0,0 @@ -"use server"; - -import { authOptions } from "@/authOptions"; -import { ResponseWithSocket } from "@/types/response-with-socket"; -import { joinBoardKey } from "@/use-cases/event-keys/board"; -import { getPlayersByBoardId } from "@/use-cases/player/get-players-by-board-id"; -import { joinOrCreateBoardAsPlayer } from "@/use-cases/player/join-or-create-board-as-player"; -import { NextApiRequest } from "next"; -import { getServerSession } from "next-auth"; - -const joinRoomHandler = async ( - req: NextApiRequest, - res: ResponseWithSocket -) => { - if (req.method !== "POST") { - return res.status(405).json({ message: "Method not allowed" }); - } - - try { - const { roomId } = req.body; - - const session = await getServerSession(req, res, authOptions); - - if (!session?.user) { - return res.status(401).json({ message: "Unauthorized" }); - } - - const player = await joinOrCreateBoardAsPlayer({ - roomId: roomId, - user: session.user, - }); - - if (!player) { - return res.status(500).json({ message: "Failed to join the room" }); - } - - const eventKey = joinBoardKey(player.boardId); - - const message = { roomId, player }; - - res?.socket?.server?.io?.emit(eventKey, message); - - const players = await getPlayersByBoardId({ - boardId: player.boardId, - }); - - const others = players?.filter((p) => p.id !== player.id); - - res.status(200).json({ player, others }); - } catch (error: any) { - console.error(`Error joining room: ${error?.message}`); - return res - .status(400) - .json({ message: `Error joining room: ${error?.message}` }); - } -}; - -export default joinRoomHandler; diff --git a/pages/api/leave-board.ts b/pages/api/leave-board.ts deleted file mode 100644 index ac9cbe6..0000000 --- a/pages/api/leave-board.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { authOptions } from "@/authOptions"; -import { ResponseWithSocket } from "@/types/response-with-socket"; -import { leaveBoard } from "@/use-cases/board/leave-board"; -import { leaveBoardKey } from "@/use-cases/event-keys/board"; -import { NextApiRequest } from "next"; -import { getServerSession } from "next-auth"; - -const leaveBoardHandler = async ( - req: NextApiRequest, - res: ResponseWithSocket -) => { - if (req.method !== "POST") { - return res.status(405).json({ message: "Method not allowed" }); - } - - try { - const { boardId, playerId, roomId } = req.body; - - const session = await getServerSession(req, res, authOptions); - - if (!session?.user) { - return res.status(401).json({ message: "Unauthorized" }); - } - - if (!boardId || !playerId || !roomId) { - return res.status(400).json({ message: "Invalid input" }); - } - - const player = await leaveBoard({ boardId, playerId, user: session?.user }); - - const eventKey = leaveBoardKey(roomId); - - const message = { roomId, player }; - - res?.socket?.server?.io?.emit(eventKey, message); - - res.status(200).json({ message: "Succefully leave board" }); - } catch (error: any) { - return res.redirect("/"); - } -}; - -export default leaveBoardHandler; diff --git a/pages/api/make-choice.ts b/pages/api/make-choice.ts deleted file mode 100644 index b724b01..0000000 --- a/pages/api/make-choice.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { ResponseWithSocket } from "@/types/response-with-socket"; -import { playerChoiceKey } from "@/use-cases/event-keys/board"; -import { makeChoice } from "@/use-cases/player/make-choice"; -import { NextApiRequest } from "next"; - -const makeChoiceHandler = async ( - req: NextApiRequest, - res: ResponseWithSocket -) => { - if (req.method !== "POST") { - res.status(405).json({ message: "Method Not Allowed" }); - return; - } - - const { choice, playerId } = req.body; - - if (!choice) { - res.status(400).json({ message: "Choice is required" }); - return; - } - - if (!playerId) { - res.status(400).json({ message: "Player ID is required" }); - return; - } - - try { - const updatedPlayer = await makeChoice({ playerId, choice }); - - const eventKey = playerChoiceKey(updatedPlayer.boardId); - - const message = { - player: { - ...updatedPlayer, - choice: "hidden", - }, - }; - - res.socket?.server?.io?.emit(eventKey, message); - - return res.status(200).json(updatedPlayer); - } catch (error: any) { - return res.status(500).json({ message: error.message ?? error }); - } -}; - -export default makeChoiceHandler; diff --git a/pages/api/reset-board.ts b/pages/api/reset-board.ts deleted file mode 100644 index 80492e7..0000000 --- a/pages/api/reset-board.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { authOptions } from "@/authOptions"; -import { ResponseWithSocket } from "@/types/response-with-socket"; -import { resetBoard } from "@/use-cases/board/reset-board"; -import { resetBoardKey } from "@/use-cases/event-keys/board"; -import { getPlayersByBoardId } from "@/use-cases/player/get-players-by-board-id"; -import { NextApiRequest } from "next"; -import { getServerSession } from "next-auth"; - -const resetBoardHandler = async ( - req: NextApiRequest, - res: ResponseWithSocket -) => { - if (req.method !== "POST") { - res.status(405).json({ message: "Method Not Allowed" }); - return; - } - - try { - const { boardId } = req.body; - - if (!boardId) { - res.status(400).json({ message: "Board ID is required" }); - return; - } - - const session = await getServerSession(req, res, authOptions); - - if (!session?.user) { - return res.status(401).json({ message: "Unauthorized" }); - } - - const result = await resetBoard({ boardId }); - - if (!result.count) - return res.status(404).json({ message: "Error while reseting board" }); - - const eventKey = resetBoardKey(boardId); - - const players = await getPlayersByBoardId({ boardId }); - - const message = { boardId, players }; - - res.socket?.server?.io?.emit(eventKey, message); - } catch (error: any) { - return res.status(500).json({ message: error.message }); - } -}; - -export default resetBoardHandler; diff --git a/pages/api/reveal-cards.ts b/pages/api/reveal-cards.ts deleted file mode 100644 index 4ef885c..0000000 --- a/pages/api/reveal-cards.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { ResponseWithSocket } from "@/types/response-with-socket"; -import { revealCardsKey } from "@/use-cases/event-keys/board"; -import { getPlayersByBoardId } from "@/use-cases/player/get-players-by-board-id"; -import { NextApiRequest } from "next"; - -const revealCardsHandler = async ( - req: NextApiRequest, - res: ResponseWithSocket -) => { - if (req.method !== "POST") { - res.status(405).json({ message: "Method Not Allowed" }); - return; - } - - try { - const { boardId, reveal } = req.body; - - if (!boardId) { - res.status(400).json({ message: "Board ID is required" }); - return; - } - - const players = await getPlayersByBoardId({ boardId }); - - const eventKey = revealCardsKey(boardId); - - const message = { reveal, players }; - - res.socket?.server?.io?.emit(eventKey, message); - - res.status(200).json({ message: "Reveal cards" }); - } catch (error: any) { - return res.status(500).json({ message: error.message }); - } -}; - -export default revealCardsHandler; diff --git a/pages/api/socket.ts b/pages/api/socket.ts deleted file mode 100644 index d682c3b..0000000 --- a/pages/api/socket.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { ResponseWithSocket } from "@/types/response-with-socket"; -import { Server as NetServer } from "http"; -import { NextApiRequest } from "next"; -import { Server as SocketServer } from "socket.io"; - -export const config = { - api: { - bodyParser: false, - }, -}; - -const ioHandler = (req: NextApiRequest, res: ResponseWithSocket) => { - if (!res.socket.server.io) { - const path = "/api/socket"; - const httpServer = res.socket.server as unknown as NetServer; - const io = new SocketServer(httpServer, { - path, - addTrailingSlash: false, - }); - res.socket.server.io = io; - } - - res.end(); -}; - -export default ioHandler; diff --git a/types/response-with-socket.ts b/types/response-with-socket.ts deleted file mode 100644 index 507f4b3..0000000 --- a/types/response-with-socket.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Server as NetServer, Socket } from "net"; -import { NextApiResponse } from "next"; -import { Server as SocketIOServer } from "socket.io"; - -export type ResponseWithSocket = NextApiResponse & { - socket: Socket & { - server: NetServer & { - io: SocketIOServer; - }; - }; -}; diff --git a/use-cases/event-keys/board.ts b/use-cases/event-keys/board.ts deleted file mode 100644 index 9fa843d..0000000 --- a/use-cases/event-keys/board.ts +++ /dev/null @@ -1,9 +0,0 @@ -const createBoardEventKey = (event: string) => { - return (boardId: string) => `board:${boardId}:${event}`; -}; - -export const joinBoardKey = createBoardEventKey("join"); -export const leaveBoardKey = createBoardEventKey("leave"); -export const playerChoiceKey = createBoardEventKey("choice"); -export const revealCardsKey = createBoardEventKey("reveal"); -export const resetBoardKey = createBoardEventKey("reset"); From 5d1e31ba3ff18c7f6efd0369189f9802239c973c Mon Sep 17 00:00:00 2001 From: ItaloMedici <59889993+ItaloMedici@users.noreply.github.com> Date: Sat, 17 Aug 2024 09:56:54 -0300 Subject: [PATCH 05/20] refactor: change socket calls to pooling --- context/board.tsx | 261 +++++++----------- context/socket-client.tsx | 55 ---- prisma/schema.prisma | 8 +- types/board-status.ts | 8 + use-cases/board/choice-options.ts | 4 +- use-cases/board/create-board.ts | 2 +- use-cases/board/leave-board.ts | 19 +- use-cases/board/revel-board.ts | 24 ++ .../player/get-others-players-on-board.ts | 20 ++ use-cases/player/get-user-player.ts | 21 ++ .../player/join-board-and-validate-limit.ts | 26 ++ .../player/join-or-create-board-as-player.ts | 48 ---- use-cases/player/notify.ts | 32 +++ use-cases/room/get-user-room.ts | 8 +- 14 files changed, 254 insertions(+), 282 deletions(-) delete mode 100644 context/socket-client.tsx create mode 100644 types/board-status.ts create mode 100644 use-cases/board/revel-board.ts create mode 100644 use-cases/player/get-others-players-on-board.ts create mode 100644 use-cases/player/get-user-player.ts create mode 100644 use-cases/player/join-board-and-validate-limit.ts delete mode 100644 use-cases/player/join-or-create-board-as-player.ts create mode 100644 use-cases/player/notify.ts diff --git a/context/board.tsx b/context/board.tsx index 4c4cdf1..dfb21e3 100644 --- a/context/board.tsx +++ b/context/board.tsx @@ -1,17 +1,13 @@ import { LoadingLogo } from "@/components/loading-logo/loading"; import { toast } from "@/components/toast"; -import { http } from "@/lib/api"; +import { fetcher, http } from "@/lib/api"; import { Player } from "@/lib/schemas/player"; +import { notificationMessages } from "@/messages/notification"; +import { randomLeaveMessage, randomWellcomeMessage } from "@/messages/wellcome"; +import { BoardStatus } from "@/types/board-status"; import { ChoiceOptions } from "@/types/choice-options"; +import { EnumNotification } from "@/types/notifications"; import { fibonacciChoiceOptions } from "@/use-cases/board/choice-options"; -import { - joinBoardKey, - leaveBoardKey, - playerChoiceKey, - resetBoardKey, - revealCardsKey, -} from "@/use-cases/event-keys/board"; -import { useRouter } from "next/navigation"; import { ReactNode, createContext, @@ -21,17 +17,22 @@ import { useRef, useState, } from "react"; -import { useSocketClient } from "./socket-client"; +import useSWR from "swr"; type BoardContextProps = { roomId: string; self: Player; others: Player[]; - revealCards: boolean; + reveal: boolean; choiceOptions: ChoiceOptions; + selfChoice?: string | null; handleChoice: (choice: string) => Promise; handleRevealCards: () => Promise; handleReset: () => Promise; + handleNotifyPlayer: ( + playerId: string, + notification?: EnumNotification + ) => Promise; }; export const BoardContext = createContext( @@ -42,8 +43,6 @@ export const useBoard = () => { return useContext(BoardContext); }; -const TIMEOUT = 60 * 1000; - export const BoardProvider = ({ roomId, children, @@ -51,68 +50,70 @@ export const BoardProvider = ({ roomId: string; children: ReactNode; }) => { - const router = useRouter(); - const { socket, isConnected } = useSocketClient(); - const [self, setSelf] = useState({} as Player); - const [others, setOthers] = useState([]); - const [revealCards, setRevealCards] = useState(false); + const { + data: boardStatus, + error, + isLoading, + } = useSWR(`/api/${roomId}/board/status`, fetcher, { + refreshInterval: 1000, + }); + + const othersPrev = useRef(boardStatus?.others); + const [selfChoice, setSelfChoice] = useState(boardStatus?.self?.choice); + const selfId = useRef(boardStatus?.self?.id); + + const [revealOptimistc, setRevealOptimistc] = useState( + boardStatus?.reveal || false + ); - const selfRef = useRef(self); + const isFirstRender = useRef(true); useEffect(() => { - if (!roomId || self?.id) return; + if (isFirstRender.current && boardStatus?.others?.length) { + isFirstRender.current = false; + othersPrev.current = boardStatus?.others; + return; + } - const joinBoard = async () => { - const result = await http.post<{ - player: Player; - others: Player[]; - }>("/join-board", { roomId }); + if (othersPrev.current?.length === boardStatus?.others?.length) return; - if (!result) return router.push("/"); + const newPlayers = boardStatus?.others?.filter( + (player) => !othersPrev.current?.find((prev) => prev.id === player.id) + ); - const { player, others } = result; + if (newPlayers?.length) { + newPlayers.forEach((player) => { + toast(`${player.name}, ${randomWellcomeMessage}`); + }); + } - setSelf(player); - selfRef.current = player; - setOthers(others); - }; + const leftPlayers = othersPrev.current?.filter( + (player) => !boardStatus?.others?.find((prev) => prev.id === player.id) + ); - joinBoard(); - }, []); + if (leftPlayers?.length) { + leftPlayers.forEach((player) => { + toast(`${player.name}, ${randomLeaveMessage}`); + }); + } - const leaveBoard = useCallback(async () => { - if (!selfRef.current?.boardId) return; + othersPrev.current = boardStatus?.others; + }, [boardStatus?.others]); - await http.post("/leave-board", { - playerId: selfRef.current.id, - boardId: selfRef.current.boardId, - roomId: roomId, - }); + useEffect(() => { + setSelfChoice(boardStatus?.self?.choice); + setRevealOptimistc(boardStatus?.reveal || false); - setSelf({} as Player); - setOthers([]); - selfRef.current = undefined; - }, [roomId]); + if (selfId.current === boardStatus?.self?.id) return; - useEffect(() => { - const timer = setTimeout(() => { - if (!isConnected || !self?.id) { - toast("Você foi desconectado da sala", { icon: "💩" }); - leaveBoard(); - router.push("/"); - } - }, TIMEOUT); - - if (isConnected && self?.id) { - return () => { - clearTimeout(timer); - }; - } + selfId.current = boardStatus?.self?.id; + }, [boardStatus?.self]); - return () => { - clearTimeout(timer); - }; - }, [isConnected, leaveBoard, router, self?.id]); + const leaveBoard = useCallback(async () => { + await http.post(`/${roomId}/board/leave`, { + playerId: selfId.current, + }); + }, [roomId]); useEffect(() => { return () => { @@ -120,122 +121,63 @@ export const BoardProvider = ({ }; }, []); - useEffect(() => { - if (!socket || !self) return; - - const joinBoardEventKey = joinBoardKey(self.boardId); - - socket.on(joinBoardEventKey, (message) => { - console.log(`[${joinBoardEventKey}] for ${self.name}:`, message); - - const newPlayer = message.player; - if (newPlayer.id === self?.id) return; - - const alreadyExist = others.find((p) => p.id === newPlayer.id); - - if (alreadyExist) return; - - toast(`${newPlayer.name} entrou na sala 🎉`); - - setOthers((prev) => [...prev, message.player]); - }); - - const leaveBoardEventKey = leaveBoardKey(roomId); + const handleNotification = async () => { + if (!boardStatus?.self.notified) return; - socket.on(leaveBoardEventKey, (message) => { - console.log(`[${leaveBoardEventKey}] for ${self.name}:`, message); - const player = message.player; + const audio = new Audio( + `/sounds/${boardStatus.self.notified.toLowerCase()}.mp3` + ); - toast(`${player.name} saiu da sala 🏃‍♂️💨`); + audio.play(); - setOthers((prev) => prev.filter((p) => p.id !== player.id)); + toast(notificationMessages[boardStatus.self.notified as EnumNotification], { + duration: 5000, }); - const choiceEventKey = playerChoiceKey(self.boardId); - - socket.on(choiceEventKey, (message) => { - console.log(`[${choiceEventKey}] for ${self.name}:`, message); - if (!message?.player) return; - - const updatedPlayer = message.player as Player; - - if (updatedPlayer.id === self.id) { - return; - } - - setOthers((prev) => - prev.map((p) => (p.email === updatedPlayer.email ? updatedPlayer : p)) - ); - }); - - const revealCardsEventKey = revealCardsKey(self.boardId); - - socket.on(revealCardsEventKey, (message) => { - console.log(`[${revealCardsEventKey}] for ${self.name}:`, message); - - if (!message?.players?.length) return; - - const players = message.players as Array; - - const _others = players.filter((_player) => _player.id !== self.id); - - setRevealCards(message.reveal); - setOthers(_others); - }); - - const resetBoardEventKey = resetBoardKey(self.boardId); - - socket.on(resetBoardEventKey, (message) => { - console.log(`[${resetBoardEventKey}] for ${self.name}:`, message); - if (!message?.players?.length) return; - - const players = message.players as Array; - - const _self = players.find((_player) => _player.id === self.id); - const _others = players.filter((_player) => _player.id !== self.id); - - if (!_self) return; + handleNotifyPlayer(boardStatus?.self.id); + }; - setOthers(_others); - setSelf(_self); + useEffect(() => { + if (!boardStatus?.self.notified) return; - setRevealCards(false); - }); + handleNotification(); + }, [boardStatus?.self?.notified]); - return () => { - socket.off(joinBoardEventKey); - socket.off(leaveBoardEventKey); - socket.off(choiceEventKey); - socket.off(revealCardsEventKey); - socket.off(resetBoardEventKey); - }; - }, [others, roomId, self, socket]); + if (error) { + toast.error(error); + } - if (!isConnected || !self?.id) { + if (!boardStatus?.self || isLoading) { return ; } const handleChoice = async (choice: string) => { - const updatedSelf = await http.post("/make-choice", { - playerId: self.id, + await http.post(`/${roomId}/make-choice`, { + playerId: boardStatus.self.id, choice, }); - if (!updatedSelf) return; - - setSelf(updatedSelf); + setSelfChoice(choice); }; const handleRevealCards = async () => { - await http.post("/reveal-cards", { - boardId: self.boardId, - reveal: !revealCards, - }); + await http.post(`/${roomId}/board/reveal`); + setRevealOptimistc((prev) => !prev); }; const handleReset = async () => { - await http.post("/reset-board", { - boardId: self.boardId, + await http.post(`/${roomId}/board/reset`, { + boardId: boardStatus.boardId, + }); + }; + + const handleNotifyPlayer = async ( + playerId: string, + notification?: EnumNotification + ) => { + await http.post(`/${roomId}/player/notify`, { + playerId, + notification, }); }; @@ -243,13 +185,14 @@ export const BoardProvider = ({ {children} diff --git a/context/socket-client.tsx b/context/socket-client.tsx deleted file mode 100644 index f300d9f..0000000 --- a/context/socket-client.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { env } from "@/env"; -import { - ReactNode, - createContext, - useContext, - useEffect, - useState, -} from "react"; -import { Socket, io } from "socket.io-client"; - -type SocketClientContextProps = { - isConnected: boolean; - socket: Socket | null; -}; - -const SocketClientContext = createContext({ - isConnected: false, - socket: null, -}); - -export const useSocketClient = () => { - return useContext(SocketClientContext); -}; - -export const SocketClientProvider = ({ children }: { children: ReactNode }) => { - const [socket, setSocket] = useState(null); - const [isConnected, setIsConnected] = useState(false); - - useEffect(() => { - const socketIo: Socket = new (io as any)(env.NEXT_PUBLIC_SITE_URL, { - path: "/api/socket", - addTraillingSlash: false, - }); - - socketIo.on("connect", () => { - setIsConnected(true); - }); - - socketIo.on("disconnect", () => { - setIsConnected(false); - }); - - setSocket(socketIo); - - return () => { - socketIo.disconnect(); - }; - }, []); - - return ( - - {children} - - ); -}; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 0d55e9d..2253b55 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -35,9 +35,10 @@ model UserRoom { } model Board { - id String @id @default(uuid()) - roomId String @unique - room Room @relation(fields: [roomId], references: [id], onDelete: Cascade) + id String @id @default(uuid()) + roomId String @unique + room Room @relation(fields: [roomId], references: [id], onDelete: Cascade) + reveal Boolean @default(false) Player Player[] } @@ -52,4 +53,5 @@ model Player { board Board @relation(fields: [boardId], references: [id], onDelete: Cascade) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt + notified String? } diff --git a/types/board-status.ts b/types/board-status.ts new file mode 100644 index 0000000..a8e1872 --- /dev/null +++ b/types/board-status.ts @@ -0,0 +1,8 @@ +import { Player } from "@/lib/schemas/player"; + +export type BoardStatus = { + boardId: string; + self: Player; + others: Array; + reveal: boolean; +}; diff --git a/use-cases/board/choice-options.ts b/use-cases/board/choice-options.ts index 678a657..a1151ee 100644 --- a/use-cases/board/choice-options.ts +++ b/use-cases/board/choice-options.ts @@ -9,6 +9,6 @@ export const fibonacciChoiceOptions: ChoiceOptions = [ { value: "13", label: "13" }, { value: "20", label: "20" }, { value: "40", label: "40" }, - { value: "coffe", label: "☕" }, - { value: "question", label: "?" }, + { value: "☕", label: "☕" }, + { value: "?", label: "?" }, ]; diff --git a/use-cases/board/create-board.ts b/use-cases/board/create-board.ts index 1351a50..803e185 100644 --- a/use-cases/board/create-board.ts +++ b/use-cases/board/create-board.ts @@ -11,7 +11,7 @@ export const createBoard = validator({ const board = await getBoard({ roomId }); if (board) { - throw new Error("Board already exists"); + return board; } const newBoard = await db.board.create({ diff --git a/use-cases/board/leave-board.ts b/use-cases/board/leave-board.ts index 9d5d82e..7c334b2 100644 --- a/use-cases/board/leave-board.ts +++ b/use-cases/board/leave-board.ts @@ -1,17 +1,22 @@ import { db } from "@/lib/db"; -import { userSchema } from "@/lib/schemas/user"; import { z } from "zod"; import { getPlayersByBoardId } from "../player/get-players-by-board-id"; import { validator } from "../validator"; import { deleteBoard } from "./delete-board"; +import { getBoard } from "./get-board"; export const leaveBoard = validator({ input: z.object({ - boardId: z.string().uuid(), + roomId: z.string().uuid(), playerId: z.string().uuid(), - user: userSchema, }), - handler: async ({ boardId, playerId, user }) => { + handler: async ({ roomId, playerId }) => { + const board = await getBoard({ roomId }); + + if (!board) { + throw new Error("Board not found"); + } + const player = await db.player.findFirst({ where: { id: playerId, @@ -25,14 +30,14 @@ export const leaveBoard = validator({ const result = await db.player.delete({ where: { id: player.id, - boardId: boardId, + boardId: board?.id, }, }); - const players = await getPlayersByBoardId({ boardId }); + const players = await getPlayersByBoardId({ boardId: board.id }); if (!players?.length) { - await deleteBoard({ boardId }); + await deleteBoard({ boardId: board.id }); } return result; diff --git a/use-cases/board/revel-board.ts b/use-cases/board/revel-board.ts new file mode 100644 index 0000000..fc11e74 --- /dev/null +++ b/use-cases/board/revel-board.ts @@ -0,0 +1,24 @@ +import { db } from "@/lib/db"; +import { z } from "zod"; +import { validator } from "../validator"; +import { getBoard } from "./get-board"; + +const input = z.object({ + roomId: z.string(), +}); + +export const toggleRevealBoard = validator({ + input, + handler: async ({ roomId }) => { + const board = await getBoard({ roomId }); + + return await db.board.update({ + where: { + id: board?.id, + }, + data: { + reveal: !board?.reveal, + }, + }); + }, +}); diff --git a/use-cases/player/get-others-players-on-board.ts b/use-cases/player/get-others-players-on-board.ts new file mode 100644 index 0000000..c0f309b --- /dev/null +++ b/use-cases/player/get-others-players-on-board.ts @@ -0,0 +1,20 @@ +import { db } from "@/lib/db"; +import { z } from "zod"; +import { validator } from "../validator"; + +export const getOthersPlayersOnBoard = validator({ + input: z.object({ + boardId: z.string().uuid(), + userPlayerId: z.string().uuid(), + }), + handler: async ({ boardId, userPlayerId }) => { + return await db.player.findMany({ + where: { + boardId: boardId, + NOT: { + id: userPlayerId, + }, + }, + }); + }, +}); diff --git a/use-cases/player/get-user-player.ts b/use-cases/player/get-user-player.ts new file mode 100644 index 0000000..c12b987 --- /dev/null +++ b/use-cases/player/get-user-player.ts @@ -0,0 +1,21 @@ +"use server"; + +import { db } from "@/lib/db"; +import { userSchema } from "@/lib/schemas/user"; +import { z } from "zod"; +import { validator } from "../validator"; + +export const getUserPlayer = validator({ + input: z.object({ + boardId: z.string().uuid(), + user: userSchema, + }), + handler: async ({ boardId, user }) => { + return await db.player.findFirst({ + where: { + boardId: boardId, + email: user.email, + }, + }); + }, +}); diff --git a/use-cases/player/join-board-and-validate-limit.ts b/use-cases/player/join-board-and-validate-limit.ts new file mode 100644 index 0000000..0fdea2b --- /dev/null +++ b/use-cases/player/join-board-and-validate-limit.ts @@ -0,0 +1,26 @@ +"use server"; + +import { db } from "@/lib/db"; +import { userSchema } from "@/lib/schemas/user"; +import { z } from "zod"; +import { validateBoardLimit } from "../board/validate-board-limit"; +import { validator } from "../validator"; + +export const joinBoardAndValidateLimit = validator({ + input: z.object({ + boardId: z.string().uuid(), + user: userSchema, + }), + handler: async ({ boardId, user }) => { + await validateBoardLimit({ boardId: boardId }); + + return await db.player.create({ + data: { + name: user.name, + imageUrl: user.image, + email: user.email, + boardId: boardId, + }, + }); + }, +}); diff --git a/use-cases/player/join-or-create-board-as-player.ts b/use-cases/player/join-or-create-board-as-player.ts deleted file mode 100644 index 4e62b89..0000000 --- a/use-cases/player/join-or-create-board-as-player.ts +++ /dev/null @@ -1,48 +0,0 @@ -"use server"; - -import { db } from "@/lib/db"; -import { userSchema } from "@/lib/schemas/user"; -import { z } from "zod"; -import { createBoard } from "../board/create-board"; -import { getBoard } from "../board/get-board"; -import { validateBoardLimit } from "../board/validate-board-limit"; -import { getUserRoom } from "../room"; -import { validator } from "../validator"; - -export const joinOrCreateBoardAsPlayer = validator({ - input: z.object({ - roomId: z.string().uuid(), - user: userSchema, - }), - handler: async ({ roomId, user }) => { - await getUserRoom({ roomId, user }); - - let board = await getBoard({ roomId }); - - if (!board) { - board = await createBoard({ roomId }); - } else { - await validateBoardLimit({ boardId: board.id }); - } - - const existingPlayer = await db.player.findFirst({ - where: { - boardId: board.id, - email: user.email, - }, - }); - - if (existingPlayer) { - return existingPlayer; - } - - return await db.player.create({ - data: { - name: user.name, - imageUrl: user.image, - email: user.email, - boardId: board.id, - }, - }); - }, -}); diff --git a/use-cases/player/notify.ts b/use-cases/player/notify.ts new file mode 100644 index 0000000..ee6d8f1 --- /dev/null +++ b/use-cases/player/notify.ts @@ -0,0 +1,32 @@ +"use server"; + +import { db } from "@/lib/db"; +import { z } from "zod"; +import { validator } from "../validator"; + +export const notifyPlayer = validator({ + input: z.object({ + playerId: z.string().uuid(), + notification: z.string().optional(), + }), + handler: async ({ playerId, notification }) => { + const player = await db.player.findFirst({ + where: { + id: playerId, + }, + }); + + const notified = player?.notified ? null : notification || null; + + console.log({ notified, notification }); + + return await db.player.update({ + where: { + id: playerId, + }, + data: { + notified, + }, + }); + }, +}); diff --git a/use-cases/room/get-user-room.ts b/use-cases/room/get-user-room.ts index a2ffef6..0ede070 100644 --- a/use-cases/room/get-user-room.ts +++ b/use-cases/room/get-user-room.ts @@ -11,17 +11,11 @@ export const getUserRoom = validator({ user: userSchema, }), handler: async ({ roomId, user }) => { - const userRoom = await db.userRoom.findFirst({ + return await db.userRoom.findFirst({ where: { userEmail: user.email, roomId, }, }); - - if (!userRoom) { - throw new Error("Room not found"); - } - - return userRoom; }, }); From 87a738ae389f811bc1628aa9ecc3dc609f1dda5e Mon Sep 17 00:00:00 2001 From: ItaloMedici <59889993+ItaloMedici@users.noreply.github.com> Date: Sat, 17 Aug 2024 09:57:03 -0300 Subject: [PATCH 06/20] build: add swr --- package-lock.json | 455 +++++++--------------------------------------- package.json | 1 + 2 files changed, 64 insertions(+), 392 deletions(-) diff --git a/package-lock.json b/package-lock.json index dcef1a2..2b33569 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,7 @@ "": { "name": "pontim", "version": "0.2.0", + "hasInstallScript": true, "dependencies": { "@hookform/resolvers": "^3.3.4", "@prisma/client": "^5.16.1", @@ -30,9 +31,8 @@ "react": "^18", "react-dom": "^18", "react-hook-form": "^7.50.1", - "socket.io": "^4.7.5", - "socket.io-client": "^4.7.5", "sonner": "^1.4.0", + "swr": "^2.2.5", "tailwind-merge": "^2.2.1", "tailwindcss-animate": "^1.0.7", "usehooks-ts": "^2.14.0", @@ -1668,11 +1668,6 @@ "integrity": "sha512-RbhOOTCNoCrbfkRyoXODZp75MlpiHMgbE5MEBZAnnnLyQNgrigEj4p0lzsMDyc1zVsJDLrivB58tgg3emX0eEA==", "dev": true }, - "node_modules/@socket.io/component-emitter": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", - "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==" - }, "node_modules/@swc/counter": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", @@ -1725,19 +1720,6 @@ "react": "^18.0.0" } }, - "node_modules/@types/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" - }, - "node_modules/@types/cors": { - "version": "2.8.17", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", - "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -1763,6 +1745,7 @@ "version": "20.11.16", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.16.tgz", "integrity": "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ==", + "dev": true, "dependencies": { "undici-types": "~5.26.4" } @@ -1941,18 +1924,6 @@ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", "dev": true }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/acorn": { "version": "8.11.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", @@ -2300,14 +2271,6 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, - "node_modules/base64id": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", - "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", - "engines": { - "node": "^4.5.0 || >= 5.9" - } - }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -2327,11 +2290,11 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -2557,18 +2520,6 @@ "node": ">= 0.6" } }, - "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -2618,6 +2569,7 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -2732,54 +2684,6 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, - "node_modules/engine.io": { - "version": "6.5.5", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz", - "integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==", - "dependencies": { - "@types/cookie": "^0.4.1", - "@types/cors": "^2.8.12", - "@types/node": ">=10.0.0", - "accepts": "~1.3.4", - "base64id": "2.0.0", - "cookie": "~0.4.1", - "cors": "~2.8.5", - "debug": "~4.3.1", - "engine.io-parser": "~5.2.1", - "ws": "~8.17.1" - }, - "engines": { - "node": ">=10.2.0" - } - }, - "node_modules/engine.io-client": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.4.tgz", - "integrity": "sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ==", - "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.1", - "engine.io-parser": "~5.2.1", - "ws": "~8.17.1", - "xmlhttprequest-ssl": "~2.0.0" - } - }, - "node_modules/engine.io-parser": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz", - "integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/engine.io/node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/enhanced-resolve": { "version": "5.15.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", @@ -3419,9 +3323,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -4466,25 +4370,6 @@ "node": ">=8.6" } }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -4517,7 +4402,8 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true }, "node_modules/mz": { "version": "2.7.0", @@ -4552,14 +4438,6 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/next": { "version": "14.2.4", "resolved": "https://registry.npmjs.org/next/-/next-14.2.4.tgz", @@ -5665,58 +5543,6 @@ "node": ">=8" } }, - "node_modules/socket.io": { - "version": "4.7.5", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", - "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==", - "dependencies": { - "accepts": "~1.3.4", - "base64id": "~2.0.0", - "cors": "~2.8.5", - "debug": "~4.3.2", - "engine.io": "~6.5.2", - "socket.io-adapter": "~2.5.2", - "socket.io-parser": "~4.2.4" - }, - "engines": { - "node": ">=10.2.0" - } - }, - "node_modules/socket.io-adapter": { - "version": "2.5.5", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", - "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", - "dependencies": { - "debug": "~4.3.4", - "ws": "~8.17.1" - } - }, - "node_modules/socket.io-client": { - "version": "4.7.5", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.5.tgz", - "integrity": "sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ==", - "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.2", - "engine.io-client": "~6.5.2", - "socket.io-parser": "~4.2.4" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/socket.io-parser": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", - "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", - "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, "node_modules/sonner": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/sonner/-/sonner-1.4.0.tgz", @@ -5977,6 +5803,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/swr": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/swr/-/swr-2.2.5.tgz", + "integrity": "sha512-QtxqyclFeAsxEUeZIYmsaQ0UjimSq1RZ9Un7I68/0ClKK/U3LoyQunwkQfJZr2fc22DfIXLNDc2wFyTEikCUpg==", + "dependencies": { + "client-only": "^0.0.1", + "use-sync-external-store": "^1.2.0" + }, + "peerDependencies": { + "react": "^16.11.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/tailwind-merge": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.2.1.tgz", @@ -6232,7 +6070,8 @@ "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true }, "node_modules/update-browserslist-db": { "version": "1.0.13", @@ -6314,6 +6153,14 @@ } } }, + "node_modules/use-sync-external-store": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", + "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/usehooks-ts": { "version": "2.14.0", "resolved": "https://registry.npmjs.org/usehooks-ts/-/usehooks-ts-2.14.0.tgz", @@ -6341,14 +6188,6 @@ "uuid": "dist/bin/uuid" } }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -6532,34 +6371,6 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, - "node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xmlhttprequest-ssl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", - "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -7449,11 +7260,6 @@ "integrity": "sha512-RbhOOTCNoCrbfkRyoXODZp75MlpiHMgbE5MEBZAnnnLyQNgrigEj4p0lzsMDyc1zVsJDLrivB58tgg3emX0eEA==", "dev": true }, - "@socket.io/component-emitter": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", - "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==" - }, "@swc/counter": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", @@ -7487,19 +7293,6 @@ "@tanstack/query-core": "5.48.0" } }, - "@types/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" - }, - "@types/cors": { - "version": "2.8.17", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", - "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", - "requires": { - "@types/node": "*" - } - }, "@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -7525,6 +7318,7 @@ "version": "20.11.16", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.16.tgz", "integrity": "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ==", + "dev": true, "requires": { "undici-types": "~5.26.4" } @@ -7651,15 +7445,6 @@ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", "dev": true }, - "accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "requires": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - } - }, "acorn": { "version": "8.11.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", @@ -7903,11 +7688,6 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, - "base64id": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", - "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" - }, "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -7924,11 +7704,11 @@ } }, "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "requires": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" } }, "browserslist": { @@ -8068,15 +7848,6 @@ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" }, - "cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "requires": { - "object-assign": "^4", - "vary": "^1" - } - }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -8113,6 +7884,7 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, "requires": { "ms": "2.1.2" } @@ -8201,47 +7973,6 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, - "engine.io": { - "version": "6.5.5", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz", - "integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==", - "requires": { - "@types/cookie": "^0.4.1", - "@types/cors": "^2.8.12", - "@types/node": ">=10.0.0", - "accepts": "~1.3.4", - "base64id": "2.0.0", - "cookie": "~0.4.1", - "cors": "~2.8.5", - "debug": "~4.3.1", - "engine.io-parser": "~5.2.1", - "ws": "~8.17.1" - }, - "dependencies": { - "cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" - } - } - }, - "engine.io-client": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.4.tgz", - "integrity": "sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ==", - "requires": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.1", - "engine.io-parser": "~5.2.1", - "ws": "~8.17.1", - "xmlhttprequest-ssl": "~2.0.0" - } - }, - "engine.io-parser": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz", - "integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==" - }, "enhanced-resolve": { "version": "5.15.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", @@ -8745,9 +8476,9 @@ } }, "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "requires": { "to-regex-range": "^5.0.1" } @@ -9479,19 +9210,6 @@ "picomatch": "^2.3.1" } }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "requires": { - "mime-db": "1.52.0" - } - }, "minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -9515,7 +9233,8 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true }, "mz": { "version": "2.7.0", @@ -9538,11 +9257,6 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, - "negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" - }, "next": { "version": "14.2.4", "resolved": "https://registry.npmjs.org/next/-/next-14.2.4.tgz", @@ -10241,49 +9955,6 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, - "socket.io": { - "version": "4.7.5", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", - "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==", - "requires": { - "accepts": "~1.3.4", - "base64id": "~2.0.0", - "cors": "~2.8.5", - "debug": "~4.3.2", - "engine.io": "~6.5.2", - "socket.io-adapter": "~2.5.2", - "socket.io-parser": "~4.2.4" - } - }, - "socket.io-adapter": { - "version": "2.5.5", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", - "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", - "requires": { - "debug": "~4.3.4", - "ws": "~8.17.1" - } - }, - "socket.io-client": { - "version": "4.7.5", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.5.tgz", - "integrity": "sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ==", - "requires": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.2", - "engine.io-client": "~6.5.2", - "socket.io-parser": "~4.2.4" - } - }, - "socket.io-parser": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", - "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", - "requires": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.1" - } - }, "sonner": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/sonner/-/sonner-1.4.0.tgz", @@ -10456,6 +10127,15 @@ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" }, + "swr": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/swr/-/swr-2.2.5.tgz", + "integrity": "sha512-QtxqyclFeAsxEUeZIYmsaQ0UjimSq1RZ9Un7I68/0ClKK/U3LoyQunwkQfJZr2fc22DfIXLNDc2wFyTEikCUpg==", + "requires": { + "client-only": "^0.0.1", + "use-sync-external-store": "^1.2.0" + } + }, "tailwind-merge": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.2.1.tgz", @@ -10647,7 +10327,8 @@ "undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true }, "update-browserslist-db": { "version": "1.0.13", @@ -10685,6 +10366,12 @@ "tslib": "^2.0.0" } }, + "use-sync-external-store": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", + "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", + "requires": {} + }, "usehooks-ts": { "version": "2.14.0", "resolved": "https://registry.npmjs.org/usehooks-ts/-/usehooks-ts-2.14.0.tgz", @@ -10703,11 +10390,6 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" - }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -10837,17 +10519,6 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, - "ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", - "requires": {} - }, - "xmlhttprequest-ssl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", - "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==" - }, "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", diff --git a/package.json b/package.json index 4c1f180..f8b60df 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "react-dom": "^18", "react-hook-form": "^7.50.1", "sonner": "^1.4.0", + "swr": "^2.2.5", "tailwind-merge": "^2.2.1", "tailwindcss-animate": "^1.0.7", "usehooks-ts": "^2.14.0", From 1126015cf41cb77d7cd342ace06a463f0aa7c6df Mon Sep 17 00:00:00 2001 From: ItaloMedici <59889993+ItaloMedici@users.noreply.github.com> Date: Sat, 17 Aug 2024 09:58:01 -0300 Subject: [PATCH 07/20] feat: create messages --- messages/error.ts | 10 ++++++++++ messages/notification.ts | 14 ++++++++++++++ messages/wellcome.ts | 28 ++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 messages/error.ts create mode 100644 messages/notification.ts create mode 100644 messages/wellcome.ts diff --git a/messages/error.ts b/messages/error.ts new file mode 100644 index 0000000..4091d4d --- /dev/null +++ b/messages/error.ts @@ -0,0 +1,10 @@ +const errorMessages = [ + "Ops, algo deu errado", + "Puts, de novo?", + "Vish, algo deu errado", + "Vacilamos nessa, tenta de novo", + "Deu ruim, algo deu errado", +]; + +export const randomErrorMessage = + errorMessages[Math.floor(Math.random() * errorMessages.length)]; diff --git a/messages/notification.ts b/messages/notification.ts new file mode 100644 index 0000000..95a2aa9 --- /dev/null +++ b/messages/notification.ts @@ -0,0 +1,14 @@ +import { EnumNotification } from "@/types/notifications"; + +export const notificationMessages: Record = { + [EnumNotification.KNOCK]: "óh de casa, hora de jogar! 🚪✊", + [EnumNotification.CAR_HORN]: + "Ei! Você esta causando engarrafamento aqui! 📣🚗", + [EnumNotification.POLICE]: "Escolha seu voto e siga seu caminho 🚨🚓", +}; + +export const notificationIcons: Record = { + [EnumNotification.KNOCK]: "🚪", + [EnumNotification.CAR_HORN]: "🚘", + [EnumNotification.POLICE]: "🚓", +}; diff --git a/messages/wellcome.ts b/messages/wellcome.ts new file mode 100644 index 0000000..90e8a2e --- /dev/null +++ b/messages/wellcome.ts @@ -0,0 +1,28 @@ +const wellcomeMessages = [ + "pulou sala 🪂", + "entrou na sala 🎉", + "chegou junto 🚀", + "veio pra jogar 🎲", + "está na área 🏟", + "chegou pra somar 🧮", + "colou com nóis 🤙", + "está no jogo 🃏", + "veio pra pontuar 🏆", +]; + +export const randomWellcomeMessage = + wellcomeMessages[Math.floor(Math.random() * wellcomeMessages.length)]; + +const leaveMessages = [ + "saiu da sala 🏃‍♂️💨", + "pulou fora 🪂", + "não aguentou a pressão 🥵", + "desistiu 🤦‍♂️", + "foi embora 😢", + "não quis jogar 😔", + "não quis saber de nada 🙄", + "não quis se arriscar 🤷‍♂️", +]; + +export const randomLeaveMessage = + leaveMessages[Math.floor(Math.random() * leaveMessages.length)]; From e00ad3bad8f438380c900deb0b44bd3460577a67 Mon Sep 17 00:00:00 2001 From: ItaloMedici <59889993+ItaloMedici@users.noreply.github.com> Date: Sat, 17 Aug 2024 09:58:31 -0300 Subject: [PATCH 08/20] refactor: create fetcher --- lib/api/index.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/api/index.tsx b/lib/api/index.tsx index 0d1c782..425574e 100644 --- a/lib/api/index.tsx +++ b/lib/api/index.tsx @@ -28,12 +28,12 @@ const get = (url: string) => }); }); -const post = (url: string, body: any) => +const post = (url: string, body?: any) => createHttpHandler(async () => { return await fetch(`/api/${url}`, { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify(body), + body: body ? JSON.stringify(body) : null, }); }); @@ -41,3 +41,6 @@ export const http = { get, post, }; + +export const fetcher = (input: RequestInfo | URL, init?: RequestInit) => + fetch(input, init).then((res) => res.json()); From b10fd6d3f5a61de2721978da8660f50cf4ec36df Mon Sep 17 00:00:00 2001 From: ItaloMedici <59889993+ItaloMedici@users.noreply.github.com> Date: Sat, 17 Aug 2024 10:00:04 -0300 Subject: [PATCH 09/20] refactor: extract errors messages --- components/toast/index.tsx | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/components/toast/index.tsx b/components/toast/index.tsx index 61b4fb1..b835e2a 100644 --- a/components/toast/index.tsx +++ b/components/toast/index.tsx @@ -1,3 +1,4 @@ +import { randomErrorMessage } from "@/messages/error"; import { ExternalToast, Toaster as ToasterSonner, @@ -21,18 +22,8 @@ const success = (message: string, options?: ToastOptions) => { }); }; -const randomErrorMessages = [ - "Ops, algo deu errado", - "Puts, de novo?", - "Vish, algo deu errado", - "Vacilamos nessa, tenta de novo", - "Deu ruim, algo deu errado", -]; - const error = (message?: string, options?: ToastOptions) => { - const errorMessage = - message ?? - randomErrorMessages[Math.floor(Math.random() * randomErrorMessages.length)]; + const errorMessage = message ?? randomErrorMessage; toastSonner.error(errorMessage, { ...options, From e8fe1cc455b7d9b022acedf6c2e3fb6f549b3803 Mon Sep 17 00:00:00 2001 From: ItaloMedici <59889993+ItaloMedici@users.noreply.github.com> Date: Sat, 17 Aug 2024 10:03:44 -0300 Subject: [PATCH 10/20] refactor: remove socket provider --- app/(dashboard)/room/[roomId]/_components/room.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/app/(dashboard)/room/[roomId]/_components/room.tsx b/app/(dashboard)/room/[roomId]/_components/room.tsx index ac5b11a..15b266f 100644 --- a/app/(dashboard)/room/[roomId]/_components/room.tsx +++ b/app/(dashboard)/room/[roomId]/_components/room.tsx @@ -1,7 +1,6 @@ "use client"; import { BoardProvider } from "@/context/board"; -import { SocketClientProvider } from "@/context/socket-client"; type RoomProps = { children: React.ReactNode; @@ -9,9 +8,5 @@ type RoomProps = { }; export const Room = ({ children, roomId }: RoomProps) => { - return ( - - {children} - - ); + return {children}; }; From 89f442b7b7c97f2c217cf70225daca5998fb69c7 Mon Sep 17 00:00:00 2001 From: ItaloMedici <59889993+ItaloMedici@users.noreply.github.com> Date: Sat, 17 Aug 2024 10:06:00 -0300 Subject: [PATCH 11/20] feat: create notifications type --- types/notifications.ts | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 types/notifications.ts diff --git a/types/notifications.ts b/types/notifications.ts new file mode 100644 index 0000000..3e6d2e7 --- /dev/null +++ b/types/notifications.ts @@ -0,0 +1,5 @@ +export enum EnumNotification { + KNOCK = "knock", + CAR_HORN = "car_horn", + POLICE = "police", +} From 9da40f618fde9ae1e9805cafc9b7a69933a2452a Mon Sep 17 00:00:00 2001 From: ItaloMedici <59889993+ItaloMedici@users.noreply.github.com> Date: Sat, 17 Aug 2024 10:16:41 -0300 Subject: [PATCH 12/20] refactor: adjust request type --- app/api/[roomId]/board/status/route.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/api/[roomId]/board/status/route.ts b/app/api/[roomId]/board/status/route.ts index 28d8275..523f17a 100644 --- a/app/api/[roomId]/board/status/route.ts +++ b/app/api/[roomId]/board/status/route.ts @@ -8,7 +8,7 @@ import { getUserRoom } from "@/use-cases/room"; import { getServerSession } from "next-auth"; export async function GET( - _: Response, + _: Request, { params }: { params: { roomId: string } } ) { try { From 548047b3d5a799ec63bab2fdea452e51fdad18ec Mon Sep 17 00:00:00 2001 From: ItaloMedici <59889993+ItaloMedici@users.noreply.github.com> Date: Sat, 17 Aug 2024 10:19:28 -0300 Subject: [PATCH 13/20] refactor: rename function --- app/(dashboard)/room/[roomId]/_components/player-card.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/(dashboard)/room/[roomId]/_components/player-card.tsx b/app/(dashboard)/room/[roomId]/_components/player-card.tsx index 0d70056..f6ec95e 100644 --- a/app/(dashboard)/room/[roomId]/_components/player-card.tsx +++ b/app/(dashboard)/room/[roomId]/_components/player-card.tsx @@ -7,7 +7,7 @@ type PlayerCardProps = { }; export const PlayerCard = ({ player }: PlayerCardProps) => { - const { revealCards, self } = useBoard(); + const { reveal, self, selfChoice } = useBoard(); const isSelf = player.id === self.id; From a3a82252bdbd5a93ddf76f2c3d20be740f977d63 Mon Sep 17 00:00:00 2001 From: ItaloMedici <59889993+ItaloMedici@users.noreply.github.com> Date: Sat, 17 Aug 2024 10:22:12 -0300 Subject: [PATCH 14/20] refactor: adjust numeric card --- .../room/[roomId]/_components/player-card.tsx | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/app/(dashboard)/room/[roomId]/_components/player-card.tsx b/app/(dashboard)/room/[roomId]/_components/player-card.tsx index f6ec95e..d87118a 100644 --- a/app/(dashboard)/room/[roomId]/_components/player-card.tsx +++ b/app/(dashboard)/room/[roomId]/_components/player-card.tsx @@ -11,6 +11,11 @@ export const PlayerCard = ({ player }: PlayerCardProps) => { const isSelf = player.id === self.id; + const formatedChoice = + reveal && player.choice + ? Buffer.from(player.choice, "base64").toString() + : ""; + return ( <> {isSelf ? ( @@ -21,13 +26,13 @@ export const PlayerCard = ({ player }: PlayerCardProps) => { label={"Você"} /> ) : ( - + )} ); From d9d863c5cd03774029247c54b08216a49718fdf1 Mon Sep 17 00:00:00 2001 From: ItaloMedici <59889993+ItaloMedici@users.noreply.github.com> Date: Sat, 17 Aug 2024 10:25:17 -0300 Subject: [PATCH 15/20] feat: create player notifications --- .../[roomId]/_components/board-toolbar.tsx | 74 ++++++++++++++++++ .../room/[roomId]/_components/board.tsx | 15 ++-- .../[roomId]/_components/cards-picker.tsx | 4 +- .../room/[roomId]/_components/deck.tsx | 25 ++++++ .../room/[roomId]/_components/player-card.tsx | 7 +- .../_components/player-notification-popup.tsx | 71 +++++++++++++++++ .../[roomId]/_components/players-cards.tsx | 45 ----------- components/ui/avatar.tsx | 2 +- components/user-button/index.tsx | 2 +- public/sounds/car_horn.mp3 | Bin 0 -> 51360 bytes public/sounds/knock.mp3 | Bin 0 -> 19245 bytes public/sounds/police.mp3 | Bin 0 -> 48191 bytes 12 files changed, 185 insertions(+), 60 deletions(-) create mode 100644 app/(dashboard)/room/[roomId]/_components/board-toolbar.tsx create mode 100644 app/(dashboard)/room/[roomId]/_components/deck.tsx create mode 100644 app/(dashboard)/room/[roomId]/_components/player-notification-popup.tsx delete mode 100644 app/(dashboard)/room/[roomId]/_components/players-cards.tsx create mode 100644 public/sounds/car_horn.mp3 create mode 100644 public/sounds/knock.mp3 create mode 100644 public/sounds/police.mp3 diff --git a/app/(dashboard)/room/[roomId]/_components/board-toolbar.tsx b/app/(dashboard)/room/[roomId]/_components/board-toolbar.tsx new file mode 100644 index 0000000..de002fe --- /dev/null +++ b/app/(dashboard)/room/[roomId]/_components/board-toolbar.tsx @@ -0,0 +1,74 @@ +import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; +import { Button } from "@/components/ui/button"; +import { useBoard } from "@/context/board"; +import { cn } from "@/lib/utils"; + +const MAX_AVATAR_DISPLAY = 5; + +export const BoardToolbar = () => { + const { others, self, handleRevealCards, reveal, handleReset } = useBoard(); + + if (!others.length) { + return null; + } + + const onRevealClick = () => { + if (reveal) { + handleReset(); + } + handleRevealCards(); + }; + + const playersAvatar = () => { + let avatarList = [self, ...others].map((player) => ({ + name: player.name + .split(" ") + .map((name) => name[0]) + .slice(0, 2) + .join(""), + imageUrl: player.imageUrl ?? undefined, + })); + + if (avatarList.length > MAX_AVATAR_DISPLAY) { + avatarList = avatarList.slice(0, MAX_AVATAR_DISPLAY); + avatarList.push({ + name: `+${others.length - MAX_AVATAR_DISPLAY}`, + imageUrl: undefined, + }); + } + + return ( +
+ {avatarList.map((player, index) => ( + 0, + })} + > + + + {player.name} + + + ))} +
+ ); + }; + + return ( +
+ + + + +
+ + {playersAvatar()} +
+ ); +}; diff --git a/app/(dashboard)/room/[roomId]/_components/board.tsx b/app/(dashboard)/room/[roomId]/_components/board.tsx index b3bed56..0df579f 100644 --- a/app/(dashboard)/room/[roomId]/_components/board.tsx +++ b/app/(dashboard)/room/[roomId]/_components/board.tsx @@ -1,20 +1,17 @@ "use client"; -import { useBoard } from "@/context/board"; import { BoardNavbar } from "./board-navbar"; +import { BoardToolbar } from "./board-toolbar"; import { CardsPicker } from "./cards-picker"; -import { PlayersCards } from "./players-cards"; +import { Deck } from "./deck"; export function Board() { - const { self, others } = useBoard(); - return ( -
+
-
- -
-
+
+ +
diff --git a/app/(dashboard)/room/[roomId]/_components/cards-picker.tsx b/app/(dashboard)/room/[roomId]/_components/cards-picker.tsx index 2fb1fbd..12ba1a7 100644 --- a/app/(dashboard)/room/[roomId]/_components/cards-picker.tsx +++ b/app/(dashboard)/room/[roomId]/_components/cards-picker.tsx @@ -3,9 +3,9 @@ import { useBoard } from "@/context/board"; import { cn } from "@/lib/utils"; export const CardsPicker = () => { - const { choiceOptions, handleChoice, self } = useBoard(); + const { choiceOptions, handleChoice, selfChoice } = useBoard(); - const isSelfOption = (option: string) => self.choice === option; + const isSelfOption = (option: string) => selfChoice == option; return (
diff --git a/app/(dashboard)/room/[roomId]/_components/deck.tsx b/app/(dashboard)/room/[roomId]/_components/deck.tsx new file mode 100644 index 0000000..dc4c73e --- /dev/null +++ b/app/(dashboard)/room/[roomId]/_components/deck.tsx @@ -0,0 +1,25 @@ +import { useBoard } from "@/context/board"; +import { PlayerCard } from "./player-card"; + +export const Deck = () => { + const { others, self } = useBoard(); + + const players = [self, ...others]; + + if (!others.length) { + return ( +
+

Sozinho por aqui... 😴

+ {/* adicionar botão de convidar */} +
+ ); + } + + return ( +
+ {players.map((player) => ( + + ))} +
+ ); +}; diff --git a/app/(dashboard)/room/[roomId]/_components/player-card.tsx b/app/(dashboard)/room/[roomId]/_components/player-card.tsx index d87118a..14385ce 100644 --- a/app/(dashboard)/room/[roomId]/_components/player-card.tsx +++ b/app/(dashboard)/room/[roomId]/_components/player-card.tsx @@ -1,6 +1,7 @@ import { NumericCard } from "@/components/card/numeric-card"; import { useBoard } from "@/context/board"; import { Player } from "@/lib/schemas/player"; +import { PlayerNotificationPopup } from "./player-notification-popup"; type PlayerCardProps = { player: Player; @@ -20,12 +21,13 @@ export const PlayerCard = ({ player }: PlayerCardProps) => { <> {isSelf ? ( ) : ( + { size={"large"} label={player.name} /> + )} ); diff --git a/app/(dashboard)/room/[roomId]/_components/player-notification-popup.tsx b/app/(dashboard)/room/[roomId]/_components/player-notification-popup.tsx new file mode 100644 index 0000000..68ad721 --- /dev/null +++ b/app/(dashboard)/room/[roomId]/_components/player-notification-popup.tsx @@ -0,0 +1,71 @@ +import { useBoard } from "@/context/board"; +import { Player } from "@/lib/schemas/player"; +import { cn } from "@/lib/utils"; +import { notificationIcons } from "@/messages/notification"; +import { EnumNotification } from "@/types/notifications"; +import { + Popover, + PopoverContent, + PopoverPortal, + PopoverTrigger, +} from "@radix-ui/react-popover"; +import { ReactNode, useState } from "react"; + +export function PlayerNotificationPopup({ + children, + player, +}: { + children: ReactNode; + player: Player; +}) { + const { handleNotifyPlayer } = useBoard(); + const [open, setOpen] = useState(false); + + const onNotifificationClick = (notification: EnumNotification) => { + setOpen(false); + if (player.choice) return; + + handleNotifyPlayer(player.id, notification); + }; + + return ( + setOpen(open)}> + setOpen((prev) => !prev)} + disabled={!!player.choice} + > +
+ {children} +
+
+ + +
+ {Object.keys(notificationIcons).map((notification) => ( +
+ onNotifificationClick(notification as EnumNotification) + } + className="p-1 w-10 cursor-pointer aspect-square rounded-full hover:bg-gray-100" + > + + {notificationIcons[notification as EnumNotification]} + +
+ ))} +
+
+
+
+ ); +} diff --git a/app/(dashboard)/room/[roomId]/_components/players-cards.tsx b/app/(dashboard)/room/[roomId]/_components/players-cards.tsx deleted file mode 100644 index a22cd55..0000000 --- a/app/(dashboard)/room/[roomId]/_components/players-cards.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { Button } from "@/components/ui/button"; -import { useBoard } from "@/context/board"; -import { PlayerCard } from "./player-card"; - -export const PlayersCards = () => { - const { others, self, handleRevealCards, revealCards, handleReset } = - useBoard(); - - const players = [self, ...others]; - - if (!others.length) { - return ( -
-

Sozinho por aqui... 😴

- {/* adicionar botão de convidar */} -
- ); - } - - const onRevealClick = () => { - if (revealCards) { - handleReset(); - } - handleRevealCards(); - }; - - return ( -
-
- {players.map((player) => ( - - ))} -
- {/*
*/} - - - {/*
*/} - -
- ); -}; diff --git a/components/ui/avatar.tsx b/components/ui/avatar.tsx index ccc94a7..d135935 100644 --- a/components/ui/avatar.tsx +++ b/components/ui/avatar.tsx @@ -12,7 +12,7 @@ const Avatar = React.forwardRef< {
- + {fallback()} diff --git a/public/sounds/car_horn.mp3 b/public/sounds/car_horn.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..d47a0f0dfdd6b744ed26def87e00257abb5ba204 GIT binary patch literal 51360 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 literal 0 HcmV?d00001 diff --git a/public/sounds/police.mp3 b/public/sounds/police.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..f307483df222536023f95f0d67a80b263ef8b246 GIT binary patch literal 48191 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 literal 0 HcmV?d00001 From 8f0c90a35300e7d52f7632d35f71bf40c436316a Mon Sep 17 00:00:00 2001 From: ItaloMedici <59889993+ItaloMedici@users.noreply.github.com> Date: Sat, 17 Aug 2024 11:08:15 -0300 Subject: [PATCH 16/20] refactor: force dynamic --- app/api/[roomId]/board/status/route.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/api/[roomId]/board/status/route.ts b/app/api/[roomId]/board/status/route.ts index 523f17a..414a1d8 100644 --- a/app/api/[roomId]/board/status/route.ts +++ b/app/api/[roomId]/board/status/route.ts @@ -7,6 +7,8 @@ import { joinBoardAndValidateLimit } from "@/use-cases/player/join-board-and-val import { getUserRoom } from "@/use-cases/room"; import { getServerSession } from "next-auth"; +export const dynamic = "force-dynamic"; + export async function GET( _: Request, { params }: { params: { roomId: string } } From 88ca3dff14ed065588082dfc0e6e031cf6bc3362 Mon Sep 17 00:00:00 2001 From: ItaloMedici <59889993+ItaloMedici@users.noreply.github.com> Date: Sat, 17 Aug 2024 11:08:48 -0300 Subject: [PATCH 17/20] fix: revalidate home when favorite room --- use-cases/room/favorite-room.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/use-cases/room/favorite-room.ts b/use-cases/room/favorite-room.ts index fd4c1f0..fde824a 100644 --- a/use-cases/room/favorite-room.ts +++ b/use-cases/room/favorite-room.ts @@ -2,6 +2,7 @@ import { db } from "@/lib/db"; import { userSchema } from "@/lib/schemas/user"; +import { revalidatePath } from "next/cache"; import { z } from "zod"; import { validator } from "../validator"; @@ -31,5 +32,7 @@ export const favoriteRoom = validator({ id: userRoom.id, }, }); + + revalidatePath("/"); }, }); From 3a20e1863367ba6080b7408d515d8d26994713e9 Mon Sep 17 00:00:00 2001 From: ItaloMedici <59889993+ItaloMedici@users.noreply.github.com> Date: Sat, 17 Aug 2024 11:09:16 -0300 Subject: [PATCH 18/20] chore: add no-unused-vars rule --- .eslintrc.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.eslintrc.json b/.eslintrc.json index bffb357..f8394a3 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,3 +1,6 @@ { - "extends": "next/core-web-vitals" + "extends": "next/core-web-vitals", + "rules": { + "no-unused-vars":"error" + } } From 00f10ef454761f5eabe93ad9da3a0158162934e4 Mon Sep 17 00:00:00 2001 From: ItaloMedici <59889993+ItaloMedici@users.noreply.github.com> Date: Sat, 17 Aug 2024 11:09:38 -0300 Subject: [PATCH 19/20] refactor: remove unused variables --- components/card/numeric-card.tsx | 1 - components/room-actions/index.tsx | 1 - lib/consts.ts | 1 + lib/db/index.ts | 1 - 4 files changed, 1 insertion(+), 3 deletions(-) diff --git a/components/card/numeric-card.tsx b/components/card/numeric-card.tsx index e252ac2..05924bc 100644 --- a/components/card/numeric-card.tsx +++ b/components/card/numeric-card.tsx @@ -45,7 +45,6 @@ export const NumericCard = ({ selected, bgColor, label, - colorOnHover, }: NumericCardProps) => { return (
diff --git a/components/room-actions/index.tsx b/components/room-actions/index.tsx index 8ac7985..b5b4b9a 100644 --- a/components/room-actions/index.tsx +++ b/components/room-actions/index.tsx @@ -30,7 +30,6 @@ export const RoomActions = ({ side, sideOffset, id, - name, roomOwnerEmail, }: ActionsProps) => { const { data } = useSession(); diff --git a/lib/consts.ts b/lib/consts.ts index 68d96f2..4b8f1c4 100644 --- a/lib/consts.ts +++ b/lib/consts.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-unused-vars */ export enum SearchParams { FAVORITES = "favorites", SEARCH = "search", diff --git a/lib/db/index.ts b/lib/db/index.ts index 3cc2054..38c5315 100644 --- a/lib/db/index.ts +++ b/lib/db/index.ts @@ -1,5 +1,4 @@ import { PrismaClient } from "@prisma/client"; -import { gl } from "date-fns/locale"; const prisma = ((globalThis as any).prisma as PrismaClient) ?? new PrismaClient(); From 44a98c5cc65ea0f075ca8f6d45737bb3743b05dd Mon Sep 17 00:00:00 2001 From: ItaloMedici Date: Wed, 21 Aug 2024 02:15:59 +0000 Subject: [PATCH 20/20] chore(release): v0.3.0 --- CHANGELOG.md | 16 ++++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c80a575..9abe237 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ +# [0.3.0](https://github.com/ItaloMedici/pontim/compare/v0.2.0...v0.3.0) (2024-08-21) + + +### Bug Fixes + +* adjust reveal event key ([7d528c6](https://github.com/ItaloMedici/pontim/commit/7d528c6eb1f5fc19ab0b06b7dc60d1ed4c78488a)) +* revalidate home when favorite room ([88ca3df](https://github.com/ItaloMedici/pontim/commit/88ca3dff14ed065588082dfc0e6e031cf6bc3362)) + + +### Features + +* create messages ([1126015](https://github.com/ItaloMedici/pontim/commit/1126015cf41cb77d7cd342ace06a463f0aa7c6df)) +* create notifications type ([89f442b](https://github.com/ItaloMedici/pontim/commit/89f442b7b7c97f2c217cf70225daca5998fb69c7)) +* create player notifications ([d9d863c](https://github.com/ItaloMedici/pontim/commit/d9d863c5cd03774029247c54b08216a49718fdf1)) +* migrate all pages routes for api folder ([f1d8ade](https://github.com/ItaloMedici/pontim/commit/f1d8ade39aa2db9e1714cda92cfbc52b956b6993)) + # 0.2.0 (2024-07-20) diff --git a/package-lock.json b/package-lock.json index 2b33569..99bb6df 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "pontim", - "version": "0.2.0", + "version": "0.3.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "pontim", - "version": "0.2.0", + "version": "0.3.0", "hasInstallScript": true, "dependencies": { "@hookform/resolvers": "^3.3.4", diff --git a/package.json b/package.json index f8b60df..7cf8238 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pontim", - "version": "0.2.0", + "version": "0.3.0", "private": true, "scripts": { "dev": "next dev",