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,
|
Server,
|
||||||
Login,
|
Login,
|
||||||
Logs,
|
Logs,
|
||||||
|
Initialize,
|
||||||
Unsupported
|
Unsupported
|
||||||
} from 'containers';
|
} from 'containers';
|
||||||
|
|
||||||
|
@ -25,9 +26,10 @@ const Routes = () => (
|
||||||
{<Route path={RouteEnum.ROOM} render={() => <Room />} />}
|
{<Route path={RouteEnum.ROOM} render={() => <Room />} />}
|
||||||
<Route path={RouteEnum.SERVER} render={() => <Server />} />
|
<Route path={RouteEnum.SERVER} render={() => <Server />} />
|
||||||
<Route path={RouteEnum.LOGIN} render={() => <Login />} />
|
<Route path={RouteEnum.LOGIN} render={() => <Login />} />
|
||||||
|
<Route path={RouteEnum.INITIALIZE} render={() => <Initialize />} />
|
||||||
<Route path={RouteEnum.UNSUPPORTED} render={() => <Unsupported />} />
|
<Route path={RouteEnum.UNSUPPORTED} render={() => <Unsupported />} />
|
||||||
|
|
||||||
<Redirect from="*" to={RouteEnum.LOGIN} />
|
<Redirect from="*" to={RouteEnum.INITIALIZE} />
|
||||||
</Switch>
|
</Switch>
|
||||||
</div>
|
</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 Server } from './Server/Server';
|
||||||
export { default as Logs } from './Logs/Logs';
|
export { default as Logs } from './Logs/Logs';
|
||||||
export { default as Login } from './Login/Login';
|
export { default as Login } from './Login/Login';
|
||||||
|
export { default as Initialize } from './Initialize/Initialize';
|
||||||
export { default as Unsupported } from './Unsupported/Unsupported';
|
export { default as Unsupported } from './Unsupported/Unsupported';
|
||||||
|
|
|
@ -34,7 +34,7 @@ const ResetPasswordForm = ({ onSubmit, userName }) => {
|
||||||
if (!values.newPassword) {
|
if (!values.newPassword) {
|
||||||
errors.newPassword = 'Required';
|
errors.newPassword = 'Required';
|
||||||
} else if (values.newPassword.length < 8) {
|
} else if (values.newPassword.length < 8) {
|
||||||
errors.password = 'Minimum of 8 characters required';
|
errors.newPassword = 'Minimum of 8 characters required';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!values.passwordAgain) {
|
if (!values.passwordAgain) {
|
||||||
|
|
|
@ -193,11 +193,11 @@ export const materialTheme = createTheme({
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: 'bold',
|
fontWeight: 'bold',
|
||||||
lineHeight: 1.4,
|
lineHeight: 1.4,
|
||||||
color: '#9E9E9E',
|
color: palette.grey[500],
|
||||||
},
|
},
|
||||||
subtitle2: {
|
subtitle2: {
|
||||||
lineHeight: 1.4,
|
lineHeight: 1.4,
|
||||||
color: '#9E9E9E',
|
color: palette.grey[500],
|
||||||
},
|
},
|
||||||
// body1: {},
|
// body1: {},
|
||||||
// body2: {},
|
// body2: {},
|
||||||
|
|
|
@ -4,6 +4,9 @@ import { WebSocketConnectOptions } from 'types';
|
||||||
import { Types } from './server.types';
|
import { Types } from './server.types';
|
||||||
|
|
||||||
export const Actions = {
|
export const Actions = {
|
||||||
|
initialized: () => ({
|
||||||
|
type: Types.INITIALIZED
|
||||||
|
}),
|
||||||
clearStore: () => ({
|
clearStore: () => ({
|
||||||
type: Types.CLEAR_STORE
|
type: Types.CLEAR_STORE
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -3,6 +3,9 @@ import { Actions } from './server.actions';
|
||||||
import { store } from 'store';
|
import { store } from 'store';
|
||||||
|
|
||||||
export const Dispatch = {
|
export const Dispatch = {
|
||||||
|
initialized: () => {
|
||||||
|
store.dispatch(Actions.initialized());
|
||||||
|
},
|
||||||
clearStore: () => {
|
clearStore: () => {
|
||||||
store.dispatch(Actions.clearStore());
|
store.dispatch(Actions.clearStore());
|
||||||
},
|
},
|
||||||
|
|
|
@ -39,6 +39,7 @@ export interface AccountActivationParams extends ServerRegisterParams {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ServerState {
|
export interface ServerState {
|
||||||
|
initialized: boolean;
|
||||||
buddyList: User[];
|
buddyList: User[];
|
||||||
ignoreList: User[];
|
ignoreList: User[];
|
||||||
info: ServerStateInfo;
|
info: ServerStateInfo;
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { ServerState } from './server.interfaces'
|
||||||
import { Types } from './server.types';
|
import { Types } from './server.types';
|
||||||
|
|
||||||
const initialState: ServerState = {
|
const initialState: ServerState = {
|
||||||
|
initialized: false,
|
||||||
buddyList: [],
|
buddyList: [],
|
||||||
ignoreList: [],
|
ignoreList: [],
|
||||||
|
|
||||||
|
@ -33,6 +34,12 @@ const initialState: ServerState = {
|
||||||
|
|
||||||
export const serverReducer = (state = initialState, action: any) => {
|
export const serverReducer = (state = initialState, action: any) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
case Types.INITIALIZED: {
|
||||||
|
return {
|
||||||
|
...initialState,
|
||||||
|
initialized: true
|
||||||
|
}
|
||||||
|
}
|
||||||
case Types.CLEAR_STORE: {
|
case Types.CLEAR_STORE: {
|
||||||
return {
|
return {
|
||||||
...initialState,
|
...initialState,
|
||||||
|
|
|
@ -5,6 +5,7 @@ interface State {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Selectors = {
|
export const Selectors = {
|
||||||
|
getInitialized: ({ server }: State) => server.initialized,
|
||||||
getMessage: ({ server }: State) => server.info.message,
|
getMessage: ({ server }: State) => server.info.message,
|
||||||
getName: ({ server }: State) => server.info.name,
|
getName: ({ server }: State) => server.info.name,
|
||||||
getVersion: ({ server }: State) => server.info.version,
|
getVersion: ({ server }: State) => server.info.version,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
export const Types = {
|
export const Types = {
|
||||||
|
INITIALIZED: '[Server] Initialized',
|
||||||
CLEAR_STORE: '[Server] Clear Store',
|
CLEAR_STORE: '[Server] Clear Store',
|
||||||
LOGIN_SUCCESSFUL: '[Server] Login Successful',
|
LOGIN_SUCCESSFUL: '[Server] Login Successful',
|
||||||
LOGIN_FAILED: '[Server] Login Failed',
|
LOGIN_FAILED: '[Server] Login Failed',
|
||||||
|
|
|
@ -10,5 +10,6 @@ export enum RouteEnum {
|
||||||
ACCOUNT = '/account',
|
ACCOUNT = '/account',
|
||||||
ADMINISTRATION = '/administration',
|
ADMINISTRATION = '/administration',
|
||||||
REPLAYS = '/replays',
|
REPLAYS = '/replays',
|
||||||
|
INITIALIZE = '/initialize',
|
||||||
UNSUPPORTED = '/unsupported',
|
UNSUPPORTED = '/unsupported',
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,10 @@ import { sanitizeHtml } from 'websocket/utils';
|
||||||
import NormalizeService from '../utils/NormalizeService';
|
import NormalizeService from '../utils/NormalizeService';
|
||||||
|
|
||||||
export class SessionPersistence {
|
export class SessionPersistence {
|
||||||
|
static initialized() {
|
||||||
|
ServerDispatch.initialized();
|
||||||
|
}
|
||||||
|
|
||||||
static clearStore() {
|
static clearStore() {
|
||||||
ServerDispatch.clearStore();
|
ServerDispatch.clearStore();
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import ProtoFiles from '../ProtoFiles';
|
||||||
import { WebClient } from '../WebClient';
|
import { WebClient } from '../WebClient';
|
||||||
|
|
||||||
import { RoomEvents, SessionEvents } from '../events';
|
import { RoomEvents, SessionEvents } from '../events';
|
||||||
|
import { SessionPersistence } from '../persistence';
|
||||||
|
|
||||||
export interface ProtobufEvents {
|
export interface ProtobufEvents {
|
||||||
[event: string]: Function;
|
[event: string]: Function;
|
||||||
|
@ -135,6 +136,8 @@ export class ProtobufService {
|
||||||
if (err) {
|
if (err) {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SessionPersistence.initialized();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue