Merge pull request #49 from turniere/ticket/TURNIERE-233
Ticket/turniere 233: Add page content loading indicators
This commit is contained in:
commit
475e00157c
|
|
@ -3,6 +3,8 @@ stages:
|
|||
- deploy
|
||||
|
||||
kaniko:
|
||||
tags:
|
||||
- docker
|
||||
stage: build
|
||||
image:
|
||||
name: gcr.io/kaniko-project/executor:debug
|
||||
|
|
@ -12,6 +14,8 @@ kaniko:
|
|||
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $CI_REGISTRY_IMAGE:latest --destination $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA --destination $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
|
||||
|
||||
kubernetes:
|
||||
tags:
|
||||
- turniere-deploy
|
||||
stage: deploy
|
||||
only:
|
||||
- master
|
||||
|
|
|
|||
|
|
@ -344,6 +344,7 @@ const reducerTournamentStatistics = (state = defaultStateTournamentStatistics, a
|
|||
storeOptionalToken(error.response);
|
||||
}
|
||||
action.parameters.errorCallback();
|
||||
return Object.assign({}, state, {loaded: true});
|
||||
});
|
||||
return state;
|
||||
case actionTypesTournamentStatistics.INT_REQUEST_TOURNAMENT_STATISTICS:
|
||||
|
|
@ -361,11 +362,12 @@ const reducerTournamentStatistics = (state = defaultStateTournamentStatistics, a
|
|||
storeOptionalToken(error.response);
|
||||
}
|
||||
action.parameters.errorCallback();
|
||||
return Object.assign({}, state, {loaded: true});
|
||||
});
|
||||
return Object.assign({}, state, action.parameters.tournamentInfo);
|
||||
return Object.assign({}, state, action.parameters.tournamentInfo, {loaded: true});
|
||||
case actionTypesTournamentStatistics.REQUEST_TOURNAMENT_STATISTICS_SUCCESS:
|
||||
action.parameters.successCallback();
|
||||
return Object.assign({}, state, action.parameters.tournamentStatistics);
|
||||
return Object.assign({}, state, action.parameters.tournamentStatistics, {loaded: true});
|
||||
default: return state;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
import Head from 'next/head';
|
||||
import {TurniereNavigation} from './Navigation';
|
||||
import {Container} from 'reactstrap';
|
||||
import {Footer} from './Footer';
|
||||
import React from 'react';
|
||||
|
||||
export function LoadingPage(props) {
|
||||
return (<div>
|
||||
<Head>
|
||||
<title>{props.title}</title>
|
||||
</Head>
|
||||
<TurniereNavigation/>
|
||||
<Container>
|
||||
<div className='text-center'>
|
||||
<img src='/static/images/logo-questionmark.png' alt='' className='loading-logo'/>
|
||||
</div>
|
||||
<div className='py-5 text-center w-100 h1 custom-font'>
|
||||
{props.text}
|
||||
</div>
|
||||
</Container>
|
||||
<Footer/>
|
||||
</div>);
|
||||
}
|
||||
|
|
@ -1,33 +1,49 @@
|
|||
import React from 'react';
|
||||
import {requestTournamentList} from '../api';
|
||||
import {Spinner} from 'react-bootstrap';
|
||||
|
||||
export default class TournamentList extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
tournaments: []
|
||||
tournaments: [],
|
||||
loaded: false
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
requestTournamentList(this.props.type, tournaments => {
|
||||
this.setState({
|
||||
tournaments: tournaments
|
||||
tournaments: tournaments,
|
||||
loaded: true
|
||||
});
|
||||
}, () => {
|
||||
this.setState({loaded: true});
|
||||
});
|
||||
}, () => {});
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.state.loaded) {
|
||||
return (<EmptyList>
|
||||
<Spinner animation='border' role='status' size='sm'/>
|
||||
<span className='ml-3'>lade Turnier-Liste</span>
|
||||
</EmptyList>);
|
||||
}
|
||||
|
||||
if (this.state.tournaments.length === 0) {
|
||||
return <p className="text-center border-light font-italic text-secondary border-top border-bottom p-1">keine
|
||||
Turniere vorhanden</p>;
|
||||
} else {
|
||||
return <EmptyList>keine Turniere vorhanden</EmptyList>;
|
||||
}
|
||||
return this.state.tournaments.map(item => (
|
||||
// The code should be item.code but the api just supports it this way by now
|
||||
<TournamentListEntry name={item.name} code={item.id} key={item.id}/>
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
function EmptyList(props) {
|
||||
return (<p className="text-center border-light font-italic text-secondary border-top border-bottom p-1">
|
||||
{props.children}
|
||||
</p>);
|
||||
}
|
||||
|
||||
function TournamentListEntry(props) {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ export const defaultStateTournamentStatistics = {
|
|||
owner_username: '',
|
||||
isPublic: '',
|
||||
|
||||
loaded: false,
|
||||
statistics_available: false,
|
||||
|
||||
most_dominant_team: {},
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import 'bootstrap/dist/css/bootstrap.min.css';
|
|||
|
||||
import '../static/css/everypage.css';
|
||||
import '../static/css/index.css';
|
||||
import {LoadingPage} from '../js/components/LoadingPage';
|
||||
|
||||
class EditTournamentPage extends React.Component {
|
||||
static async getInitialProps({query}) {
|
||||
|
|
@ -29,26 +30,31 @@ class EditTournamentPage extends React.Component {
|
|||
super(props);
|
||||
|
||||
this.state = {
|
||||
validCode: false
|
||||
validCode: false,
|
||||
loaded: false
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
requestTournament(this.props.query.code, () => {
|
||||
this.setState({validCode: true});
|
||||
this.setState({validCode: true, loaded: true});
|
||||
|
||||
if (this._edittournamentcontent != null) {
|
||||
this._edittournamentcontent.notifyOfContentUpdate();
|
||||
}
|
||||
}, () => {
|
||||
this.setState({validCode: false});
|
||||
this.setState({validCode: false, loaded: true});
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const {validCode} = this.state;
|
||||
const {validCode, loaded} = this.state;
|
||||
const {tournamentname, ownerUsername, isSignedIn, username} = this.props;
|
||||
|
||||
if (!loaded) {
|
||||
return <LoadingPage title='turnie.re' text='Turnier-Einstellungen werden geladen...'/>;
|
||||
}
|
||||
|
||||
return (<UserRestrictor>
|
||||
<Option condition={validCode && isSignedIn && ownerUsername === username}>
|
||||
<div className='pb-5'>
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import {requestTournamentStatistics} from '../js/api';
|
|||
import {EditButton, TournamentStatusBar, TournamentStatusBarButton} from '../js/components/TournamentStatusBar';
|
||||
import Navbar from 'react-bootstrap/Navbar';
|
||||
import {TournamentBigImage} from '../js/components/TournamentBigImage';
|
||||
import {LoadingPage} from '../js/components/LoadingPage';
|
||||
|
||||
class StatisticsTournamentPage extends React.Component {
|
||||
static async getInitialProps({query}) {
|
||||
|
|
@ -24,6 +25,10 @@ class StatisticsTournamentPage extends React.Component {
|
|||
render() {
|
||||
const {tournamentStatistics} = this.props;
|
||||
|
||||
if (!tournamentStatistics.loaded) {
|
||||
return <LoadingPage title='turnie.re' text='Statistiken zum Turnier werden geladen...'/>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Head>
|
||||
|
|
|
|||
|
|
@ -12,11 +12,12 @@ import 'bootstrap/dist/css/bootstrap.min.css';
|
|||
|
||||
import '../static/css/everypage.css';
|
||||
import '../static/css/tournament.css';
|
||||
import {getTournament} from '../js/redux/tournamentApi';
|
||||
import {PlayoffStages} from '../js/components/PlayoffStages';
|
||||
import GroupStage from '../js/components/GroupStage';
|
||||
import {TournamentBigImage} from '../js/components/TournamentBigImage';
|
||||
import {EditButton, TournamentStatusBar, TournamentStatusBarButton} from '../js/components/TournamentStatusBar';
|
||||
import {LoadingPage} from '../js/components/LoadingPage';
|
||||
import {getTournament} from '../js/redux/tournamentApi';
|
||||
|
||||
class PrivateTournamentPage extends React.Component {
|
||||
render() {
|
||||
|
|
@ -71,7 +72,8 @@ class Main extends React.Component {
|
|||
super(props);
|
||||
|
||||
this.state = {
|
||||
tournament: null
|
||||
tournament: null,
|
||||
loaded: false
|
||||
};
|
||||
this.onTournamentRequestSuccess = this.onTournamentRequestSuccess.bind(this);
|
||||
this.onTournamentRequestError = this.onTournamentRequestError.bind(this);
|
||||
|
|
@ -82,14 +84,14 @@ class Main extends React.Component {
|
|||
}
|
||||
|
||||
onTournamentRequestSuccess(requestStatus, tournament) {
|
||||
this.setState({status: requestStatus, tournament: tournament});
|
||||
this.setState({status: requestStatus, tournament: tournament, loaded: true});
|
||||
}
|
||||
|
||||
onTournamentRequestError(error) {
|
||||
if (error.response) {
|
||||
this.setState({status: error.response.status});
|
||||
this.setState({status: error.response.status, loaded: true});
|
||||
} else {
|
||||
this.setState({status: -1});
|
||||
this.setState({status: -1, loaded: true});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -109,6 +111,9 @@ class Main extends React.Component {
|
|||
<Footer/>
|
||||
</div>);
|
||||
} else {
|
||||
if (!this.state.loaded) {
|
||||
return <LoadingPage title='turnie.re' text='Turnier wird geladen...'/>;
|
||||
}
|
||||
return <ErrorPageComponent code={status}/>;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,3 +72,19 @@ footer {
|
|||
background-size: cover;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.loading-logo {
|
||||
animation: blink .8s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes blink {
|
||||
0% {
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
70% {
|
||||
filter: grayscale(0%);
|
||||
}
|
||||
100% {
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue