Kopie van https://gitlab.com/studieverenigingvia/ict/centurion met een paar aanpassingen
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
313 lines
8.1 KiB
313 lines
8.1 KiB
import { useState } from "react";
|
|
import {
|
|
Button,
|
|
Card,
|
|
Col,
|
|
Divider,
|
|
Form,
|
|
Input,
|
|
InputNumber,
|
|
Row,
|
|
Select,
|
|
Badge,
|
|
} from "antd";
|
|
import { red } from "@ant-design/colors";
|
|
|
|
import connection, {
|
|
useConfig,
|
|
useIsConnected,
|
|
useRoom,
|
|
useTimelineSongFileChanged,
|
|
} from "../lib/Connection";
|
|
|
|
import "../css/lobby.css";
|
|
import logo from "../img/via-logo.svg";
|
|
import haramlogo from "../img/harambee_logo.png";
|
|
import beer from "../img/beer.png";
|
|
import { RoomOptions } from "../types/types";
|
|
|
|
const { Option } = Select;
|
|
|
|
export interface PropType {
|
|
currentUserReady: boolean;
|
|
onCurrentUserReadyChange?: (ready: boolean) => void;
|
|
}
|
|
|
|
const Lobby = (props: PropType) => {
|
|
// Form/control states.
|
|
const [selectedRoomId, setSelectedRoomId] = useState(1);
|
|
const [seekTime, setSeekTime] = useState(0);
|
|
const [timelineName, setTimelineName] = useState(null);
|
|
const [joiningLobby, setJoiningLobby] = useState(false);
|
|
const [joinLobbyError, setJoinLobbyError] = useState(false);
|
|
const [isPreloading, setIsPreloading] = useState(false);
|
|
const timeline = useTimelineSongFileChanged();
|
|
|
|
// Room and logic states.
|
|
const isConnected = useIsConnected();
|
|
const room = useRoom();
|
|
const config = useConfig();
|
|
|
|
const isLeader = room?.isLeader || false;
|
|
const userCount = room?.userCount || 0;
|
|
|
|
async function handleJoin() {
|
|
await preloadAudio();
|
|
connection.requestSetReady();
|
|
props.onCurrentUserReadyChange?.(true);
|
|
}
|
|
|
|
async function applyRoomId(v: number) {
|
|
setJoiningLobby(true);
|
|
await connection.requestJoin(v);
|
|
setJoiningLobby(false);
|
|
setJoinLobbyError(!v);
|
|
}
|
|
|
|
function handleJoinRandomLobby() {
|
|
connection.requestJoinRandom();
|
|
setJoinLobbyError(false);
|
|
}
|
|
|
|
function handleTimelineNameSet(timelineName: any) {
|
|
setTimelineName(timelineName);
|
|
connection.setRoomOptions(
|
|
new RoomOptions(
|
|
seekTime * 1000 || 0,
|
|
timelineName || room?.timelineName || ""
|
|
)
|
|
);
|
|
}
|
|
|
|
function handleSetSeekTime(seekTime: number) {
|
|
setSeekTime(seekTime);
|
|
connection.setRoomOptions(
|
|
new RoomOptions(
|
|
seekTime * 1000 || 0,
|
|
timelineName || room?.timelineName || ""
|
|
)
|
|
);
|
|
}
|
|
|
|
function preloadAudio(): Promise<boolean> {
|
|
setIsPreloading(true);
|
|
const songFile = timeline?.songFile;
|
|
|
|
if (!songFile) {
|
|
return Promise.resolve(false);
|
|
}
|
|
|
|
return new Promise<boolean>((resolve) => {
|
|
const audioElement = new Audio();
|
|
audioElement.addEventListener("canplaythrough", () => {
|
|
// 'canplaythrough' means the browser thinks it has buffered enough to play
|
|
// until the end.
|
|
setIsPreloading(false);
|
|
resolve(true);
|
|
});
|
|
audioElement.src = songFile;
|
|
});
|
|
}
|
|
|
|
const leaderConfig = (
|
|
<Row justify="center">
|
|
<Col>
|
|
<Form
|
|
layout="horizontal"
|
|
labelCol={{ span: 8 }}
|
|
wrapperCol={{ span: 24 }}
|
|
>
|
|
<Form.Item label="Starttijd">
|
|
<Input
|
|
type="number"
|
|
suffix="sec"
|
|
value={seekTime}
|
|
onChange={(v) => handleSetSeekTime(parseInt(v.target.value) || 0)}
|
|
/>
|
|
</Form.Item>
|
|
|
|
<Form.Item label="Nummer">
|
|
<Select
|
|
defaultValue={(room && room.timelineName) || ""}
|
|
onChange={(e) => handleTimelineNameSet(e)}
|
|
>
|
|
{config &&
|
|
config.availableTimelines.map((item, i) => (
|
|
<Option key={item} value={item}>
|
|
{item}
|
|
</Option>
|
|
))}
|
|
</Select>
|
|
</Form.Item>
|
|
</Form>
|
|
|
|
<Button
|
|
block
|
|
type="primary"
|
|
loading={isPreloading}
|
|
onClick={handleJoin}
|
|
>
|
|
Start
|
|
</Button>
|
|
</Col>
|
|
</Row>
|
|
);
|
|
|
|
const nonLeaderConfig = (
|
|
<Row justify="center">
|
|
<Col>
|
|
<p>
|
|
{room?.running ? "We luisteren naar" : "We gaan luisteren naar"}{" "}
|
|
<b>{room && room.timelineName}</b> en
|
|
{room?.running && <span> zijn al gestart!</span>}
|
|
{!room?.running && (
|
|
<span> starten op {(room?.seekTime || 0) / 1000} seconden</span>
|
|
)}
|
|
</p>
|
|
|
|
<Button
|
|
block
|
|
type="primary"
|
|
disabled={!room || props.currentUserReady}
|
|
loading={isPreloading}
|
|
onClick={handleJoin}
|
|
>
|
|
{room && props.currentUserReady
|
|
? "Wachten op het startsein"
|
|
: "Kom erbij"}
|
|
</Button>
|
|
</Col>
|
|
</Row>
|
|
);
|
|
|
|
return (
|
|
<div className="lobby">
|
|
<Row className="centurion-title" justify="center">
|
|
<Col span={4} md={4}>
|
|
<img
|
|
src={beer}
|
|
className={`beer beer-flipped ${
|
|
isConnected ? "connected" : "connecting"
|
|
}`}
|
|
alt="beer"
|
|
/>
|
|
</Col>
|
|
<Col span={12} md={6}>
|
|
Centurion!
|
|
</Col>
|
|
<Col span={4} md={4}>
|
|
<img
|
|
src={beer}
|
|
className={`beer ${isConnected ? "connected" : "connecting"}`}
|
|
alt="beer"
|
|
/>
|
|
</Col>
|
|
</Row>
|
|
<Row>
|
|
<Col className="hints" span={24}>
|
|
<div>Honderd minuten...</div>
|
|
<div>Honderd shots...</div>
|
|
<div>Kun jij het aan?</div>
|
|
</Col>
|
|
</Row>
|
|
<br />
|
|
|
|
{!isConnected && (
|
|
<Row justify="center">
|
|
<Col className="lobby-connecting">
|
|
<h2>Verbinden...</h2>
|
|
</Col>
|
|
</Row>
|
|
)}
|
|
|
|
{isConnected && (
|
|
<Row justify="center">
|
|
<Col xs={24} sm={16} md={12} xl={10}>
|
|
<Card>
|
|
<h3>
|
|
Huidige lobby: <b>{room ? `#${room.id}` : "Geen lobby"}</b>
|
|
</h3>
|
|
|
|
{room && (
|
|
<Row>
|
|
{userCount === 1 ? (
|
|
<span>Er is één gebruiker aanwezig.</span>
|
|
) : (
|
|
<span>Er zijn {userCount} gebruikers aanwezig.</span>
|
|
)}
|
|
</Row>
|
|
)}
|
|
|
|
<Row justify="center">
|
|
{room?.users?.map((u) => (
|
|
<Badge
|
|
key={u.id}
|
|
status={u.readyToParticipate ? "success" : "error"}
|
|
/>
|
|
))}
|
|
</Row>
|
|
|
|
{room && <Row>Deel de link met je vrienden om mee te doen!</Row>}
|
|
|
|
<Divider />
|
|
|
|
{room && (isLeader ? leaderConfig : nonLeaderConfig)}
|
|
|
|
<Divider />
|
|
|
|
<Row justify="center">
|
|
<Col>
|
|
<InputNumber
|
|
style={{ width: "calc(100% - 150px)" }}
|
|
min={1}
|
|
max={100000}
|
|
value={selectedRoomId || room?.id || 0}
|
|
onChange={(v) => setSelectedRoomId(v || 0)}
|
|
/>
|
|
|
|
<Button
|
|
style={{ width: "150px" }}
|
|
type="primary"
|
|
loading={joiningLobby}
|
|
onClick={async () => {
|
|
await applyRoomId(selectedRoomId);
|
|
}}
|
|
>
|
|
Ga naar die lobby
|
|
</Button>
|
|
|
|
{joinLobbyError && (
|
|
<span style={{ color: red[4] }}>
|
|
Die lobby bestaat niet
|
|
</span>
|
|
)}
|
|
</Col>
|
|
</Row>
|
|
|
|
<Row justify="center">
|
|
<span className={"lobby-options-or"}>of</span>
|
|
</Row>
|
|
|
|
<Row justify="center">
|
|
<Col>
|
|
<Button
|
|
type="primary"
|
|
onClick={() => {
|
|
handleJoinRandomLobby();
|
|
}}
|
|
>
|
|
Join een nieuwe lobby
|
|
</Button>
|
|
</Col>
|
|
</Row>
|
|
</Card>
|
|
</Col>
|
|
</Row>
|
|
)}
|
|
<img src={haramlogo} className="haram-logo" alt="haramlogo"/>
|
|
<img src={logo} className="via-logo" alt="logo" />
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default Lobby;
|
|
|