import React, { useState, useEffect } from 'react'; import { CopyToClipboard } from 'react-copy-to-clipboard'; import QRCode from 'qrcode.react'; import { Access, Room, Permission, RoomShare, api, Restriction } from '../Common/Api'; import Dialog from './Dialog'; import ShareWith from './ShareWith'; import { SubmitInput } from './SubmitInput'; import { AccessOptions } from '../Common/Translation'; 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.'), access: t('bbb', 'Public: Everyone knowing the link is able to join. Password: Guests have to provide a password. Waiting room: A moderator has to accept every guest before they can join. Internal: Only Nextcloud users can join.'), 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.'), requireModerator: t('bbb', 'If enabled, normal users have to wait until a moderator is in the room.'), moderatorToken: t('bbb', 'If enabled, a moderator URL is generated which allows access with moderator permission.'), internalRestrictedShareWith: t('bbb', 'Only selected users and groups are allowed to access the room.'), 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.'), joinMuted: t('bbb', 'If enabled, all users will join the meeting muted.'), logoutURL: t('bbb', 'After the meeting ends, all users will be redirected to this URL'), }; 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='; type Props = { room: Room; restriction?: Restriction; updateProperty: (key: string, value: string | boolean | number | null) => Promise; open: boolean; setOpen: (open: boolean) => void; } const EditRoomDialog: React.FC = ({ room, restriction, updateProperty, open, setOpen }) => { const [shares, setShares] = useState(); const maxParticipantsLimit = (restriction?.maxParticipants || 0) < 0 ? undefined : restriction?.maxParticipants; const minParticipantsLimit = (restriction?.maxParticipants || -1) < 1 ? 0 : 1; 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]); useEffect(() => { if (!shares) { return; } updateProperty('shared', shares.filter(share => share.permission === Permission.Admin).length > 0); }, [shares]); function inputElement(label: string, field: string, type: 'text' | 'number' = 'text') { return (
updateProperty(field, value)} min={minParticipantsLimit} max={maxParticipantsLimit} /> {descriptions[field] && {descriptions[field]}}
); } function inputElementRestricted(label: string, field: string, type: 'text' | 'number' = 'text', restricted: boolean) { return (
updateProperty(field, value)} disabled={restricted} /> {descriptions[field] && {descriptions[field]}}
); } function selectElement(label: string, field: string, value: string, options: { [key: string]: string }, onChange: (value: string) => void) { return (
{(value === Access.Password && room.password) && } {descriptions[field] && {descriptions[field]}}
); } const accessOptions = {...AccessOptions}; for(const roomType of restriction?.roomTypes || []) { if (roomType !== room.access) { delete accessOptions[roomType]; } } return ( setOpen(false)} title={t('bbb', 'Edit "{room}"', { room: room.name })}>

{t('bbb', 'Room URL')}

{inputElement(t('bbb', 'Name'), 'name')} {inputElement(t('bbb', 'Welcome'), 'welcome')} {inputElement(t('bbb', 'Participant limit'), 'maxParticipants', 'number')} {selectElement(t('bbb', 'Access'), 'access', room.access, accessOptions, (value) => { updateProperty('access', value); })} {inputElementRestricted(t('bbb', 'Custom redirect after meeting'), 'logoutURL', 'text', !restriction?.allowLogoutURL)} {room.access === Access.InternalRestricted &&
{descriptions.internalRestrictedShareWith}
}
{!room.everyoneIsModerator && }
updateProperty('everyoneIsModerator', event.target.checked)} />
{descriptions.moderator}
updateProperty('moderatorToken', event.target.checked ? 'true' : null)} />
{!!room.moderatorToken && } {descriptions.moderatorToken}

{t('bbb', 'Miscellaneous')}

updateProperty('record', event.target.checked)} />

{descriptions.recording}

updateProperty('requireModerator', event.target.checked)} />

{descriptions.requireModerator}

updateProperty('listenOnly', event.target.checked)} />

{descriptions.listenOnly}

updateProperty('mediaCheck', !event.target.checked)} />

{descriptions.mediaCheck}

updateProperty('cleanLayout', event.target.checked)} />

{descriptions.cleanLayout}

updateProperty('joinMuted', event.target.checked)} />

{descriptions.joinMuted}

); }; export default EditRoomDialog;