Spaces:
Sleeping
Sleeping
| "use client" | |
| import { FC, useEffect, useState } from "react" | |
| import Player from "./player/Player" | |
| import { | |
| ClientToServerEvents, | |
| createClientSocket, | |
| ServerToClientEvents, | |
| } from "../lib/socket" | |
| import Button from "./action/Button" | |
| import { Socket } from "socket.io-client" | |
| import ConnectingAlert from "./alert/ConnectingAlert" | |
| import PlaylistMenu from "./playlist/PlaylistMenu" | |
| import IconLoop from "./icon/IconLoop" | |
| import InputUrl from "./input/InputUrl" | |
| import UserList from "./user/UserList" | |
| import ChatPanel from "./chat/ChatPanel" | |
| import YoutubeSearch from "./search/YoutubeSearch" | |
| import NameModal from "./modal/NameModal" | |
| interface Props { | |
| id: string | |
| } | |
| let connecting = false | |
| const Room: FC<Props> = ({ id }) => { | |
| const [connected, setConnected] = useState(false) | |
| const [socket, setSocket] = useState<Socket< | |
| ServerToClientEvents, | |
| ClientToServerEvents | |
| > | null>(null) | |
| const [url, setUrl] = useState("") | |
| const [showNameModal, setShowNameModal] = useState(false) | |
| useEffect(() => { | |
| fetch("/api/socketio").finally(() => { | |
| if (socket !== null) { | |
| setConnected(socket.connected) | |
| } else { | |
| // Get user name from localStorage | |
| const userName = typeof window !== "undefined" | |
| ? localStorage.getItem("userName") || undefined | |
| : undefined | |
| // Show modal if no userName | |
| if (!userName || !userName.trim()) { | |
| setShowNameModal(true) | |
| return | |
| } | |
| // Get room metadata from sessionStorage (set during creation) | |
| const roomKey = `room_${id}_meta` | |
| const roomMeta = typeof window !== "undefined" && sessionStorage.getItem(roomKey) | |
| ? JSON.parse(sessionStorage.getItem(roomKey) || "{}") | |
| : {} | |
| const isPublic = roomMeta.isPublic | |
| const newSocket = createClientSocket(id, userName, isPublic) | |
| newSocket.on("connect", () => { | |
| setConnected(true) | |
| }) | |
| setSocket(newSocket) | |
| } | |
| }) | |
| return () => { | |
| if (socket !== null) { | |
| socket.disconnect() | |
| } | |
| } | |
| }, [id, socket]) | |
| const connectionCheck = () => { | |
| if (socket !== null && socket.connected) { | |
| connecting = false | |
| setConnected(true) | |
| return | |
| } | |
| setTimeout(connectionCheck, 100) | |
| } | |
| const handleNameSubmit = (name: string) => { | |
| // Save to localStorage | |
| if (typeof window !== "undefined") { | |
| localStorage.setItem("userName", name) | |
| } | |
| setShowNameModal(false) | |
| // Get room metadata from sessionStorage (set during creation) | |
| const roomKey = `room_${id}_meta` | |
| const roomMeta = typeof window !== "undefined" && sessionStorage.getItem(roomKey) | |
| ? JSON.parse(sessionStorage.getItem(roomKey) || "{}") | |
| : {} | |
| const isPublic = roomMeta.isPublic | |
| // Create socket connection with the name | |
| const newSocket = createClientSocket(id, name, isPublic) | |
| newSocket.on("connect", () => { | |
| setConnected(true) | |
| }) | |
| setSocket(newSocket) | |
| } | |
| if (showNameModal) { | |
| return <NameModal show={true} onSubmit={handleNameSubmit} /> | |
| } | |
| if (!connected || socket === null) { | |
| if (!connecting) { | |
| connecting = true | |
| connectionCheck() | |
| } | |
| return ( | |
| <div className={"flex justify-center"}> | |
| <ConnectingAlert /> | |
| </div> | |
| ) | |
| } | |
| return ( | |
| <div className={"flex flex-col sm:flex-row gap-2"}> | |
| <div className={"grow"}> | |
| <Player roomId={id} socket={socket} /> | |
| <div className={"flex flex-row gap-2 p-2 bg-dark-900/50 rounded-lg border border-dark-700/50 mt-2"}> | |
| <Button | |
| tooltip={"Do a forced manual sync"} | |
| className={"px-3 py-2 flex flex-row gap-2 items-center"} | |
| actionClasses={"bg-dark-800 hover:bg-dark-700 active:bg-dark-600 border border-dark-700/50"} | |
| onClick={() => { | |
| console.log("Fetching update", socket?.id) | |
| socket?.emit("fetch") | |
| }} | |
| > | |
| <IconLoop className={"hover:animate-spin"} /> | |
| <div className={"hidden-below-sm"}>Manual sync</div> | |
| </Button> | |
| <InputUrl | |
| className={"grow"} | |
| url={url} | |
| placeholder={"Play url now"} | |
| tooltip={"Play given url now"} | |
| onChange={setUrl} | |
| onSubmit={() => { | |
| console.log("Requesting", url, "now") | |
| socket?.emit("playUrl", url) | |
| setUrl("") | |
| }} | |
| > | |
| Play | |
| </InputUrl> | |
| </div> | |
| {/* Chat + YouTube Search */} | |
| <div className="grid grid-cols-1 md:grid-cols-2 gap-3 p-2 mt-2"> | |
| <ChatPanel socket={socket} /> | |
| <YoutubeSearch socket={socket} /> | |
| </div> | |
| <UserList socket={socket} /> | |
| </div> | |
| <PlaylistMenu socket={socket} /> | |
| </div> | |
| ) | |
| } | |
| export default Room |