2020-06-16 16:54:50 +02:00
import React , { useState , useEffect } from 'react' ;
2021-01-23 12:02:38 +01:00
import { CopyToClipboard } from 'react-copy-to-clipboard' ;
2021-01-26 10:29:13 +01:00
import QRCode from 'qrcode.react' ;
2020-08-27 17:21:34 +02:00
import { Access , Room , Permission , RoomShare , api , Restriction } from '../Common/Api' ;
2020-06-04 14:01:31 +02:00
import Dialog from './Dialog' ;
2020-06-15 17:23:53 +02:00
import ShareWith from './ShareWith' ;
2020-06-04 14:01:31 +02:00
import { SubmitInput } from './SubmitInput' ;
2020-08-27 17:21:34 +02:00
import { AccessOptions } from '../Common/Translation' ;
2020-06-04 14:01:31 +02:00
const descriptions : { [ key : string ] : string } = {
name : t ( 'bbb' , 'Descriptive name of this room.' ) ,
welcome : t ( 'bbb' , 'This message is shown to all users in the chat area after they joined.' ) ,
maxParticipants : t ( 'bbb' , 'Sets a limit on the number of participants for this room. Zero means there is no limit.' ) ,
recording : t ( 'bbb' , 'If enabled, the moderator is able to start the recording.' ) ,
2023-08-28 14:40:05 +02:00
access : t ( 'bbb' , 'Explanation of the different concepts that constitute access options :<br>- Public: Anyone who has the link can join.- <br>Internal: Only Nextcloud users can join.- <br>Password: Only guests who have the password can join..- <br>Waiting room: A moderator must accept each guest before they can join.- <br>Restricted : Only selected users and groups can access this room.' ) ,
2020-06-17 08:19:54 +02:00
moderator : t ( 'bbb' , 'A moderator is able to manage all participants in a meeting including kicking, muting or selecting a presenter. Users with the role moderator are also able to close a meeting or change the default settings.' ) ,
2020-08-29 14:37:50 +02:00
requireModerator : t ( 'bbb' , 'If enabled, normal users have to wait until a moderator is in the room.' ) ,
2021-01-22 19:12:55 +01:00
moderatorToken : t ( 'bbb' , 'If enabled, a moderator URL is generated which allows access with moderator permission.' ) ,
2021-01-23 12:10:58 +01:00
internalRestrictedShareWith : t ( 'bbb' , 'Only selected users and groups are allowed to access the room.' ) ,
2021-04-19 14:47:15 +02:00
listenOnly : t ( 'bbb' , 'If disabled, a microphone is needed to join the conference.' ) ,
mediaCheck : t ( 'bbb' , 'If enabled, the user has not to perform an echo call and webcam preview on the first join (available since BBB server 2.3).' ) ,
cleanLayout : t ( 'bbb' , 'If enabled, the user list, chat area and presentation are hidden by default.' ) ,
2021-07-30 12:12:42 +02:00
joinMuted : t ( 'bbb' , 'If enabled, all users will join the meeting muted.' ) ,
2020-06-04 14:01:31 +02:00
} ;
2021-01-30 10:40:13 +01:00
const LOGO_QR = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAOxAAADsQBlSsOGwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAGnSURBVFiF7de9TxRBHMbxzxG5BonRBOGsVRJfIvGFPwFKX0tjJGqsrfwvCC0YtbJSQyT4J0hB1BhtjZFCI4FoqTRCsbO43g24e+5Q3ZNsZm9+z8zzvZns7Rw9/a0jeIx1bNZ8rYe5WzuFt7CSILj9WsFwHtooADzA7XD/DG/CgDrUwHlcDZ/ncLfdtBoCn9cUGtN8yPiWd/QVikOhfZcQ4G1oD8cA8u2oa9ljyufe3vq+HYx7ph7Avv8YO4Rx2b4uy35oKqubFWhiBl+wiJf4imn0V52smxWYxc22vn7cwwHcqjJZ1RUYi4QXNYUzKQEm/1FvYCIlwEAJz/6UAB9KeN6nBFjAp13qH2VPRjKADdkr9Uek9h3XgicZwGk8wcFI7VConUoFMIZXOLGL5ySWVHgUywI08RSDJbyDwdusE+AGjpb0wjFcrxPgSoXwXJerAnScVgo63gXAaKSv49RVBFgL7dnIwN9dAMR0LrSreUfxbfgCd3BJdix/7Q/pBn5WDPuF++G+gQu4WMjq0Ii9+WPyWeFU3K4WHsm2o+7gNTwMX7SnbW0BScCZl0uGVe8AAAAASUVORK5CYII=' ;
2020-06-04 14:01:31 +02:00
type Props = {
2020-06-16 16:54:50 +02:00
room : Room ;
2020-08-27 17:21:34 +02:00
restriction? : Restriction ;
2021-01-22 19:12:55 +01:00
updateProperty : ( key : string , value : string | boolean | number | null ) = > Promise < void > ;
2020-06-16 16:54:50 +02:00
open : boolean ;
setOpen : ( open : boolean ) = > void ;
2020-06-04 14:01:31 +02:00
}
2020-08-27 17:21:34 +02:00
const EditRoomDialog : React.FC < Props > = ( { room , restriction , updateProperty , open , setOpen } ) = > {
2020-06-16 16:54:50 +02:00
const [ shares , setShares ] = useState < RoomShare [ ] > ( ) ;
2020-08-27 17:21:34 +02:00
const maxParticipantsLimit = ( restriction ? . maxParticipants || 0 ) < 0 ? undefined : restriction ? . maxParticipants ;
const minParticipantsLimit = ( restriction ? . maxParticipants || - 1 ) < 1 ? 0 : 1 ;
2020-06-16 16:54:50 +02:00
useEffect ( ( ) = > {
if ( ! open ) {
return ;
}
api . getRoomShares ( room . id ) . then ( roomShares = > {
console . log ( room . name , roomShares ) ;
setShares ( roomShares ) ;
} ) . catch ( err = > {
console . warn ( 'Could not load room shares.' , err ) ;
setShares ( [ ] ) ;
} ) ;
} , [ room . id , open ] ) ;
2020-06-04 14:01:31 +02:00
2020-09-08 17:01:50 +02:00
useEffect ( ( ) = > {
if ( ! shares ) {
return ;
}
updateProperty ( 'shared' , shares . filter ( share = > share . permission === Permission . Admin ) . length > 0 ) ;
} , [ shares ] ) ;
2020-06-04 18:56:55 +02:00
function inputElement ( label : string , field : string , type : 'text' | 'number' = 'text' ) {
2020-06-04 14:01:31 +02:00
return (
< div className = "bbb-form-element" >
< label htmlFor = { ` bbb- ${ field } ` } >
2020-06-04 18:56:55 +02:00
< h3 > { label } < / h3 >
2020-06-04 14:01:31 +02:00
< / label >
2020-08-27 17:21:34 +02:00
< SubmitInput initialValue = { room [ field ] } type = { type } name = { field } onSubmitValue = { value = > updateProperty ( field , value ) } min = { minParticipantsLimit } max = { maxParticipantsLimit } / >
2020-06-04 14:01:31 +02:00
{ descriptions [ field ] && < em > { descriptions [ field ] } < / em > }
< / div >
) ;
}
2020-06-16 16:54:50 +02:00
function selectElement ( label : string , field : string , value : string , options : { [ key : string ] : string } , onChange : ( value : string ) = > void ) {
2020-06-04 18:56:55 +02:00
return (
< div className = "bbb-form-element" >
< label htmlFor = { ` bbb- ${ field } ` } >
< h3 > { label } < / h3 >
< / label >
< select name = { field } value = { value } onChange = { ( event ) = > onChange ( event . target . value ) } >
{ Object . keys ( options ) . map ( key = > {
const label = options [ key ] ;
return < option key = { key } value = { key } > { label } < / option > ;
} ) }
< / select >
2021-01-23 12:02:38 +01:00
{ ( value === Access . Password && room . password ) && < CopyToClipboard text = { room . password } > < input type = "text" readOnly = { true } className = "icon-clippy" value = { room . password } / > < / CopyToClipboard > }
2020-06-04 18:56:55 +02:00
{ descriptions [ field ] && < em > { descriptions [ field ] } < / em > }
< / div >
) ;
}
2020-08-27 17:21:34 +02:00
const accessOptions = { . . . AccessOptions } ;
for ( const roomType of restriction ? . roomTypes || [ ] ) {
if ( roomType !== room . access ) {
delete accessOptions [ roomType ] ;
}
}
2020-06-04 14:01:31 +02:00
return (
2020-06-16 16:54:50 +02:00
< Dialog open = { open } onClose = { ( ) = > setOpen ( false ) } title = { t ( 'bbb' , 'Edit "{room}"' , { room : room.name } ) } >
2021-01-26 10:29:13 +01:00
< div className = "bbb-form-element" >
2021-01-27 11:20:26 +01:00
< h3 > { t ( 'bbb' , 'Room URL' ) } < / h3 >
2021-01-26 10:29:13 +01:00
< div className = "bbb-input-container" >
< CopyToClipboard text = { api . getRoomUrl ( room ) } > < input type = "text" readOnly = { true } className = "icon-clippy" value = { api . getRoomUrl ( room ) } / > < / CopyToClipboard >
< label className = "bbb-qrcode-container" >
< input type = "checkbox" / >
2021-01-30 10:40:13 +01:00
< QRCode value = { api . getRoomUrl ( room ) } level = "Q" imageSettings = { { src : LOGO_QR , excavate : true , height : 32 , width : 32 } } / >
2021-01-26 10:29:13 +01:00
< / label >
< / div >
< / div >
2020-06-16 16:54:50 +02:00
{ inputElement ( t ( 'bbb' , 'Name' ) , 'name' ) }
{ inputElement ( t ( 'bbb' , 'Welcome' ) , 'welcome' ) }
{ inputElement ( t ( 'bbb' , 'Participant limit' ) , 'maxParticipants' , 'number' ) }
2020-08-27 17:21:34 +02:00
{ selectElement ( t ( 'bbb' , 'Access' ) , 'access' , room . access , accessOptions , ( value ) = > {
2020-06-16 16:54:50 +02:00
updateProperty ( 'access' , value ) ;
} ) }
{ room . access === Access . InternalRestricted && < div className = "bbb-form-element bbb-form-shareWith" >
< ShareWith permission = { Permission . User } room = { room } shares = { shares } setShares = { setShares } / >
2021-01-23 12:10:58 +01:00
< em > { descriptions . internalRestrictedShareWith } < / em >
2020-06-16 16:54:50 +02:00
< / div > }
2020-06-15 17:23:53 +02:00
2020-06-16 16:54:50 +02:00
< div className = "bbb-form-element" >
< label htmlFor = { 'bbb-moderator' } >
< h3 > Moderator < / h3 >
< / label >
2020-06-17 08:19:54 +02:00
{ ! room . everyoneIsModerator && < ShareWith permission = { Permission . Moderator } room = { room } shares = { shares } setShares = { setShares } / > }
< div className = "bbb-mt-1" >
< input id = { ` bbb-everyoneIsModerator- ${ room . id } ` }
type = "checkbox"
className = "checkbox"
checked = { room . everyoneIsModerator }
onChange = { ( event ) = > updateProperty ( 'everyoneIsModerator' , event . target . checked ) } / >
< label htmlFor = { ` bbb-everyoneIsModerator- ${ room . id } ` } > { t ( 'bbb' , 'Every participant is moderator' ) } < / label >
< / div >
< em > { descriptions . moderator } < / em >
2021-01-22 19:12:55 +01:00
< div className = "bbb-mt-1" >
< input id = { ` bbb-moderatorToken- ${ room . id } ` }
type = "checkbox"
className = "checkbox"
checked = { ! ! room . moderatorToken }
onChange = { ( event ) = > updateProperty ( 'moderatorToken' , event . target . checked ? 'true' : null ) } / >
< label htmlFor = { ` bbb-moderatorToken- ${ room . id } ` } > { t ( 'bbb' , 'Moderator access via URL' ) } < / label >
< / div >
2021-01-23 12:02:38 +01:00
{ ! ! room . moderatorToken && < CopyToClipboard text = { api . getRoomUrl ( room , true ) } > < input type = "text" readOnly = { true } className = "icon-clippy" value = { api . getRoomUrl ( room , true ) } / > < / CopyToClipboard > }
2021-01-22 19:12:55 +01:00
< em > { descriptions . moderatorToken } < / em >
2020-06-16 16:54:50 +02:00
< / div >
2021-04-19 14:47:15 +02:00
< div className = "bbb-form-element" >
< h3 > { t ( 'bbb' , 'Miscellaneous' ) } < / h3 >
2020-06-04 14:01:31 +02:00
< div >
2021-04-19 14:47:15 +02:00
< div >
< input id = { ` bbb-record- ${ room . id } ` }
type = "checkbox"
className = "checkbox"
checked = { room . record }
disabled = { ! restriction ? . allowRecording }
onChange = { ( event ) = > updateProperty ( 'record' , event . target . checked ) } / >
< label htmlFor = { ` bbb-record- ${ room . id } ` } > { t ( 'bbb' , 'Recording' ) } < / label >
< / div >
< p > < em > { descriptions . recording } < / em > < / p >
2020-06-04 14:01:31 +02:00
< / div >
2020-08-29 14:37:50 +02:00
< div >
2021-04-19 14:47:15 +02:00
< div >
< input id = { ` bbb-requireModerator- ${ room . id } ` }
type = "checkbox"
className = "checkbox"
checked = { room . requireModerator }
onChange = { ( event ) = > updateProperty ( 'requireModerator' , event . target . checked ) } / >
< label htmlFor = { ` bbb-requireModerator- ${ room . id } ` } > { t ( 'bbb' , 'Require moderator to start room' ) } < / label >
< / div >
< p > < em > { descriptions . requireModerator } < / em > < / p >
< / div >
< div >
< div >
< input id = { ` bbb-listenOnly- ${ room . id } ` }
type = "checkbox"
className = "checkbox"
checked = { room . listenOnly }
onChange = { ( event ) = > updateProperty ( 'listenOnly' , event . target . checked ) } / >
< label htmlFor = { ` bbb-listenOnly- ${ room . id } ` } > { t ( 'bbb' , 'Listen only option' ) } < / label >
< / div >
< p > < em > { descriptions . listenOnly } < / em > < / p >
< / div >
< div >
< div >
< input id = { ` bbb-mediaCheck- ${ room . id } ` }
type = "checkbox"
className = "checkbox"
checked = { ! room . mediaCheck }
onChange = { ( event ) = > updateProperty ( 'mediaCheck' , ! event . target . checked ) } / >
< label htmlFor = { ` bbb-mediaCheck- ${ room . id } ` } > { t ( 'bbb' , 'Skip media check before usage' ) } < / label >
< / div >
< p > < em > { descriptions . mediaCheck } < / em > < / p >
< / div >
< div >
< div >
< input id = { ` bbb-cleanLayout- ${ room . id } ` }
type = "checkbox"
className = "checkbox"
checked = { room . cleanLayout }
onChange = { ( event ) = > updateProperty ( 'cleanLayout' , event . target . checked ) } / >
< label htmlFor = { ` bbb-cleanLayout- ${ room . id } ` } > { t ( 'bbb' , 'Clean layout' ) } < / label >
< / div >
< p > < em > { descriptions . cleanLayout } < / em > < / p >
2020-08-29 14:37:50 +02:00
< / div >
2021-07-30 12:12:42 +02:00
< div >
< div >
< input id = { ` bbb-joinMuted- ${ room . id } ` }
type = "checkbox"
className = "checkbox"
checked = { room . joinMuted }
onChange = { ( event ) = > updateProperty ( 'joinMuted' , event . target . checked ) } / >
< label htmlFor = { ` bbb-joinMuted- ${ room . id } ` } > { t ( 'bbb' , 'Join meeting muted' ) } < / label >
< / div >
< p > < em > { descriptions . joinMuted } < / em > < / p >
< / div >
2020-06-16 16:54:50 +02:00
< / div >
< / Dialog >
2020-06-04 14:01:31 +02:00
) ;
} ;
2020-08-27 17:21:34 +02:00
export default EditRoomDialog ;