|
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> |
|
); |
|
} |
|
|