Add initial welcome page
This commit is contained in:
parent
6f35ddd792
commit
4773b12a3b
|
@ -1,6 +1,7 @@
|
||||||
[ignore]
|
[ignore]
|
||||||
.*/node_modules/.*
|
.*/node_modules/@atlaskit/.*/*.js.flow
|
||||||
.*/build/.*
|
.*/build/.*
|
||||||
|
.*/node_modules/electron-packager/test/fixtures/infer-malformed-json/.*
|
||||||
|
|
||||||
[include]
|
[include]
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
|
import { AtlasKitThemeProvider } from '@atlaskit/theme';
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import { HashRouter as Router, Route, Switch } from 'react-router-dom';
|
||||||
|
|
||||||
import { Conference } from '../../conference';
|
import { Conference } from '../../conference';
|
||||||
import config from '../../config';
|
import config from '../../config';
|
||||||
|
import { Welcome } from '../../welcome';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main component encapsulating the entire application.
|
* Main component encapsulating the entire application.
|
||||||
|
@ -28,7 +32,19 @@ export default class App extends Component<*> {
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Conference />
|
<AtlasKitThemeProvider mode = 'dark'>
|
||||||
|
<Router>
|
||||||
|
<Switch>
|
||||||
|
<Route
|
||||||
|
exact
|
||||||
|
component = { Welcome }
|
||||||
|
path = '/' />
|
||||||
|
<Route
|
||||||
|
component = { Conference }
|
||||||
|
path = '/:domain?/:room' />
|
||||||
|
</Switch>
|
||||||
|
</Router>
|
||||||
|
</AtlasKitThemeProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,59 +1,120 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
RemoteControl,
|
RemoteControl,
|
||||||
setupScreenSharingForWindow,
|
setupScreenSharingForWindow,
|
||||||
setupAlwaysOnTopRender,
|
setupAlwaysOnTopRender,
|
||||||
setupWiFiStats
|
setupWiFiStats
|
||||||
|
|
||||||
// $FlowFixMe
|
|
||||||
} from 'jitsi-meet-electron-utils';
|
} from 'jitsi-meet-electron-utils';
|
||||||
|
|
||||||
import config from '../../config';
|
import config from '../../config';
|
||||||
|
|
||||||
|
import { Wrapper } from '../styled';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* React Router history object.
|
||||||
|
* This contains implementations for managing session history.
|
||||||
|
*/
|
||||||
|
history: Object;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* React Router match object.
|
||||||
|
* This contains parameters passed through <Route /> component.
|
||||||
|
*/
|
||||||
|
match: Object;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Conference component.
|
* Conference component.
|
||||||
*/
|
*/
|
||||||
export default class Conference extends Component<*> {
|
export default class Conference extends Component<Props, *> {
|
||||||
/**
|
/**
|
||||||
* Attach the script
|
* Reference to the element of this component.
|
||||||
|
*/
|
||||||
|
_ref: Object;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* External API object.
|
||||||
|
*/
|
||||||
|
_api: Object;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a new {@code Conference} instance.
|
||||||
|
*
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._ref = React.createRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attach the script to this component.
|
||||||
*/
|
*/
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
const parentNode = this._ref.current;
|
||||||
|
const room = this.props.match.params.room;
|
||||||
|
const domain = this.props.match.params.domain || config.defaultDomain;
|
||||||
|
|
||||||
const script = document.createElement('script');
|
const script = document.createElement('script');
|
||||||
|
|
||||||
script.async = true;
|
script.async = true;
|
||||||
script.onload = this._onScriptLoad;
|
script.onload = () => this._onScriptLoad(parentNode, room, domain);
|
||||||
script.onerror = console.error;
|
script.onerror = () => this._navigateToHome();
|
||||||
script.src = `https://${config.defaultDomain}/external_api.js`;
|
script.src = `https://${domain}/external_api.js`;
|
||||||
|
|
||||||
// $FlowFixMe
|
this._ref.current.appendChild(script);
|
||||||
document.head.appendChild(script);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove conference on unmounting.
|
||||||
|
*/
|
||||||
|
componentWillUnmount() {
|
||||||
|
if (this._api) {
|
||||||
|
this._api.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render function of component.
|
* Implements React's {@link Component#render()}.
|
||||||
*
|
*
|
||||||
* @return {ReactElement}
|
* @inheritdoc
|
||||||
|
* @returns {ReactElement}
|
||||||
*/
|
*/
|
||||||
render() {
|
render() {
|
||||||
return null;
|
return <Wrapper innerRef={this._ref} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When the script is loaded attach utils from jitsi-meet-electron-utils
|
* Navigates to home screen (Welcome).
|
||||||
*/
|
*/
|
||||||
_onScriptLoad() {
|
_navigateToHome() {
|
||||||
|
this.props.history.push('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the script is loaded create the iframe element in this component
|
||||||
|
* and attach utils from jitsi-meet-electron-utils.
|
||||||
|
*/
|
||||||
|
_onScriptLoad(parentNode: Object, roomName: string, domain: string) {
|
||||||
const JitsiMeetExternalAPI = window.JitsiMeetExternalAPI;
|
const JitsiMeetExternalAPI = window.JitsiMeetExternalAPI;
|
||||||
|
|
||||||
const api = new JitsiMeetExternalAPI(config.defaultDomain);
|
this._api = new JitsiMeetExternalAPI(domain, {
|
||||||
const iframe = api.getIFrame();
|
parentNode,
|
||||||
|
roomName
|
||||||
|
});
|
||||||
|
const iframe = this._api.getIFrame();
|
||||||
|
|
||||||
setupScreenSharingForWindow(iframe);
|
setupScreenSharingForWindow(iframe);
|
||||||
new RemoteControl(iframe); // eslint-disable-line no-new
|
new RemoteControl(iframe); // eslint-disable-line no-new
|
||||||
setupAlwaysOnTopRender(api);
|
setupAlwaysOnTopRender(this._api);
|
||||||
setupWiFiStats(iframe);
|
setupWiFiStats(iframe);
|
||||||
|
|
||||||
|
this._api.on('readyToClose', () => this._navigateToHome());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
export * from './components';
|
export * from './components';
|
||||||
|
export * from './styled';
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
export default styled.div`
|
||||||
|
height: 100vh;
|
||||||
|
`;
|
|
@ -0,0 +1 @@
|
||||||
|
export { default as Wrapper } from './Wrapper';
|
|
@ -0,0 +1,124 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import { AtlasKitThemeProvider } from '@atlaskit/theme';
|
||||||
|
import Button from '@atlaskit/button';
|
||||||
|
import { FieldTextStateless } from '@atlaskit/field-text';
|
||||||
|
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import URL from 'url';
|
||||||
|
|
||||||
|
import { WelcomeWrapper as Wrapper, Content, Form } from '../styled';
|
||||||
|
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* React Router history object.
|
||||||
|
* This contains implementations for managing session history.
|
||||||
|
*/
|
||||||
|
history: Object;
|
||||||
|
};
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL of the room to join.
|
||||||
|
* If this is not a url it will be treated as room name for default domain.
|
||||||
|
*/
|
||||||
|
url: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Welcome Component.
|
||||||
|
*/
|
||||||
|
export default class Welcome extends Component<Props, State> {
|
||||||
|
/**
|
||||||
|
* Initializes a new {@code Welcome} instance.
|
||||||
|
*
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
constructor(props: Props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
url: ''
|
||||||
|
};
|
||||||
|
|
||||||
|
// Bind event handlers.
|
||||||
|
this._onURLChange = this._onURLChange.bind(this);
|
||||||
|
this._onFormSubmit = this._onFormSubmit.bind(this);
|
||||||
|
this._onJoin = this._onJoin.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render function of component.
|
||||||
|
*
|
||||||
|
* @return {ReactElement}
|
||||||
|
*/
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<AtlasKitThemeProvider mode = 'light'>
|
||||||
|
<Wrapper>
|
||||||
|
<Content>
|
||||||
|
<Form onSubmit = { this._onFormSubmit }>
|
||||||
|
<FieldTextStateless
|
||||||
|
autoFocus = { true }
|
||||||
|
isLabelHidden = { true }
|
||||||
|
shouldFitContainer = { true }
|
||||||
|
onChange = { this._onURLChange }
|
||||||
|
type = 'text'
|
||||||
|
value = { this.state.url } />
|
||||||
|
</Form>
|
||||||
|
<Button
|
||||||
|
appearance = 'primary'
|
||||||
|
type = 'button'
|
||||||
|
onClick = { this._onJoin }>
|
||||||
|
GO
|
||||||
|
</Button>
|
||||||
|
</Content>
|
||||||
|
</Wrapper>
|
||||||
|
</AtlasKitThemeProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_onFormSubmit: (*) => void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevents submission of the form and delegates the join logic.
|
||||||
|
*/
|
||||||
|
_onFormSubmit(event: Event) {
|
||||||
|
event.preventDefault();
|
||||||
|
this._onJoin();
|
||||||
|
}
|
||||||
|
|
||||||
|
_onJoin: (*) => void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redirect and join conference.
|
||||||
|
*/
|
||||||
|
_onJoin() {
|
||||||
|
const url = URL.parse(this.state.url);
|
||||||
|
|
||||||
|
// Check if the parsed url is a full url or just room name.
|
||||||
|
if (url.host && url.path) {
|
||||||
|
|
||||||
|
// This will be triggered when the full url is present.
|
||||||
|
this.props.history.push(url.host + url.path);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Directly to the the path.
|
||||||
|
this.props.history.push(url.path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_onURLChange: (*) => void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keeps URL input value and URL in state in sync.
|
||||||
|
*/
|
||||||
|
_onURLChange(event: SyntheticInputEvent<HTMLInputElement>) {
|
||||||
|
this.setState({
|
||||||
|
url: event.currentTarget.value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
export { default as Welcome } from './Welcome';
|
|
@ -0,0 +1,2 @@
|
||||||
|
export * from './components';
|
||||||
|
export * from './styled';
|
|
@ -0,0 +1,10 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
export default styled.div`
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 30px;
|
||||||
|
`;
|
|
@ -0,0 +1,8 @@
|
||||||
|
// Flow
|
||||||
|
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
export default styled.form`
|
||||||
|
width: 350px;
|
||||||
|
margin: 0 15px;
|
||||||
|
`;
|
|
@ -0,0 +1,9 @@
|
||||||
|
// @flow
|
||||||
|
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
export default styled.div`
|
||||||
|
background: linear-gradient(#165ecc,#44A5FF);
|
||||||
|
display: flex;
|
||||||
|
height: 100vh;
|
||||||
|
`;
|
|
@ -0,0 +1,3 @@
|
||||||
|
export { default as Content } from './Content';
|
||||||
|
export { default as Form } from './Form';
|
||||||
|
export { default as WelcomeWrapper } from './WelcomeWrapper';
|
|
@ -3,8 +3,6 @@
|
||||||
<head>
|
<head>
|
||||||
<style>
|
<style>
|
||||||
body, html {
|
body, html {
|
||||||
margin: 0;
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
body {
|
body {
|
||||||
|
|
|
@ -5,6 +5,11 @@ import { render } from 'react-dom';
|
||||||
|
|
||||||
import { App } from './features/app';
|
import { App } from './features/app';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AtlasKit components will deflect from appearance if css-reset is not present.
|
||||||
|
*/
|
||||||
|
import '@atlaskit/css-reset';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render the main / root application.
|
* Render the main / root application.
|
||||||
* $FlowFixMe
|
* $FlowFixMe
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
10
package.json
10
package.json
|
@ -30,10 +30,16 @@
|
||||||
"readmeFilename": "README.md",
|
"readmeFilename": "README.md",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@atlaskit/button": "7.2.5",
|
||||||
|
"@atlaskit/css-reset": "2.0.2",
|
||||||
|
"@atlaskit/field-text": "5.1.0",
|
||||||
|
"@atlaskit/theme": "3.2.2",
|
||||||
"electron-is-dev": "0.3.0",
|
"electron-is-dev": "0.3.0",
|
||||||
"jitsi-meet-electron-utils": "jitsi/jitsi-meet-electron-utils",
|
"jitsi-meet-electron-utils": "jitsi/jitsi-meet-electron-utils",
|
||||||
"react": "16.3.2",
|
"react": "16.3.2",
|
||||||
"react-dom": "16.3.2"
|
"react-dom": "16.3.2",
|
||||||
|
"react-router-dom": "4.2.2",
|
||||||
|
"styled-components": "3.3.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-core": "6.26.3",
|
"babel-core": "6.26.3",
|
||||||
|
@ -41,6 +47,7 @@
|
||||||
"babel-loader": "7.1.4",
|
"babel-loader": "7.1.4",
|
||||||
"babel-preset-env": "1.7.0",
|
"babel-preset-env": "1.7.0",
|
||||||
"babel-preset-react": "6.24.1",
|
"babel-preset-react": "6.24.1",
|
||||||
|
"css-loader": "0.28.11",
|
||||||
"electron": "2.0.0",
|
"electron": "2.0.0",
|
||||||
"electron-packager": "12.0.2",
|
"electron-packager": "12.0.2",
|
||||||
"electron-rebuild": "1.7.3",
|
"electron-rebuild": "1.7.3",
|
||||||
|
@ -54,6 +61,7 @@
|
||||||
"html-webpack-plugin": "3.2.0",
|
"html-webpack-plugin": "3.2.0",
|
||||||
"node-loader": "0.6.0",
|
"node-loader": "0.6.0",
|
||||||
"precommit-hook": "3.0.0",
|
"precommit-hook": "3.0.0",
|
||||||
|
"style-loader": "0.21.0",
|
||||||
"webpack": "4.8.1",
|
"webpack": "4.8.1",
|
||||||
"webpack-cli": "2.1.3"
|
"webpack-cli": "2.1.3"
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,13 @@ const commonConfig = {
|
||||||
},
|
},
|
||||||
test: /\.js$/
|
test: /\.js$/
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
use: [
|
||||||
|
{ loader: 'style-loader' },
|
||||||
|
{ loader: 'css-loader' }
|
||||||
|
],
|
||||||
|
test: /\.css$/
|
||||||
|
},
|
||||||
{
|
{
|
||||||
use: 'node-loader',
|
use: 'node-loader',
|
||||||
test: /\.node$/
|
test: /\.node$/
|
||||||
|
|
Loading…
Reference in New Issue