diff --git a/app/.eslintrc.js b/app/.eslintrc.cjs similarity index 97% rename from app/.eslintrc.js rename to app/.eslintrc.cjs index d24d9bf35..3739657e5 100644 --- a/app/.eslintrc.js +++ b/app/.eslintrc.cjs @@ -10,7 +10,8 @@ module.exports = [ 'import', 'react', - 'jsx-control-statements' + 'jsx-control-statements', + "react-hooks" ], extends: [ @@ -171,6 +172,8 @@ module.exports = 'prefer-spread': 2, 'prefer-template': 2, 'quotes': [ 2, 'single', { avoidEscape: true } ], + "react-hooks/rules-of-hooks": "error", + "react-hooks/exhaustive-deps": "warn", 'semi': [ 2, 'always' ], 'semi-spacing': 2, 'space-before-blocks': 2, diff --git a/app/gulpfile.js b/app/gulpfile.js index 52bf94075..717ac686e 100644 --- a/app/gulpfile.js +++ b/app/gulpfile.js @@ -31,34 +31,36 @@ * Alias for `gulp dist`. */ -const fs = require('fs'); -const path = require('path'); -const gulp = require('gulp'); -const gulpif = require('gulp-if'); -const gutil = require('gulp-util'); -const plumber = require('gulp-plumber'); -const rename = require('gulp-rename'); -const header = require('gulp-header'); -const touch = require('gulp-touch-cmd'); -const browserify = require('browserify'); -const watchify = require('watchify'); -const envify = require('envify/custom'); -const uglify = require('gulp-uglify-es').default; -const source = require('vinyl-source-stream'); -const buffer = require('vinyl-buffer'); -const del = require('del'); -const mkdirp = require('mkdirp'); -const ncp = require('ncp'); -const eslint = require('gulp-eslint'); -const stylus = require('gulp-stylus'); -const cssBase64 = require('gulp-css-base64'); -const nib = require('nib'); -const browserSync = require('browser-sync'); - -const PKG = require('./package.json'); +import * as fs from 'fs'; +import * as path from 'path'; +import { default as gulp } from 'gulp'; +import { default as gulpif } from 'gulp-if'; +import { default as gutil } from 'gulp-util'; +import { default as plumber } from 'gulp-plumber'; +import { default as rename } from 'gulp-rename'; +import { default as header } from 'gulp-header'; +import { default as touch } from 'gulp-touch-cmd'; +import { default as browserify } from 'browserify'; +import { default as watchify } from 'watchify'; +// eslint-disable-next-line import/extensions +import { default as envify } from 'envify/custom.js'; +import { default as uglify } from 'gulp-uglify-es'; +import { default as source } from 'vinyl-source-stream'; +import { default as buffer } from 'vinyl-buffer'; +import { deleteAsync } from 'del'; +import * as mkdirp from 'mkdirp'; +import { default as ncp } from 'ncp'; +import { default as eslint } from 'gulp-eslint'; +import { default as stylus } from 'gulp-stylus'; +import { default as cssBase64 } from 'gulp-css-base64'; +import { default as nib } from 'nib'; +import { default as browserSync } from 'browser-sync'; +// eslint-disable-next-line import/extensions +import config from '../server/config.js'; + +const PKG = JSON.parse(fs.readFileSync('package.json').toString()); const BANNER = fs.readFileSync('banner.txt').toString(); -const BANNER_OPTIONS = -{ +const BANNER_OPTIONS = { pkg : PKG, currentYear : (new Date()).getFullYear() }; @@ -69,42 +71,40 @@ process.env.NODE_ENV = process.env.NODE_ENV || 'development'; gutil.log(`NODE_ENV: ${process.env.NODE_ENV}`); -function logError(error) +function logError(error) { gutil.log(gutil.colors.red(error.stack)); } -function bundle(options) +function bundle(options) { options = options || {}; const watch = Boolean(options.watch); - let bundler = browserify( - { - entries : PKG.main, - extensions : [ '.js', '.jsx' ], - // required for sourcemaps (must be false otherwise). - debug : process.env.NODE_ENV === 'development', - // required for watchify. - cache : {}, - // required for watchify. - packageCache : {}, - // required to be true only for watchify. - fullPaths : watch - }) + let bundler = browserify({ + entries : PKG.main, + extensions : [ '.js', '.jsx' ], + // required for sourcemaps (must be false otherwise). + debug : process.env.NODE_ENV === 'development', + // required for watchify. + cache : {}, + // required for watchify. + packageCache : {}, + // required to be true only for watchify. + fullPaths : watch + }) .transform('babelify') - .transform(envify( - { - NODE_ENV : process.env.NODE_ENV, - _ : 'purge' - })); + .transform(envify({ + NODE_ENV : process.env.NODE_ENV, + _ : 'purge' + })); - if (watch) + if (watch) { bundler = watchify(bundler); - bundler.on('update', () => + bundler.on('update', () => { const start = Date.now(); @@ -114,7 +114,7 @@ function bundle(options) }); } - function rebundle() + function rebundle() { return bundler.bundle() .on('error', logError) @@ -123,7 +123,7 @@ function bundle(options) .pipe(buffer()) .pipe(rename(`${PKG.name}.js`)) .pipe(gulpif(process.env.NODE_ENV === 'production', - uglify() + uglify.default() )) .pipe(header(BANNER, BANNER_OPTIONS)) .pipe(gulp.dest(OUTPUT_DIR)); @@ -132,12 +132,11 @@ function bundle(options) return rebundle(); } -gulp.task('clean', () => del(OUTPUT_DIR, { force: true })); +gulp.task('clean', () => deleteAsync(OUTPUT_DIR, { force: true })); -gulp.task('lint', () => +gulp.task('lint', () => { - const src = - [ + const src = [ 'gulpfile.js', 'lib/**/*.js', 'lib/**/*.jsx' @@ -149,38 +148,37 @@ gulp.task('lint', () => .pipe(eslint.format()); }); -gulp.task('css', () => +gulp.task('css', () => { return gulp.src('stylus/index.styl') .pipe(plumber()) - .pipe(stylus( - { - use : nib(), - compress : process.env.NODE_ENV === 'production' - })) + .pipe(stylus({ + use : nib(), + compress : process.env.NODE_ENV === 'production' + })) .on('error', logError) - .pipe(cssBase64( - { - baseDir : '.', - maxWeightResource : 50000 // So big ttf fonts are not included, nice. - })) + .pipe(cssBase64({ + baseDir : '.', + maxWeightResource : 50000 // So big ttf fonts are not included, nice. + })) .pipe(rename(`${PKG.name}.css`)) .pipe(gulp.dest(OUTPUT_DIR)) .pipe(touch()); }); -gulp.task('html', () => +gulp.task('html', () => { return gulp.src('index.html') .pipe(gulp.dest(OUTPUT_DIR)); }); -gulp.task('resources', (done) => +gulp.task('resources', (done) => { const dst = path.join(OUTPUT_DIR, 'resources'); mkdirp.sync(dst); - ncp('resources', dst, { stopOnErr: true }, (error) => + + ncp('resources', dst, { stopOnErr: true }, (error) => { if (error && error[0].code !== 'ENOENT') throw new Error(`resources copy failed: ${error}`); @@ -189,12 +187,12 @@ gulp.task('resources', (done) => }); }); -gulp.task('bundle', () => +gulp.task('bundle', () => { return bundle({ watch: false }); }); -gulp.task('bundle:watch', () => +gulp.task('bundle:watch', () => { return bundle({ watch: true }); }); @@ -208,7 +206,7 @@ gulp.task('dist', gulp.series( 'resources' )); -gulp.task('watch', (done) => +gulp.task('watch', (done) => { // Watch changes in HTML. gulp.watch([ 'index.html' ], gulp.series( @@ -245,23 +243,19 @@ gulp.task('browser:base', gulp.series( gulp.task('live', gulp.series( 'browser:base', - (done) => + (done) => { - const config = require('../server/config'); - - browserSync( - { - open : 'external', - host : config.domain, - startPath : '/?info=true', - server : - { - baseDir : OUTPUT_DIR - }, - https : config.https.tls, - ghostMode : false, - files : path.join(OUTPUT_DIR, '**', '*') - }); + browserSync({ + open : 'external', + host : config.domain, + startPath : '/?info=true', + server : { + baseDir : OUTPUT_DIR + }, + https : config.https.tls, + ghostMode : false, + files : path.join(OUTPUT_DIR, '**', '*') + }); done(); } @@ -269,44 +263,38 @@ gulp.task('live', gulp.series( gulp.task('devel', gulp.series( 'browser:base', - async (done) => + async (done) => { - const config = require('../server/config'); - - await new Promise((resolve) => + await new Promise((resolve) => { - browserSync.create('producer1').init( - { - open : 'external', - host : config.domain, - startPath : '/?roomId=devel&info=true&_throttleSecret=foo&consume=false', - server : - { - baseDir : OUTPUT_DIR - }, - https : config.https.tls, - ghostMode : false, - files : path.join(OUTPUT_DIR, '**', '*') + browserSync.create('producer1').init({ + open : 'external', + host : config.domain, + startPath : '/?roomId=devel&info=true&_throttleSecret=foo&consume=false', + server : { + baseDir : OUTPUT_DIR }, - resolve); + https : config.https.tls, + ghostMode : false, + files : path.join(OUTPUT_DIR, '**', '*') + }, + resolve); }); - await new Promise((resolve) => + await new Promise((resolve) => { - browserSync.create('consumer1').init( - { - open : 'external', - host : config.domain, - startPath : '/?roomId=devel&info=true&_throttleSecret=foo&produce=false', - server : - { - baseDir : OUTPUT_DIR - }, - https : config.https.tls, - ghostMode : false, - files : path.join(OUTPUT_DIR, '**', '*') + browserSync.create('consumer1').init({ + open : 'external', + host : config.domain, + startPath : '/?roomId=devel&info=true&_throttleSecret=foo&produce=false', + server : { + baseDir : OUTPUT_DIR }, - resolve); + https : config.https.tls, + ghostMode : false, + files : path.join(OUTPUT_DIR, '**', '*') + }, + resolve); }); done(); @@ -315,44 +303,38 @@ gulp.task('devel', gulp.series( gulp.task('devel:tcp', gulp.series( 'browser:base', - async (done) => + async (done) => { - const config = require('../server/config'); - - await new Promise((resolve) => + await new Promise((resolve) => { - browserSync.create('producer1').init( - { - open : 'external', - host : config.domain, - startPath : '/?roomId=devel:tcp&info=true&_throttleSecret=foo&forceTcp=true&consume=false', - server : - { - baseDir : OUTPUT_DIR - }, - https : config.https.tls, - ghostMode : false, - files : path.join(OUTPUT_DIR, '**', '*') + browserSync.create('producer1').init({ + open : 'external', + host : config.domain, + startPath : '/?roomId=devel:tcp&info=true&_throttleSecret=foo&forceTcp=true&consume=false', + server : { + baseDir : OUTPUT_DIR }, - resolve); + https : config.https.tls, + ghostMode : false, + files : path.join(OUTPUT_DIR, '**', '*') + }, + resolve); }); - await new Promise((resolve) => + await new Promise((resolve) => { - browserSync.create('consumer1').init( - { - open : 'external', - host : config.domain, - startPath : '/?roomId=devel:tcp&info=true&_throttleSecret=foo&forceTcp=true&produce=false', - server : - { - baseDir : OUTPUT_DIR - }, - https : config.https.tls, - ghostMode : false, - files : path.join(OUTPUT_DIR, '**', '*') + browserSync.create('consumer1').init({ + open : 'external', + host : config.domain, + startPath : '/?roomId=devel:tcp&info=true&_throttleSecret=foo&forceTcp=true&produce=false', + server : { + baseDir : OUTPUT_DIR }, - resolve); + https : config.https.tls, + ghostMode : false, + files : path.join(OUTPUT_DIR, '**', '*') + }, + resolve); }); done(); @@ -361,44 +343,38 @@ gulp.task('devel:tcp', gulp.series( gulp.task('devel:vp9', gulp.series( 'browser:base', - async (done) => + async (done) => { - const config = require('../server/config'); - - await new Promise((resolve) => + await new Promise((resolve) => { - browserSync.create('producer1').init( - { - open : 'external', - host : config.domain, - startPath : '/?roomId=devel:vp9&info=true&_throttleSecret=foo&forceVP9=true&svc=L3T3&consume=false', - server : - { - baseDir : OUTPUT_DIR - }, - https : config.https.tls, - ghostMode : false, - files : path.join(OUTPUT_DIR, '**', '*') + browserSync.create('producer1').init({ + open : 'external', + host : config.domain, + startPath : '/?roomId=devel:vp9&info=true&_throttleSecret=foo&forceVP9=true&svc=L3T3&consume=false', + server : { + baseDir : OUTPUT_DIR }, - resolve); + https : config.https.tls, + ghostMode : false, + files : path.join(OUTPUT_DIR, '**', '*') + }, + resolve); }); - await new Promise((resolve) => + await new Promise((resolve) => { - browserSync.create('consumer1').init( - { - open : 'external', - host : config.domain, - startPath : '/?roomId=devel:vp9&info=true&_throttleSecret=foo&forceVP9=true&svc=L3T3&produce=false', - server : - { - baseDir : OUTPUT_DIR - }, - https : config.https.tls, - ghostMode : false, - files : path.join(OUTPUT_DIR, '**', '*') + browserSync.create('consumer1').init({ + open : 'external', + host : config.domain, + startPath : '/?roomId=devel:vp9&info=true&_throttleSecret=foo&forceVP9=true&svc=L3T3&produce=false', + server : { + baseDir : OUTPUT_DIR }, - resolve); + https : config.https.tls, + ghostMode : false, + files : path.join(OUTPUT_DIR, '**', '*') + }, + resolve); }); done(); @@ -407,44 +383,38 @@ gulp.task('devel:vp9', gulp.series( gulp.task('devel:h264', gulp.series( 'browser:base', - async (done) => + async (done) => { - const config = require('../server/config'); - - await new Promise((resolve) => + await new Promise((resolve) => { - browserSync.create('producer1').init( - { - open : 'external', - host : config.domain, - startPath : '/?roomId=devel:h264&info=true&_throttleSecret=foo&forceH264=true&consume=false', - server : - { - baseDir : OUTPUT_DIR - }, - https : config.https.tls, - ghostMode : false, - files : path.join(OUTPUT_DIR, '**', '*') + browserSync.create('producer1').init({ + open : 'external', + host : config.domain, + startPath : '/?roomId=devel:h264&info=true&_throttleSecret=foo&forceH264=true&consume=false', + server : { + baseDir : OUTPUT_DIR }, - resolve); + https : config.https.tls, + ghostMode : false, + files : path.join(OUTPUT_DIR, '**', '*') + }, + resolve); }); - await new Promise((resolve) => + await new Promise((resolve) => { - browserSync.create('consumer1').init( - { - open : 'external', - host : config.domain, - startPath : '/?roomId=devel:h264&info=true&_throttleSecret=foo&forceH264=true&produce=false', - server : - { - baseDir : OUTPUT_DIR - }, - https : config.https.tls, - ghostMode : false, - files : path.join(OUTPUT_DIR, '**', '*') + browserSync.create('consumer1').init({ + open : 'external', + host : config.domain, + startPath : '/?roomId=devel:h264&info=true&_throttleSecret=foo&forceH264=true&produce=false', + server : { + baseDir : OUTPUT_DIR }, - resolve); + https : config.https.tls, + ghostMode : false, + files : path.join(OUTPUT_DIR, '**', '*') + }, + resolve); }); done(); diff --git a/app/lib/RoomClient.js b/app/lib/RoomClient.js index b1ea9330d..9db62b6c3 100644 --- a/app/lib/RoomClient.js +++ b/app/lib/RoomClient.js @@ -1,13 +1,13 @@ +import * as cookiesManager from './cookiesManager'; import protooClient from 'protoo-client'; import * as mediasoupClient from 'mediasoup-client'; import Logger from './Logger'; import { getProtooUrl } from './urlFactory'; -import * as cookiesManager from './cookiesManager'; import * as requestActions from './redux/requestActions'; import * as stateActions from './redux/stateActions'; import * as e2e from './e2e'; -const VIDEO_CONSTRAINS = +const VIDEO_CONSTRAINTS = { qvga : { width: { ideal: 320 }, height: { ideal: 240 } }, vga : { width: { ideal: 640 }, height: { ideal: 480 } }, @@ -28,12 +28,12 @@ let store; export default class RoomClient { /** - * @param {Object} data - * @param {Object} data.store - The Redux store. + * @param {Object} data - The Redux store.\ + * */ - static init(data) + static async init(data) { - store = data.store; + store = data; } constructor( @@ -247,7 +247,8 @@ export default class RoomClient this._recvTransport.close(); store.dispatch( - stateActions.setRoomState('closed')); + stateActions.setRoomState('closed') + ); } async join() @@ -990,7 +991,7 @@ export default class RoomClient video : { deviceId : { ideal: device.deviceId }, - ...VIDEO_CONSTRAINS[resolution] + ...VIDEO_CONSTRAINTS[resolution] } }); @@ -1234,7 +1235,7 @@ export default class RoomClient video : { deviceId : { exact: this._webcam.device.deviceId }, - ...VIDEO_CONSTRAINS[this._webcam.resolution] + ...VIDEO_CONSTRAINTS[this._webcam.resolution] } }); @@ -1291,7 +1292,7 @@ export default class RoomClient video : { deviceId : { exact: this._webcam.device.deviceId }, - ...VIDEO_CONSTRAINS[this._webcam.resolution] + ...VIDEO_CONSTRAINTS[this._webcam.resolution] } }); diff --git a/app/lib/RoomContext.js b/app/lib/RoomContext.js index d4b79adae..dd6eac3e9 100644 --- a/app/lib/RoomContext.js +++ b/app/lib/RoomContext.js @@ -1,14 +1,45 @@ -import React from 'react'; +import React, { + createContext, + useContext, + useState +} from 'react'; +import RoomClientContextComponent from './components/RoomClientContextComponent'; +import Logger from './Logger'; +const logger = new Logger(); -const RoomContext = React.createContext(); +export const RoomClientContext = createContext(null); -export default RoomContext; +export const RoomClientUpdateContext = createContext(null); -export function withRoomContext(Component) +export function UseRoomClient() { - return (props) => ( // eslint-disable-line react/display-name - - {(roomClient) => } - + return useContext(RoomClientContext); +} + +export function UseRoomClientUpdate() +{ + return useContext(RoomClientUpdateContext); +} + +export function RoomClientProvider({ children }) +{ + logger.debug('children: ', children); + + const [ roomClient, setRoomClient ] = useState(UseRoomClient()); + + function setRoomClientInstance(data) + { + logger.debug('RoomContext.setRoomClientInstance(data): ', data); + setRoomClient(data); + } + + return ( + + + + {children} + + + ); } diff --git a/app/lib/components/ChatInput.jsx b/app/lib/components/ChatInput.jsx index 626d6e458..8a847f3ce 100644 --- a/app/lib/components/ChatInput.jsx +++ b/app/lib/components/ChatInput.jsx @@ -1,7 +1,7 @@ import React from 'react'; import { connect } from 'react-redux'; import PropTypes from 'prop-types'; -import { withRoomContext } from '../RoomContext'; +// import withRoomContext from '../RoomContext'; const BotMessageRegex = new RegExp('^@bot (.*)'); @@ -115,9 +115,8 @@ const mapStateToProps = (state) => }; }; -const ChatInputContainer = withRoomContext(connect( - mapStateToProps, - undefined -)(ChatInput)); +const ChatInputContainer = connect( + mapStateToProps +)(ChatInput); -export default ChatInputContainer; +// export default ChatInputContainer; diff --git a/app/lib/components/EditableInput.jsx b/app/lib/components/EditableInput.jsx index addf1f40c..71194a296 100644 --- a/app/lib/components/EditableInput.jsx +++ b/app/lib/components/EditableInput.jsx @@ -1,51 +1,51 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { RIEInput } from 'riek'; - -export default class EditableInput extends React.Component -{ - render() - { - const { - value, - propName, - className, - classLoading, - classInvalid, - editProps, - onChange - } = this.props; - - return ( - onChange(data)} - /> - ); - } - - shouldComponentUpdate(nextProps) - { - if (nextProps.value === this.props.value) - return false; - - return true; - } -} - -EditableInput.propTypes = -{ - value : PropTypes.string, - propName : PropTypes.string.isRequired, - className : PropTypes.string, - classLoading : PropTypes.string, - classInvalid : PropTypes.string, - editProps : PropTypes.any, - onChange : PropTypes.func.isRequired -}; +// import React from 'react'; +// import PropTypes from 'prop-types'; +// import { RIEInput } from 'riek'; +// +// export default class EditableInput extends React.Component +// { +// render() +// { +// const { +// value, +// propName, +// className, +// classLoading, +// classInvalid, +// editProps, +// onChange +// } = this.props; +// +// return ( +// onChange(data)} +// /> +// ); +// } +// +// shouldComponentUpdate(nextProps) +// { +// if (nextProps.value === this.props.value) +// return false; +// +// return true; +// } +// } +// +// EditableInput.propTypes = +// { +// value : PropTypes.string, +// propName : PropTypes.string.isRequired, +// className : PropTypes.string, +// classLoading : PropTypes.string, +// classInvalid : PropTypes.string, +// editProps : PropTypes.any, +// onChange : PropTypes.func.isRequired +// }; diff --git a/app/lib/components/Me.jsx b/app/lib/components/Me.jsx index 689513f98..d31796418 100644 --- a/app/lib/components/Me.jsx +++ b/app/lib/components/Me.jsx @@ -1,197 +1,206 @@ -import React from 'react'; +import React, { + componentDidMount, + componentDidUpdate, + componentWillUnmount +} from 'react'; import { connect } from 'react-redux'; import PropTypes from 'prop-types'; -import ReactTooltip from 'react-tooltip'; +import Tooltip from 'react-tooltip'; import classnames from 'classnames'; import * as cookiesManager from '../cookiesManager'; import * as appPropTypes from './appPropTypes'; -import { withRoomContext } from '../RoomContext'; +// import withRoomContext from '../RoomContext'; import * as stateActions from '../redux/stateActions'; import PeerView from './PeerView'; -class Me extends React.Component +function Me(props) { - constructor(props) - { - super(props); - - this._mounted = false; - this._rootNode = null; - } - - render() - { - const { - roomClient, - connected, - me, - audioProducer, - videoProducer, - faceDetection, - onSetStatsPeerId - } = this.props; - - let micState; - - if (!me.canSendMic) - micState = 'unsupported'; - else if (!audioProducer) - micState = 'unsupported'; - else if (!audioProducer.paused) - micState = 'on'; - else - micState = 'off'; - - let webcamState; - - if (!me.canSendWebcam) - webcamState = 'unsupported'; - else if (videoProducer && videoProducer.type !== 'share') - webcamState = 'on'; - else - webcamState = 'off'; - - let changeWebcamState; - - if (Boolean(videoProducer) && videoProducer.type !== 'share' && me.canChangeWebcam) - changeWebcamState = 'on'; - else - changeWebcamState = 'unsupported'; - - let shareState; - - if (Boolean(videoProducer) && videoProducer.type === 'share') - shareState = 'on'; - else - shareState = 'off'; - - const videoVisible = Boolean(videoProducer) && !videoProducer.paused; - - let tip; - - if (!me.displayNameSet) - tip = 'Click on your name to change it'; - - return ( -
(this._rootNode = node)} - data-tip={tip} - data-tip-disable={!tip} - > - -
-
- { - micState === 'on' - ? roomClient.muteMic() - : roomClient.unmuteMic(); - }} - /> - -
- { - if (webcamState === 'on') - { - cookiesManager.setDevices({ webcamEnabled: false }); - roomClient.disableWebcam(); - } - else - { - cookiesManager.setDevices({ webcamEnabled: true }); - roomClient.enableWebcam(); - } - }} - /> - -
roomClient.changeWebcam()} - /> - -
- { - if (shareState === 'on') - roomClient.disableShare(); - else - roomClient.enableShare(); - }} - /> -
- - - - { - roomClient.changeDisplayName(displayName); - }} - onChangeMaxSendingSpatialLayer={(spatialLayer) => - { - roomClient.setMaxSendingSpatialLayer(spatialLayer); - }} - onStatsClick={onSetStatsPeerId} - /> - - -
- ); - } + let mounted = false; + const rootNode = null; - componentDidMount() + componentDidMount(); { - this._mounted = true; - + mounted = true; + setTimeout(() => { - if (!this._mounted || this.props.me.displayNameSet) + if (!mounted || props.me.displayNameSet) + { return; - - ReactTooltip.show(this._rootNode); + } + + Tooltip.show(rootNode); }, 4000); } - - componentWillUnmount() + + componentWillUnmount(); { - this._mounted = false; + mounted = false; } - componentDidUpdate(prevProps) + componentDidUpdate(prevProps); { - if (!prevProps.me.displayNameSet && this.props.me.displayNameSet) - ReactTooltip.hide(this._rootNode); + if (!prevProps.me.displayNameSet && props.me.displayNameSet) + { + Tooltip.hide(rootNode); + } } + + // constructor(props) + // { + // super(props); + // + // this._mounted = false; + // this._rootNode = null; + // } + + const { + roomClient, + connected, + me, + audioProducer, + videoProducer, + faceDetection, + onSetStatsPeerId + } = props; + + let micState; + + if (!me.canSendMic) + micState = 'unsupported'; + else if (!audioProducer) + micState = 'unsupported'; + else if (!audioProducer.paused) + micState = 'on'; + else + micState = 'off'; + + let webcamState; + + if (!me.canSendWebcam) + webcamState = 'unsupported'; + else if (videoProducer && videoProducer.type !== 'share') + webcamState = 'on'; + else + webcamState = 'off'; + + let changeWebcamState; + + if (Boolean(videoProducer) && videoProducer.type !== 'share' && me.canChangeWebcam) + changeWebcamState = 'on'; + else + changeWebcamState = 'unsupported'; + + let shareState; + + if (Boolean(videoProducer) && videoProducer.type === 'share') + shareState = 'on'; + else + shareState = 'off'; + + const videoVisible = Boolean(videoProducer) && !videoProducer.paused; + + let tip; + + if (!me.displayNameSet) + tip = 'Click on your name to change it'; + + return ( +
(this._rootNode = node)} + data-tip={tip} + data-tip-disable={!tip} + > + +
+
+ { + micState === 'on' + ? roomClient.muteMic() + : roomClient.unmuteMic(); + }} + /> + +
+ { + if (webcamState === 'on') + { + cookiesManager.setDevices({ webcamEnabled: false }); + roomClient.disableWebcam(); + } + else + { + cookiesManager.setDevices({ webcamEnabled: true }); + roomClient.enableWebcam(); + } + }} + /> + +
roomClient.changeWebcam()} + /> + +
+ { + if (shareState === 'on') + roomClient.disableShare(); + else + roomClient.enableShare(); + }} + /> +
+ + + + { + roomClient.changeDisplayName(displayName); + }} + onChangeMaxSendingSpatialLayer={(spatialLayer) => + { + roomClient.setMaxSendingSpatialLayer(spatialLayer); + }} + onStatsClick={onSetStatsPeerId} + /> + + +
+ ); + } Me.propTypes = @@ -229,9 +238,9 @@ const mapDispatchToProps = (dispatch) => }; }; -const MeContainer = withRoomContext(connect( +const MeContainer = connect( mapStateToProps, mapDispatchToProps -)(Me)); +)(Me); export default MeContainer; diff --git a/app/lib/components/NetworkThrottle.jsx b/app/lib/components/NetworkThrottle.jsx index 846182708..e4f11eb9b 100644 --- a/app/lib/components/NetworkThrottle.jsx +++ b/app/lib/components/NetworkThrottle.jsx @@ -1,194 +1,182 @@ -import React from 'react'; +import React, { componentWillUnmount, useState } from 'react'; import Draggable from 'react-draggable'; import PropTypes from 'prop-types'; -import { withRoomContext } from '../RoomContext'; +import { useRoomClient } from '../RoomContext'; -class NetworkThrottle extends React.Component +export default function NetworkThrottle(secret) { - constructor(props) + const [ uplink, setUplink ] = useState(''); + const [ downlink, setDownlink ] = useState(''); + const [ rtt, setRtt ] = useState(''); + const [ packetLoss, setPacketLoss ] = useState(''); + const [ disabled, setDisabled ] = useState(false); + + const roomClient = useRoomClient(); + + async function _apply() { - super(props); - - this.state = + setUplink( + Number(uplink) === uplink ? uplink : 0 + ); + setUplink( + Number(downlink) === downlink ? downlink : 0 + ); + setUplink( + Number(rtt) === rtt ? rtt : 0 + ); + setUplink( + Number(packetLoss) === packetLoss ? packetLoss : 0 + ); + + setDisabled(true); + + await roomClient.applyNetworkThrottle( + { secret, uplink, downlink, rtt, packetLoss } + ); + + window.onunload = () => { - uplink : '', - downlink : '', - rtt : '', - packetLoss : '', - disabled : false + roomClient.resetNetworkThrottle({ silent: true, secret }); }; + + setDisabled(false); } - render() + async function _reset() { - const { uplink, downlink, rtt, packetLoss, disabled } = this.state; - - return ( - -
- { - event.preventDefault(); - - this._apply(); - }} - > -

Network Throttle

- -
-
-

- UPLINK (kbps) -

- - this.setState({ uplink: event.target.value })} - /> -
- -
-

- DOWNLINK (kbps) -

- - this.setState({ downlink: event.target.value })} - /> -
- -
-

- RTT (ms) -

- - this.setState({ rtt: event.target.value })} - /> -
- -
-

- PACKETLOSS (%) -

- - this.setState({ packetLoss: event.target.value })} - /> -
-
- -
- - - -
-
-
- ); + setUplink(''); + setDownlink(''); + setRtt(''); + setPacketLoss(''); + setDisabled(true); + + await roomClient.resetNetworkThrottle({ secret }); + + setDisabled(false); } - - componentWillUnmount() + + componentWillUnmount(() => { - const { roomClient } = this.props; - roomClient.resetNetworkThrottle({ silent: true }); } + ); + + return ( + +
+ { + event.preventDefault(); + + _apply(); + }} + > +

Network Throttle

+ +
+
+

+ UPLINK (kbps) +

+ + setUplink(event.target.value)} + /> +
- async _apply() - { - const { roomClient, secret } = this.props; - let { uplink, downlink, rtt, packetLoss } = this.state; - - uplink = Number(uplink) || 0; - downlink = Number(downlink) || 0; - rtt = Number(rtt) || 0; - packetLoss = Number(packetLoss) || 0; - - this.setState({ disabled: true }); - - await roomClient.applyNetworkThrottle( - { secret, uplink, downlink, rtt, packetLoss }); +
+

+ DOWNLINK (kbps) +

- window.onunload = () => - { - roomClient.resetNetworkThrottle({ silent: true, secret }); - }; - - this.setState({ disabled: false }); - } + setDownlink(event.target.value)} + /> +
- async _reset() - { - const { roomClient, secret } = this.props; +
+

+ RTT (ms) +

- this.setState( - { - uplink : '', - downlink : '', - rtt : '', - packetLoss : '', - disabled : false - }); + setRtt(event.target.value)} + /> +
- this.setState({ disabled: true }); +
+

+ PACKETLOSS (%) +

- await roomClient.resetNetworkThrottle({ secret }); + setPacketLoss(event.target.value)} + /> +
+
+ +
+ + + +
+
+
+ ); - this.setState({ disabled: false }); - } } NetworkThrottle.propTypes = @@ -196,5 +184,3 @@ NetworkThrottle.propTypes = roomClient : PropTypes.any.isRequired, secret : PropTypes.string.isRequired }; - -export default withRoomContext(NetworkThrottle); diff --git a/app/lib/components/Peer.jsx b/app/lib/components/Peer.jsx index abe6324f2..55433e89e 100644 --- a/app/lib/components/Peer.jsx +++ b/app/lib/components/Peer.jsx @@ -2,7 +2,7 @@ import React from 'react'; import { connect } from 'react-redux'; import PropTypes from 'prop-types'; import * as appPropTypes from './appPropTypes'; -import { withRoomContext } from '../RoomContext'; +// import withRoomContext from '../RoomContext'; import * as stateActions from '../redux/stateActions'; import PeerView from './PeerView'; @@ -130,9 +130,9 @@ const mapDispatchToProps = (dispatch) => }; }; -const PeerContainer = withRoomContext(connect( +const PeerContainer = connect( mapStateToProps, mapDispatchToProps -)(Peer)); +)(Peer); export default PeerContainer; diff --git a/app/lib/components/PeerView.jsx b/app/lib/components/PeerView.jsx index f5b6401f4..6c3bce7ca 100644 --- a/app/lib/components/PeerView.jsx +++ b/app/lib/components/PeerView.jsx @@ -452,7 +452,6 @@ export default class PeerView extends React.Component