UNPKG

bigbluebutton-strapi

Version:

Integrate online classes into Strapi CMS via BigBlueButton open-source video conferencing. This free plugin also provides API end-points to easily setup start and join buttons for web conferencing into any frontend app.

368 lines (355 loc) 13.9 kB
import React, { useState, useEffect } from 'react'; import PropTypes from 'prop-types'; import AceEditor from 'react-ace'; import { ModalLayout, ModalBody, ModalHeader, ModalFooter, } from '@strapi/design-system/ModalLayout'; import { Tabs, Tab, TabGroup, TabPanels, TabPanel } from '@strapi/design-system/Tabs'; import { Typography } from '@strapi/design-system/Typography'; import { Button } from '@strapi/design-system/Button'; import { Box } from '@strapi/design-system/Box'; import { TextInput } from '@strapi/design-system/TextInput'; import { Grid, GridItem } from '@strapi/design-system/Grid'; import { Switch } from '@strapi/design-system/Switch'; import { Link } from '@strapi/design-system/Link'; import { createClass } from '../../utils/apiCalls'; import ApiCreateEndPoint from './ApiCreateEndPoint'; import 'ace-builds/src-noconflict/mode-json'; import 'ace-builds/src-noconflict/theme-monokai'; import 'ace-builds/src-noconflict/ext-language_tools'; const Modal = ({ isVisible, handleClose }) => { const [isForm, setIsForm] = useState(true); const [className, setClassName] = useState(''); const [moderatorChecked, setModeratorChecked] = useState(false); const [moderatorAccessCode, setModeratorAccessCode] = useState(''); const [viewerChecked, setViewerChecked] = useState(false); const [viewerAccessCode, setViewerAccessCode] = useState(''); const [moderatorApproval, setModeratorApproval] = useState(false); const [classNameError, setClassNameError] = useState(''); const [moderatorCodeError, setModeratorCodeError] = useState(''); const [viewerCodeError, setViewerCodeError] = useState(''); const [bbbAdvanceSetting, setbbbAdvanceSetting] = useState({ maxParticipants: 100, logoutURL: 'https://higheredlab.com/', allowModsToUnmuteUsers: false, lockSettingsDisablePrivateChat: false, logo: 'https://higheredlab.com/wp-content/uploads/hel.png', muteOnStart: false, 'userdata-bbb_skip_check_audio': 'false', 'userdata-bbb_listen_only_mode': 'true', }); const classCreateData = { className, moderatorAccessCode, viewerAccessCode, bbbSettings: { moderatorApproval, ...bbbAdvanceSetting, }, }; async function handleCreateClass(data) { if (!className && !moderatorAccessCode && !viewerAccessCode) { setClassNameError('Class Name is required'); setModeratorCodeError('Moderator Access code is required'); setViewerCodeError('Viewer Access code is required'); } else if (!className) { setClassNameError('Class Name is required'); } else if (!moderatorAccessCode) { setModeratorCodeError('Moderator Access code is required'); } else if (!viewerAccessCode) { setViewerCodeError('Viewer Access code is required'); } else { const res = await createClass(data); if (res.status === 200) { handleClose(); setClassName(''); setModeratorAccessCode(''); setModeratorChecked(false); setViewerChecked(false); setViewerAccessCode(''); setModeratorApproval(false); setIsForm(true); } } } useEffect(() => { if (moderatorChecked && !moderatorAccessCode) { const accessCode = Math.random().toString().substring(2, 6); const code = parseInt(accessCode, 10); setModeratorAccessCode(code); } else if (!moderatorChecked) { setModeratorAccessCode(''); } if (viewerChecked && !viewerAccessCode) { const accessCode = Math.random().toString().substring(2, 6); const code = parseInt(accessCode, 10); setViewerAccessCode(code); } else if (!viewerChecked) { setViewerAccessCode(''); } }, [moderatorChecked, viewerChecked, isVisible, moderatorAccessCode, viewerAccessCode]); const onChangeJson = extraSetting => { setbbbAdvanceSetting(JSON.parse(extraSetting)); }; const handleTabChange = tabNum => { if (tabNum === 0) { setIsForm(true); } else if (tabNum === 1) { setIsForm(false); } }; return ( <div> {isVisible && ( <ModalLayout onClose={() => { setIsForm(true); handleClose(); }} labelledBy="title" > <ModalHeader> <Typography fontWeight="bold" textColor="neutral800" as="h2" id="title" variant="beta"> Create Class </Typography> </ModalHeader> <ModalBody> <TabGroup label="Some stuff for the label" id="tabs" variant="simple" onTabChange={tabNum => handleTabChange(tabNum)} > <Tabs> <Tab> <Typography textColor="neutral800" id="title" variant="delta"> Form </Typography> </Tab> <Tab> <Typography textColor="neutral800" id="title" variant="delta"> Api-EndPoint </Typography> </Tab> </Tabs> <TabPanels> <TabPanel> <Box color="neutral800" paddingTop={2} background="neutral0"> <Grid gap={5}> <GridItem col={5}> <Box padding={2}> <Typography variant="delta">Class Name</Typography> </Box> </GridItem> <GridItem col={6}> <Box padding={2}> <TextInput placeholder="Enter a class Name" aria-label="Class" name="className" error={classNameError || ''} onChange={e => { setClassName(e.target.value); setClassNameError(''); }} /> </Box> </GridItem> <GridItem col={5}> <Box padding={2}> <Typography variant="delta">Moderator Access Code</Typography> </Box> </GridItem> <GridItem col={5}> <Box padding={2}> <TextInput placeholder="Click on switch for Access Code" type="number" aria-label="moderatorAccessCode" name="moderatorAccessCode" error={moderatorCodeError || ''} onChange={e => { setModeratorAccessCode(e.target.value); setModeratorCodeError(''); }} value={moderatorAccessCode} size="S" /> </Box> </GridItem> <GridItem col={2}> <Box padding={2}> <Switch label="Activate moderator access code" selected={moderatorChecked} onChange={() => { setModeratorChecked(s => !s); setModeratorCodeError(''); }} data-testid="moderator-access-code" /> </Box> </GridItem> <GridItem col={5}> <Box padding={2}> <Typography variant="delta">Viewer Access Code</Typography> </Box> </GridItem> <GridItem col={5}> <Box padding={2}> <TextInput placeholder="Click on switch for Access Code" type="number" aria-label="viewerAccessCode" name="viewerAccessCode" error={viewerCodeError || ''} onChange={e => { setViewerAccessCode(e.target.value); setViewerCodeError(''); }} value={viewerAccessCode} size="S" /> </Box> </GridItem> <GridItem col={2}> <Box padding={2}> <Switch label="Activate viewer access code" selected={viewerChecked} onChange={() => { setViewerChecked(s => !s); setViewerCodeError(''); }} data-testid="viewer-access-code" /> </Box> </GridItem> <GridItem col={10}> <Box padding={2}> <Typography variant="delta"> Requires moderator approval to join </Typography> </Box> </GridItem> <GridItem col={2}> <Box padding={2}> <Switch label="Activate moderator approval to join" selected={moderatorApproval} onChange={() => setModeratorApproval(s => !s)} /> </Box> </GridItem> <GridItem col={11}> <Box padding={2}> <Typography variant="beta">Advance Settings</Typography> <Box> <Typography variant="epsilon"> You can customize settings for your BigBlueButton class. </Typography> </Box> </Box> </GridItem> <GridItem col={11}> <Box padding={2}> <AceEditor placeholder="BigBlueButton Settings" mode="json" theme="monokai" name="setting" onChange={onChangeJson} fontSize={18} showPrintMargin={false} showGutter highlightActiveLine height="300px" width="700px" defaultValue={`{ "maxParticipants":"100", "logoutURL":"https://higheredlab.com/", "allowModsToUnmuteUsers":"false", "lockSettingsDisablePrivateChat":"false", "logo":"https://higheredlab.com/wp-content/uploads/hel.png", "muteOnStart":"false", "userdata-bbb_skip_check_audio":"false", "userdata-bbb_listen_only_mode":"true" }`} setOptions={{ enableBasicAutocompletion: false, enableLiveAutocompletion: false, enableSnippets: false, showLineNumbers: true, tabSize: 4, }} /> </Box> </GridItem> <GridItem col={11}> <Box padding={2}> <Link href="https://docs.bigbluebutton.org/dev/api.html" isExternal> <Typography variant="epsilon" textColor="primary600"> You may refer to the API doc for more information </Typography> </Link> </Box> </GridItem> </Grid> </Box> </TabPanel> <TabPanel> <Box color="neutral800" paddingTop={2} background="neutral0"> <ApiCreateEndPoint /> </Box> </TabPanel> </TabPanels> </TabGroup> </ModalBody> <ModalFooter startActions={ <Button onClick={() => { setIsForm(true); handleClose(); }} variant="tertiary" > Cancel </Button> } endActions={ isForm ? ( <Button onClick={() => { handleCreateClass(classCreateData); }} data-testid="create-class" > Create </Button> ) : ( <Button onClick={() => { setIsForm(true); handleClose(); }} data-testid="create-class" > Close </Button> ) } /> </ModalLayout> )} </div> ); }; Modal.propTypes = { isVisible: PropTypes.bool.isRequired, handleClose: PropTypes.func.isRequired, }; export default Modal;