Webatrice: show loading screen until protobuf initializes (#4559)
* show loading screen until protobuf initializes * cleanup Co-authored-by: Jeremy Letto <jeremy.letto@datasite.com>
This commit is contained in:
parent
bb16ae09ef
commit
6928a2bd98
15 changed files with 178 additions and 4 deletions
|
@ -11,6 +11,7 @@ import {
|
|||
Server,
|
||||
Login,
|
||||
Logs,
|
||||
Initialize,
|
||||
Unsupported
|
||||
} from 'containers';
|
||||
|
||||
|
@ -25,9 +26,10 @@ const Routes = () => (
|
|||
{<Route path={RouteEnum.ROOM} render={() => <Room />} />}
|
||||
<Route path={RouteEnum.SERVER} render={() => <Server />} />
|
||||
<Route path={RouteEnum.LOGIN} render={() => <Login />} />
|
||||
<Route path={RouteEnum.INITIALIZE} render={() => <Initialize />} />
|
||||
<Route path={RouteEnum.UNSUPPORTED} render={() => <Unsupported />} />
|
||||
|
||||
<Redirect from="*" to={RouteEnum.LOGIN} />
|
||||
<Redirect from="*" to={RouteEnum.INITIALIZE} />
|
||||
</Switch>
|
||||
</div>
|
||||
);
|
||||
|
|
88
webclient/src/containers/Initialize/Initialize.css
Normal file
88
webclient/src/containers/Initialize/Initialize.css
Normal file
|
@ -0,0 +1,88 @@
|
|||
.Initialize {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.Initialize img {
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
h6.subtitle {
|
||||
margin: 20px 0 10px;
|
||||
}
|
||||
|
||||
.Initialize-graphics {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.Initialize-graphics__square {
|
||||
position: absolute;
|
||||
border: 2px solid;
|
||||
opacity: .05;
|
||||
}
|
||||
|
||||
.Initialize-graphics__bar {
|
||||
position: absolute;
|
||||
opacity: .05;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.Initialize-graphics__square.topLeft {
|
||||
transform: rotate(27deg);
|
||||
top: 38px;
|
||||
left: 64px;
|
||||
height: 134px;
|
||||
width: 100px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.Initialize-graphics__square.topRight {
|
||||
transform: rotate(10deg);
|
||||
top: 74px;
|
||||
right: 62px;
|
||||
height: 50px;
|
||||
width: 66px;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.Initialize-graphics__square.bottomLeft {
|
||||
transform: rotate(120deg);
|
||||
bottom: 61px;
|
||||
left: 66px;
|
||||
height: 50px;
|
||||
width: 66px;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.Initialize-graphics__square.bottomRight {
|
||||
transform: rotate(-24deg);
|
||||
bottom: 54px;
|
||||
right: 0;
|
||||
height: 88px;
|
||||
width: 66px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.Initialize-graphics__bar.bottomBar {
|
||||
transform: rotate(30deg);
|
||||
bottom: -4px;
|
||||
left: -29px;
|
||||
height: 50px;
|
||||
width: 222px;
|
||||
}
|
||||
|
||||
.Initialize-graphics__bar.topBar {
|
||||
transform: rotate(-330deg);
|
||||
top: 10px;
|
||||
right: -49px;
|
||||
height: 50px;
|
||||
width: 222px;
|
||||
}
|
59
webclient/src/containers/Initialize/Initialize.tsx
Normal file
59
webclient/src/containers/Initialize/Initialize.tsx
Normal file
|
@ -0,0 +1,59 @@
|
|||
import { useState } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { Redirect, withRouter } from 'react-router-dom';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
|
||||
import { Images } from 'images';
|
||||
import { ServerSelectors } from 'store';
|
||||
import { RouteEnum } from 'types';
|
||||
|
||||
import './Initialize.css';
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
root: {
|
||||
'& .Initialize-graphics': {
|
||||
color: theme.palette.primary.contrastText,
|
||||
},
|
||||
|
||||
'& .Initialize-graphics__bar': {
|
||||
backgroundColor: theme.palette.primary.contrastText,
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
const Initialize = ({ initialized }: InitializeProps) => {
|
||||
const classes = useStyles();
|
||||
|
||||
return initialized
|
||||
? <Redirect from="*" to={RouteEnum.LOGIN} />
|
||||
: (
|
||||
<div className={'Initialize ' + classes.root}>
|
||||
<div className='Initialize-content'>
|
||||
<img src={Images.Logo} alt="logo" />
|
||||
<Typography variant="subtitle1" className='subtitle'>DID YOU KNOW</Typography>
|
||||
<Typography variant="subtitle2">Cockatrice is run by volunteers</Typography>
|
||||
<Typography variant="subtitle2">that love card games!</Typography>
|
||||
</div>
|
||||
|
||||
<div className="Initialize-graphics">
|
||||
<div className="topLeft Initialize-graphics__square" />
|
||||
<div className="topRight Initialize-graphics__square" />
|
||||
<div className="bottomRight Initialize-graphics__square" />
|
||||
<div className="bottomLeft Initialize-graphics__square" />
|
||||
<div className="topBar Initialize-graphics__bar" />
|
||||
<div className="bottomBar Initialize-graphics__bar" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface InitializeProps {
|
||||
initialized: boolean;
|
||||
}
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
initialized: ServerSelectors.getInitialized(state),
|
||||
});
|
||||
|
||||
export default withRouter(connect(mapStateToProps)(Initialize));
|
|
@ -7,4 +7,5 @@ export { default as Player } from './Player/Player';
|
|||
export { default as Server } from './Server/Server';
|
||||
export { default as Logs } from './Logs/Logs';
|
||||
export { default as Login } from './Login/Login';
|
||||
export { default as Initialize } from './Initialize/Initialize';
|
||||
export { default as Unsupported } from './Unsupported/Unsupported';
|
||||
|
|
|
@ -34,7 +34,7 @@ const ResetPasswordForm = ({ onSubmit, userName }) => {
|
|||
if (!values.newPassword) {
|
||||
errors.newPassword = 'Required';
|
||||
} else if (values.newPassword.length < 8) {
|
||||
errors.password = 'Minimum of 8 characters required';
|
||||
errors.newPassword = 'Minimum of 8 characters required';
|
||||
}
|
||||
|
||||
if (!values.passwordAgain) {
|
||||
|
|
|
@ -193,11 +193,11 @@ export const materialTheme = createTheme({
|
|||
fontSize: 14,
|
||||
fontWeight: 'bold',
|
||||
lineHeight: 1.4,
|
||||
color: '#9E9E9E',
|
||||
color: palette.grey[500],
|
||||
},
|
||||
subtitle2: {
|
||||
lineHeight: 1.4,
|
||||
color: '#9E9E9E',
|
||||
color: palette.grey[500],
|
||||
},
|
||||
// body1: {},
|
||||
// body2: {},
|
||||
|
|
|
@ -4,6 +4,9 @@ import { WebSocketConnectOptions } from 'types';
|
|||
import { Types } from './server.types';
|
||||
|
||||
export const Actions = {
|
||||
initialized: () => ({
|
||||
type: Types.INITIALIZED
|
||||
}),
|
||||
clearStore: () => ({
|
||||
type: Types.CLEAR_STORE
|
||||
}),
|
||||
|
|
|
@ -3,6 +3,9 @@ import { Actions } from './server.actions';
|
|||
import { store } from 'store';
|
||||
|
||||
export const Dispatch = {
|
||||
initialized: () => {
|
||||
store.dispatch(Actions.initialized());
|
||||
},
|
||||
clearStore: () => {
|
||||
store.dispatch(Actions.clearStore());
|
||||
},
|
||||
|
|
|
@ -39,6 +39,7 @@ export interface AccountActivationParams extends ServerRegisterParams {
|
|||
}
|
||||
|
||||
export interface ServerState {
|
||||
initialized: boolean;
|
||||
buddyList: User[];
|
||||
ignoreList: User[];
|
||||
info: ServerStateInfo;
|
||||
|
|
|
@ -6,6 +6,7 @@ import { ServerState } from './server.interfaces'
|
|||
import { Types } from './server.types';
|
||||
|
||||
const initialState: ServerState = {
|
||||
initialized: false,
|
||||
buddyList: [],
|
||||
ignoreList: [],
|
||||
|
||||
|
@ -33,6 +34,12 @@ const initialState: ServerState = {
|
|||
|
||||
export const serverReducer = (state = initialState, action: any) => {
|
||||
switch (action.type) {
|
||||
case Types.INITIALIZED: {
|
||||
return {
|
||||
...initialState,
|
||||
initialized: true
|
||||
}
|
||||
}
|
||||
case Types.CLEAR_STORE: {
|
||||
return {
|
||||
...initialState,
|
||||
|
|
|
@ -5,6 +5,7 @@ interface State {
|
|||
}
|
||||
|
||||
export const Selectors = {
|
||||
getInitialized: ({ server }: State) => server.initialized,
|
||||
getMessage: ({ server }: State) => server.info.message,
|
||||
getName: ({ server }: State) => server.info.name,
|
||||
getVersion: ({ server }: State) => server.info.version,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
export const Types = {
|
||||
INITIALIZED: '[Server] Initialized',
|
||||
CLEAR_STORE: '[Server] Clear Store',
|
||||
LOGIN_SUCCESSFUL: '[Server] Login Successful',
|
||||
LOGIN_FAILED: '[Server] Login Failed',
|
||||
|
|
|
@ -10,5 +10,6 @@ export enum RouteEnum {
|
|||
ACCOUNT = '/account',
|
||||
ADMINISTRATION = '/administration',
|
||||
REPLAYS = '/replays',
|
||||
INITIALIZE = '/initialize',
|
||||
UNSUPPORTED = '/unsupported',
|
||||
}
|
||||
|
|
|
@ -5,6 +5,10 @@ import { sanitizeHtml } from 'websocket/utils';
|
|||
import NormalizeService from '../utils/NormalizeService';
|
||||
|
||||
export class SessionPersistence {
|
||||
static initialized() {
|
||||
ServerDispatch.initialized();
|
||||
}
|
||||
|
||||
static clearStore() {
|
||||
ServerDispatch.clearStore();
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import ProtoFiles from '../ProtoFiles';
|
|||
import { WebClient } from '../WebClient';
|
||||
|
||||
import { RoomEvents, SessionEvents } from '../events';
|
||||
import { SessionPersistence } from '../persistence';
|
||||
|
||||
export interface ProtobufEvents {
|
||||
[event: string]: Function;
|
||||
|
@ -135,6 +136,8 @@ export class ProtobufService {
|
|||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
SessionPersistence.initialized();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue