import React, { useEffect, useState } from "react"; import { commands, GameSettings, LobbyState, PingStartCondition, PlayerProfile } from "@/bindings"; import { useTauriEvent } from "@/lib/hooks"; import ProfilePicture, { iconForDecor, ProfileDecor } from "./ProfilePicture"; import { defaultSettings } from "./MenuScreen"; import { ask } from "@tauri-apps/plugin-dialog"; import { IconArrowBigLeftLinesFilled, IconCircleCheckFilled, IconCircleDashedPlus, IconFlagFilled, IconInfoCircleFilled, IconSettingsFilled } from "@tabler/icons-react"; import LoadingCover from "./LoadingCover"; import GameSettingsModal from "./game-settings/GameSettingsModal"; function ProfileList({ profiles, decoration, emptyText }: { profiles: [string, PlayerProfile][]; decoration: ProfileDecor; emptyText: string; }) { return (
{profiles.length === 0 && {emptyText}} {profiles.map(([k, p]) => ( ))}
); } function TeamButton({ onClick, active, deco, text }: { onClick: () => void; active: boolean; deco: ProfileDecor; text: string; }) { const Icon = iconForDecor(deco); return ( ); } const initLobbyState: LobbyState = { profiles: {}, join_code: "", teams: {}, self_id: "", is_host: false, settings: defaultSettings() }; export default function LobbyScreen() { const [lobbyState, setLobbyState] = useState(initLobbyState); const [loadingCover, setLoadingCover] = useState(true); const [settingOpen, setSettingsOpen] = useState(false); useEffect(() => { let cancel = false; const clear = setTimeout(() => { commands.getLobbyState().then((state) => { if (!cancel) { setLobbyState(state); setLoadingCover(false); } }); }, 300); return () => { cancel = true; clearTimeout(clear); }; }, [setLobbyState]); useTauriEvent("lobbyStateUpdate", () => { commands.getLobbyState().then((state) => { setLobbyState(state); }); }); const profiles = Object.entries(lobbyState.profiles).filter(([_, p]) => p !== undefined) as [ string, PlayerProfile ][]; const seekers = profiles.filter(([id, _]) => lobbyState.teams[id] ?? false); const hiders = profiles.filter(([id, _]) => !(lobbyState.teams[id] ?? false)); const isSeeker = lobbyState.teams[lobbyState.self_id] ?? false; const onLeaveLobby = () => { // Don't prompt since the lobby is empty (besides us obv) // <= even though it should never be 0... hopefully.... if (lobbyState.is_host && profiles.length <= 1) { commands.quitToMenu(); return; } const hostMsg = lobbyState.is_host ? " You are the host so this will cancel the lobby" : ""; const msg = `Are you sure you want to leave this lobby?${hostMsg}`; ask(msg, { title: "Leave Lobby", kind: lobbyState.is_host ? "warning" : "info" }).then((choice) => { if (choice) { commands.quitToMenu(); } }); }; const canStart = lobbyState.is_host && seekers.length !== 0 && hiders.length !== 0; const onStartGame = () => { if (canStart) { setLoadingCover(true); ask( "Are you ready to start the game? New players will be unable to join. The hiding timer will begin the moment you press start." ) .then((choice) => { if (choice) { commands.hostStartGame().finally(() => { setLoadingCover(false); }); } else { setLoadingCover(false); } }) .catch(() => { setLoadingCover(false); }); } }; const onOpenSettings = () => { setSettingsOpen(true); }; const onSettingsSave = (settings: GameSettings) => { commands.hostUpdateSettings(settings); setSettingsOpen(false); }; return ( <> {settingOpen && ( )}
Lobby Join: {lobbyState.join_code}
commands.switchTeams(true)} active={isSeeker} text="Seekers" deco="seeker" />
{lobbyState.is_host && ( )} {lobbyState.is_host && ( )}
commands.switchTeams(false)} active={!isSeeker} text="Hiders" deco="hider" />
); }