"use client"; import { useState, useEffect } from "react"; import { Markazi_Text, Nunito } from "next/font/google"; import { useRouter } from "next/navigation"; import Image from "next/image"; import Link from "next/link"; import { useAuth } from "react-oidc-context"; import { useSession } from "muzak/contexts/SessionContext"; import { getUser, api, Track } from "muzak/data/fetcher"; import getSessionId from "muzak/data/session"; import { useSpotifyIframe } from "muzak/contexts/SpotifyIframe"; const nunito = Nunito({ weight: "900", subsets: ["latin"], }); const MAX_PARTY_SIZE = 8; export default function Lobby() { const [userList, setUserList] = useState([]); const [noList, setNoList] = useState([]); const [yesList, setYesList] = useState([]); const [sessionSocket, setSessionSocket] = useState(null); const { sessionId, setSessionId } = useSession(); const [sessionState, setSessionState] = useState("lobby"); const [currentSong, setCurrentSong] = useState(); const [songLoading, setSongLoading] = useState(false); const [spotifyId, setSpotifyId] = useState(null); const auth = useAuth(); const user = getUser(); const router = useRouter(); const controller = useSpotifyIframe(); const [revealed, setRevealed] = useState(false); const [playingPercentage, setPlayingPercentage] = useState(0); const [secondsLeft, setSecondsLeft] = useState(30); const [state, setState] = useState("lobby"); // lobby, playing, waiting, loading // Main message handler and dispatcher function onMessage(e) { console.log(e); let data = JSON.parse(e.data); for (let key in data) { if (key === "joined") { addUser(data[key]); } else if (key == "track") { getTrack(); } else if (key == "voted") { voteUser(data[key]); } else if (key == "done") { router.push("/post-game"); } } console.log(data); } // Setup session useEffect(() => { //console.log("session: ", sessionId); let socket: WebSocket | null; if (sessionId) { socket = new WebSocket( `${process.env.NEXT_PUBLIC_WS_HOST}/voting/session/${sessionId}/`, ); socket.onmessage = onMessage; setSessionSocket(socket); // console.log("session made: ", sessionId); } return () => { if (socket) { socket.close(); } }; }, [sessionId]); async function setSession() { const id = await getSessionId(); setSessionId(id); console.log("Session ID:", id); } useEffect(() => { if (!auth.isLoading && !auth.error && auth.isAuthenticated) { setSession(); } }, [auth]); function startSession() { setSessionState("voting"); setState("loading"); getTrack(); } function addUser(user: object) { const newUser = { id: user["id"], name: user["username"], avatar: `https://api.dicebear.com/9.x/bottts-neutral/svg?seed=${user["id"]}`, hidden: false, }; setUserList((prevUserList) => { if (prevUserList.find((u) => u.id === user["id"])) { console.log("User already exists, not adding"); return prevUserList; } return [...prevUserList, newUser]; }); } // Visually processes the incoming vote for a user. function voteUser(vote: object) { const userId = vote["id"]; const userName = vote["username"]; const points = vote["points"]; if (points === 0) { setYesList((prevYesList) => { //if (prevYesList.find((u) => u.id === userId)) return prevYesList; return prevYesList.filter((u) => u.id !== userId); }); setNoList((prevNoList) => { if (prevNoList.find((u) => u.id === userId)) { return prevNoList; } return [ ...prevNoList, { id: userId, name: userName, avatar: `https://api.dicebear.com/9.x/bottts-neutral/svg?seed=${userId}`, }, ]; }); } else { setNoList((prevNoList) => { return prevNoList.filter((u) => u.id !== userId); }); setYesList((prevYesList) => { if (prevYesList.find((u) => u.id === userId)) { return prevYesList; } return [ ...prevYesList, { id: userId, name: userName, avatar: `https://api.dicebear.com/9.x/bottts-neutral/svg?seed=${userId}`, }, ]; }); } setUserList((prevUserList) => { // Set hidden true on the user that voted: return prevUserList.map((user) => { if (user.id === userId) { return { ...user, hidden: true }; } return user; }); }); } async function getTrack() { setSongLoading(true); setState("loading"); setUserList((prevUserList) => { return prevUserList.map((user) => { return { ...user, hidden: false }; }); }); setYesList([]); setNoList([]); const { data: session } = await api.sessions.get({ session_id: sessionId }); const trackId = session?.current_track; if (trackId) { const { data: track } = await api.tracks.detail({ id: trackId }); console.log(session); console.log(track); setCurrentSong(track); } else { nextTrack(); } setSpotifyId(session?.current_track); setSongLoading(false); } async function nextTrack() { console.log("nextTrack"); setState("loading"); setRevealed(false); setSongLoading(true); sessionSocket.send( JSON.stringify({ action: "next", token: user.access_token, }), ); } async function endPlay() { controller?.seek(100); } // Spotify Player stuff useEffect(() => { if (controller) { console.log("Loaded track:", spotifyId); controller.loadUri(`spotify:track:${spotifyId}`); controller.play(); // Note: do not set playing state here, but later when its actually playing. console.log(controller._listeners); if (controller._listeners["playback_update"].length === 0) { controller.addListener("playback_update", (e) => { updatePlayback(e); }); } } else { console.log("Spotify player not initialized"); } }, [controller, spotifyId]); function updatePlayback(e) { let duration = e.data.duration; let playingPosition = e.data.position; const playingSeconds = Math.floor((duration - playingPosition) / 1000); setPlayingPercentage((playingPosition / duration) * 100); setSecondsLeft((s) => { setState((state) => { if (playingSeconds >= 1) { return "playing"; } if (state == "playing" && s <= 0) { console.log("track ended"); return "waiting"; } return state; }); return playingSeconds; }); } async function playTrack() { controller.play(); } async function pauseTrack() { controller.togglePlay(); } useEffect(() => { console.log("useEffect state:", state); if (state == "waiting") { setRevealed(true); setTimeout(() => { setState("next"); }, 5000); } else if (state == "next") { nextTrack(); } }, [state]); if (sessionState == "lobby") { return (

LOBBY

Players: {userList.length}
{userList.length === 0 ? (
Waiting for players...
) : (
{userList.map((user) => (
{user.name} {user.name} {user.host && (
Crown image
)}
))}
)}
); } else if (sessionState == "voting") { return (
{(state == "playing" || state == "waiting") && (
{secondsLeft}
)}
{noList.map((user) => (
{user.name}
{user.name}
))}{" "}
Meh
{!songLoading && currentSong ? (
{currentSong.name}
) : (
Loading...
)}
{yesList.map((user) => (
{user.name}
{user.name}
))}{" "}
Yeah
{!songLoading && currentSong ? (

{currentSong.artist}

{currentSong.name}

) : (

Loading

...

)}
!u.hidden) ? "bg-blue-950/80" : "bg-transparent p-0"} `} > {userList.map((user) => (
{user.name}
{user.name}
))}
); } }