diff --git a/frontend/app/explore-rooms/explore-rooms.tsx b/frontend/app/explore-rooms/explore-rooms.tsx new file mode 100644 index 00000000..37f35396 --- /dev/null +++ b/frontend/app/explore-rooms/explore-rooms.tsx @@ -0,0 +1,33 @@ +"use client"; + +import RoomCard from "./room-card"; +import { useCallback, useEffect } from "react"; +import { useRouter } from "next/navigation"; +import { DeleteRoomEvent, RoomEntity } from "@/app/lib/dtos"; +import { chatSocket as socket } from "@/socket"; + +export function ExploreRooms({ rooms }: { rooms: RoomEntity[] }) { + const router = useRouter(); + const handleDeleteRoomEvent = useCallback( + (data: DeleteRoomEvent) => { + router.refresh(); + }, + [router], + ); + useEffect(() => { + socket.on("delete-room", handleDeleteRoomEvent); + return () => { + socket.off("delete-room", handleDeleteRoomEvent); + }; + }, [handleDeleteRoomEvent]); + return ( +
+

Explore Rooms

+
+ {rooms.map((room) => ( + + ))} +
+
+ ); +} diff --git a/frontend/app/explore-rooms/page.tsx b/frontend/app/explore-rooms/page.tsx index f6dcc1d4..8dadd5b9 100644 --- a/frontend/app/explore-rooms/page.tsx +++ b/frontend/app/explore-rooms/page.tsx @@ -1,16 +1,11 @@ import { getRooms } from "@/app/lib/actions"; -import RoomCard from "./room-card"; +import { ExploreRooms } from "./explore-rooms"; export default async function ExploreRoomsPage() { const rooms = await getRooms({ joined: false }); return ( -
-

Explore Rooms

-
- {rooms.map((room) => ( - - ))} -
-
+ <> + + ); } diff --git a/frontend/app/lib/client-socket-provider.tsx b/frontend/app/lib/client-socket-provider.tsx index 44243e22..4166a55e 100644 --- a/frontend/app/lib/client-socket-provider.tsx +++ b/frontend/app/lib/client-socket-provider.tsx @@ -7,10 +7,7 @@ import { useCallback, useEffect } from "react"; import { useAuthContext } from "./client-auth"; import { DenyEvent, - DeleteRoomEvent, - EnterRoomEvent, InviteEvent, - LeaveRoomEvent, MatchEvent, MessageEvent, PublicUserEntity, @@ -32,56 +29,6 @@ export default function SocketProvider() { }); }; - const handleDeleteRoomEvent = useCallback( - (data: DeleteRoomEvent) => { - if (pathName === "/room/" + data.roomId.toString()) { - showDeleteRoomNotificationToast(); - router.push("/room"); - router.refresh(); - } else if ( - pathName.startsWith("/room/") || - pathName === "/explore-rooms" - ) { - router.refresh(); - } - }, - [pathName, router], - ); - - const handleEnterRoomEvent = useCallback( - (data: EnterRoomEvent) => { - if (pathName === "/room/" + data.roomId.toString()) { - router.refresh(); - } else if ( - (pathName.startsWith("/room/") || pathName === "/room") && - currentUser?.id === data.userId - ) { - router.refresh(); - } - }, - [currentUser, pathName, router], - ); - - const handleLeaveRoomEvent = useCallback( - (data: LeaveRoomEvent) => { - if ( - pathName === "/room/" + data.roomId.toString() && - data.userId === currentUser?.id - ) { - router.push("/room"); - router.refresh(); - } else if (pathName === "/room/" + data.roomId.toString()) { - router.refresh(); - } else if ( - (pathName.startsWith("/room/") || pathName === "/room") && - currentUser?.id === data.userId - ) { - router.refresh(); - } - }, - [currentUser, pathName, router], - ); - const MatchPong = (data: MatchEvent) => { router.push(`/pong/${data.roomId}?mode=player`); }; @@ -168,13 +115,10 @@ export default function SocketProvider() { const handler = (event: string, data: any) => { if (event === "message") { showMessageToast(data); - } else if (event === "delete-room") { - handleDeleteRoomEvent(data); - } else if (event === "enter-room") { - handleEnterRoomEvent(data); - } else if (event === "leave") { - handleLeaveRoomEvent(data); } else if ( + event === "delete-room" || + event === "enter-room" || + event === "leave" || event === "mute" || event === "unmute" || event === "update-role" @@ -202,12 +146,6 @@ export default function SocketProvider() { chatSocket.offAny(handler); chatSocket.disconnect(); }; - }, [ - currentUser, - handleDeleteRoomEvent, - handleEnterRoomEvent, - handleLeaveRoomEvent, - toast, - ]); + }, [currentUser, toast]); return <>; } diff --git a/frontend/app/lib/hooks/useKick.ts b/frontend/app/lib/hooks/useKick.ts index 5c22abbc..edd9e519 100644 --- a/frontend/app/lib/hooks/useKick.ts +++ b/frontend/app/lib/hooks/useKick.ts @@ -1,11 +1,12 @@ "use client"; import { kickUserOnRoom } from "@/app/lib/actions"; -import type { UserOnRoomEntity } from "@/app/lib/dtos"; +import type { LeaveRoomEvent, UserOnRoomEntity } from "@/app/lib/dtos"; import { toast } from "@/components/ui/use-toast"; -import { useCallback, useState } from "react"; +import { useCallback, useEffect, useState } from "react"; import { useRouter } from "next/navigation"; import { chatSocket as socket } from "@/socket"; +import { usePathname } from "next/navigation"; const showKickErrorToast = () => { toast({ @@ -14,9 +15,37 @@ const showKickErrorToast = () => { }); }; -export function useKick(roomId: number, userId: number) { +export function useKick(roomId: number, userId: number, meId: number) { const router = useRouter(); const [kickPending, setKickPending] = useState(false); + const pathName = usePathname(); + + const handleLeaveRoomEvent = useCallback( + (data: LeaveRoomEvent) => { + if ( + pathName === "/room/" + data.roomId.toString() && + data.userId === meId + ) { + router.push("/room"); + router.refresh(); + } else if (pathName === "/room/" + data.roomId.toString()) { + router.refresh(); + } else if ( + (pathName.startsWith("/room/") || pathName === "/room") && + meId === data.userId + ) { + router.refresh(); + } + }, + [meId, pathName, router], + ); + + useEffect(() => { + socket.on("leave", handleLeaveRoomEvent); + return () => { + socket.off("leave", handleLeaveRoomEvent); + }; + }, [handleLeaveRoomEvent]); const kick = useCallback(async () => { setKickPending(true); diff --git a/frontend/app/room/[id]/sidebar-item.tsx b/frontend/app/room/[id]/sidebar-item.tsx index 5177c83a..36d62963 100644 --- a/frontend/app/room/[id]/sidebar-item.tsx +++ b/frontend/app/room/[id]/sidebar-item.tsx @@ -1,6 +1,8 @@ "use client"; import type { + DeleteRoomEvent, + EnterRoomEvent, PublicUserEntity, RoomEntity, UserOnRoomEntity, @@ -13,6 +15,7 @@ import { ContextMenuSeparator, ContextMenuTrigger, } from "@/components/ui/context-menu"; +import { useCallback, useEffect } from "react"; import { useRouter } from "next/navigation"; import { useBlock } from "@/app/lib/hooks/useBlock"; import { useInviteToGame } from "@/app/lib/hooks/useInviteToGame"; @@ -20,6 +23,7 @@ import { useKick } from "@/app/lib/hooks/useKick"; import { useMute } from "@/app/lib/hooks/useMute"; import { useUpdateRole } from "@/app/lib/hooks/useUpdateRole"; import MuteMenu from "./mute-menu"; +import { chatSocket as socket } from "@/socket"; function truncateString(str: string | undefined, num: number): string { if (!str) { @@ -51,7 +55,7 @@ export default function SidebarItem({ ); const { invitePending, isInvitingToGame, inviteToGame, cancelInviteToGame } = useInviteToGame(user.userId); - const { kickPending, kick } = useKick(room.id, user.userId); + const { kickPending, kick } = useKick(room.id, user.userId, me.userId); const { mutePending, isMuted, mute, unmute } = useMute( room.id, user.userId, @@ -73,6 +77,35 @@ export default function SidebarItem({ router.push(`/user/${user.userId}`); } }; + const handleEnterRoomEvent = useCallback( + (data: EnterRoomEvent) => { + if (room.id === data.roomId) { + router.refresh(); + } + }, + [router, room.id], + ); + const handleDeleteRoomEvent = useCallback( + (data: DeleteRoomEvent) => { + if (room.id === data.roomId) { + router.push("/room"); + router.refresh(); + } else { + router.refresh(); + } + }, + [room.id, router], + ); + + useEffect(() => { + socket.on("enter-room", handleEnterRoomEvent); + socket.on("delete-room", handleDeleteRoomEvent); + return () => { + socket.off("enter-room", handleEnterRoomEvent); + socket.off("delete-room", handleDeleteRoomEvent); + }; + }, [handleEnterRoomEvent, handleDeleteRoomEvent]); + return ( <> diff --git a/frontend/app/room/rooms-sidebar.tsx b/frontend/app/room/rooms-sidebar.tsx index 0cccc078..be78908a 100644 --- a/frontend/app/room/rooms-sidebar.tsx +++ b/frontend/app/room/rooms-sidebar.tsx @@ -1,9 +1,12 @@ "use client"; -import type { RoomEntity } from "@/app/lib/dtos"; +import type { EnterRoomEvent, RoomEntity } from "@/app/lib/dtos"; import { Stack } from "@/components/layout/stack"; import Link from "next/link"; +import { useCallback, useEffect } from "react"; import { usePathname, useRouter } from "next/navigation"; import CreateRoomDialog from "./create-room-dialog"; +import { useAuthContext } from "@/app/lib/client-auth"; +import { chatSocket as socket } from "@/socket"; function RoomButton({ room, @@ -42,10 +45,28 @@ function ExploreButton() { export default function RoomsSidebar({ rooms }: { rooms: RoomEntity[] }) { const pathname = usePathname(); + const { currentUser } = useAuthContext(); + const router = useRouter(); let selectedRoomId: number | undefined; if (pathname.startsWith("/room/")) { selectedRoomId = parseInt(pathname.split("/")[2], 10); } + + const handleEnterRoomEvent = useCallback( + (data: EnterRoomEvent) => { + if (currentUser?.id === data.userId) { + router.refresh(); + } + }, + [currentUser, router], + ); + useEffect(() => { + socket.on("enter-room", handleEnterRoomEvent); + return () => { + socket.off("enter-room", handleEnterRoomEvent); + }; + }, [handleEnterRoomEvent]); + return (