| import Stack from '@mui/material/Stack'; |
| import TextField from '@mui/material/TextField'; |
| import {isValidRoomID, isValidPartialRoomID} from './generateNewRoomID'; |
| import {useCallback, useEffect, useState} from 'react'; |
| import Button from '@mui/material/Button'; |
| import {useSocket} from './useSocket'; |
| import FormGroup from '@mui/material/FormGroup'; |
| import FormControlLabel from '@mui/material/FormControlLabel'; |
| import Checkbox from '@mui/material/Checkbox'; |
| import {RoomState} from './types/RoomState'; |
| import setURLParam from './setURLParam'; |
| import {getURLParams} from './URLParams'; |
| import { |
| JoinRoomConfig, |
| Roles, |
| ServerState, |
| StreamingStatus, |
| } from './types/StreamingTypes'; |
| import Alert from '@mui/material/Alert'; |
|
|
| function capitalize(str: string): string { |
| return str.charAt(0).toUpperCase() + str.slice(1); |
| } |
|
|
| type Props = { |
| roomState: RoomState | null; |
| serverState: ServerState | null; |
| onJoinRoomOrUpdateRoles?: () => void; |
| streamingStatus: StreamingStatus; |
| }; |
|
|
| export default function RoomConfig({ |
| roomState, |
| serverState, |
| onJoinRoomOrUpdateRoles, |
| streamingStatus, |
| }: Props) { |
| const {socket, clientID} = useSocket(); |
|
|
| const urlParams = getURLParams(); |
| const roomIDParam = urlParams.roomID; |
| const autoJoinRoom = urlParams.autoJoin; |
|
|
| const [roomID, setRoomID] = useState<string>( |
| (roomIDParam ?? '').toUpperCase(), |
| ); |
| const [roomIDError, setRoomIDError] = useState<boolean>(false); |
| const [roles, setRoles] = useState<{speaker: boolean; listener: boolean}>({ |
| speaker: true, |
| listener: true, |
| }); |
| const [lockServer, setLockServer] = useState<boolean>(false); |
| const [lockServerName, setLockServerName] = useState<string>(''); |
|
|
| const [joinInProgress, setJoinInProgress] = useState<boolean>(false); |
| const [didAttemptAutoJoin, setDidAttemptAutoJoin] = useState<boolean>(false); |
|
|
| const isValidServerLock = |
| lockServer === false || |
| (lockServerName != null && lockServerName.length > 0); |
| const isValidRoles = Object.values(roles).filter(Boolean).length > 0; |
| const isValidAllInputs = |
| isValidRoomID(roomID) && isValidRoles && isValidServerLock; |
| const roomIDFromServer = roomState?.room_id ?? null; |
|
|
| const onJoinRoom = useCallback( |
| (createNewRoom: boolean) => { |
| if (socket == null) { |
| console.error('Socket is null, cannot join room'); |
| return; |
| } |
| console.debug(`Attempting to join roomID ${roomID}...`); |
|
|
| const lockServerValidated: string | null = |
| lockServer && roles['speaker'] ? lockServerName : null; |
|
|
| setJoinInProgress(true); |
|
|
| const configObject: JoinRoomConfig = { |
| roles: (Object.keys(roles) as Array<Roles>).filter( |
| (role) => roles[role] === true, |
| ), |
| lockServerName: lockServerValidated, |
| }; |
|
|
| socket.emit( |
| 'join_room', |
| clientID, |
| createNewRoom ? null : roomID, |
| configObject, |
| (result) => { |
| console.log('join_room result:', result); |
| if (createNewRoom) { |
| setRoomID(result.roomID); |
| } |
| if (onJoinRoomOrUpdateRoles != null) { |
| onJoinRoomOrUpdateRoles(); |
| } |
| setURLParam('roomID', result.roomID); |
| setJoinInProgress(false); |
| }, |
| ); |
| }, |
| [ |
| clientID, |
| lockServer, |
| lockServerName, |
| onJoinRoomOrUpdateRoles, |
| roles, |
| roomID, |
| socket, |
| ], |
| ); |
|
|
| useEffect(() => { |
| if ( |
| autoJoinRoom === true && |
| didAttemptAutoJoin === false && |
| socket != null |
| ) { |
| |
| |
| setDidAttemptAutoJoin(true); |
| if ( |
| isValidAllInputs && |
| joinInProgress === false && |
| roomIDFromServer == null |
| ) { |
| console.debug('Attempting to auto-join room...'); |
|
|
| onJoinRoom(false); |
| } else { |
| console.debug('Unable to auto-join room', { |
| isValidAllInputs, |
| joinInProgress, |
| roomIDFromServer, |
| }); |
| } |
| } |
| }, [ |
| autoJoinRoom, |
| didAttemptAutoJoin, |
| isValidAllInputs, |
| joinInProgress, |
| onJoinRoom, |
| roomIDFromServer, |
| socket, |
| ]); |
|
|
| return ( |
| <Stack direction="column" spacing="12px"> |
| <Stack direction="row" spacing="12px" sx={{alignItems: 'center'}}> |
| <TextField |
| size="small" |
| label="Room Code" |
| variant="outlined" |
| disabled={roomState?.room_id != null} |
| value={roomID} |
| error={roomIDError} |
| onChange={(e) => { |
| const id = e.target.value.toUpperCase(); |
| if (isValidPartialRoomID(id)) { |
| setRoomIDError(false); |
| setRoomID(id); |
| } else { |
| setRoomIDError(true); |
| } |
| }} |
| sx={{width: '8em'}} |
| /> |
|
|
| <div> |
| <Button |
| variant="contained" |
| disabled={ |
| isValidAllInputs === false || |
| joinInProgress || |
| streamingStatus !== 'stopped' |
| } |
| onClick={() => onJoinRoom(false)}> |
| {roomState?.room_id != null ? 'Update Roles' : 'Join Room'} |
| </Button> |
| </div> |
|
|
| {roomState?.room_id == null && ( |
| <div> |
| <Button |
| variant="contained" |
| disabled={ |
| roomState?.room_id != null || |
| joinInProgress || |
| streamingStatus !== 'stopped' |
| } |
| onClick={() => onJoinRoom(true)}> |
| {'Create New Room'} |
| </Button> |
| </div> |
| )} |
| </Stack> |
|
|
| <FormGroup> |
| {Object.keys(roles).map((role) => { |
| return ( |
| <FormControlLabel |
| disabled={streamingStatus !== 'stopped'} |
| key={role} |
| control={ |
| <Checkbox |
| checked={roles[role]} |
| onChange={(event: React.ChangeEvent<HTMLInputElement>) => { |
| setRoles((prevRoles) => ({ |
| ...prevRoles, |
| [role]: event.target.checked, |
| })); |
| }} |
| /> |
| } |
| label={capitalize(role)} |
| /> |
| ); |
| })} |
|
|
| {urlParams.enableServerLock && roles['speaker'] === true && ( |
| <> |
| <FormControlLabel |
| disabled={streamingStatus !== 'stopped'} |
| control={ |
| <Checkbox |
| checked={lockServer} |
| onChange={(event: React.ChangeEvent<HTMLInputElement>) => { |
| setLockServer(event.target.checked); |
| }} |
| /> |
| } |
| label="Lock Server (prevent other users from streaming)" |
| /> |
| </> |
| )} |
| </FormGroup> |
|
|
| {urlParams.enableServerLock && |
| roles['speaker'] === true && |
| lockServer && ( |
| <TextField |
| disabled={streamingStatus !== 'stopped'} |
| label="Enter Your Name + Expected Lock End Time" |
| variant="outlined" |
| value={lockServerName} |
| onChange={(event: React.ChangeEvent<HTMLInputElement>) => { |
| setLockServerName(event.target.value); |
| }} |
| helperText="Locking the server will prevent anyone else from using it until you close the page, in order to maximize server performance. Please only use this for live demos." |
| /> |
| )} |
|
|
| {serverState?.serverLock != null && |
| serverState.serverLock.clientID === clientID && ( |
| <Alert severity="success">{`The server is now locked for your use (${serverState?.serverLock?.name}). Close this window to release the lock so that others may use the server.`}</Alert> |
| )} |
| </Stack> |
| ); |
| } |
|
|