Add basic timer implementation
This commit is contained in:
parent
f2a79acfe5
commit
e134492ef8
|
|
@ -46,6 +46,14 @@ export function getTournamentMatches(tournamentId, successCallback, errorCallbac
|
||||||
.catch(errorCallback);
|
.catch(errorCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getTournamentTimerEnd(tournamentId, successCallback, errorCallback) {
|
||||||
|
getRequest(getState(), '/tournaments/' + tournamentId + '/timer_end')
|
||||||
|
.then(response => {
|
||||||
|
const timerEndDate = new Date(response.data);
|
||||||
|
successCallback(response.status, timerEndDate);
|
||||||
|
})
|
||||||
|
.catch(errorCallback);
|
||||||
|
}
|
||||||
|
|
||||||
function convertTournament(apiTournament) {
|
function convertTournament(apiTournament) {
|
||||||
let groupStage = null;
|
let groupStage = null;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import Head from 'next/head';
|
import Head from 'next/head';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {ErrorPageComponent} from '../js/components/ErrorComponents';
|
import {ErrorPageComponent} from '../js/components/ErrorComponents';
|
||||||
import {getTournamentMatches, getTournamentMeta} from '../js/redux/tournamentApi';
|
import {getTournamentMatches, getTournamentMeta, getTournamentTimerEnd} from '../js/redux/tournamentApi';
|
||||||
import {
|
import {
|
||||||
Col, Container, DropdownItem, DropdownMenu, DropdownToggle, Navbar, NavbarBrand, NavItem, Row, UncontrolledDropdown,
|
Col, Container, DropdownItem, DropdownMenu, DropdownToggle, Navbar, NavbarBrand, NavItem, Row, UncontrolledDropdown,
|
||||||
Spinner
|
Spinner
|
||||||
|
|
@ -12,7 +12,7 @@ import {sortMatchesByPositionAscending} from '../js/utils/sorting';
|
||||||
|
|
||||||
function FullscreenPage(props) {
|
function FullscreenPage(props) {
|
||||||
return (<div>
|
return (<div>
|
||||||
<FullscreenPageHeader title={props.tournamentMeta.name} code={props.tournamentMeta.code} filter={props.filter}/>
|
<FullscreenPageHeader title={props.tournamentMeta.name} code={props.tournamentMeta.code} filter={props.filter} timerEnd={props.timerEnd}/>
|
||||||
<Matches matches={props.matches}/>
|
<Matches matches={props.matches}/>
|
||||||
</div>);
|
</div>);
|
||||||
}
|
}
|
||||||
|
|
@ -55,9 +55,31 @@ function FilterDropdown(props) {
|
||||||
|
|
||||||
|
|
||||||
function FullscreenPageHeader(props) {
|
function FullscreenPageHeader(props) {
|
||||||
|
const [timeLeft, setTimeLeft] = React.useState(null);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (props.timerEnd) {
|
||||||
|
const intervalId = setInterval(() => {
|
||||||
|
const now = new Date();
|
||||||
|
const timeLeft = props.timerEnd - now;
|
||||||
|
setTimeLeft(timeLeft > 0 ? timeLeft : 0);
|
||||||
|
}, 1000);
|
||||||
|
return () => clearInterval(intervalId);
|
||||||
|
}
|
||||||
|
}, [props.timerEnd]);
|
||||||
|
|
||||||
|
const formatTimeLeft = (timeLeft) => {
|
||||||
|
if (timeLeft === null) return '';
|
||||||
|
const hours = Math.floor(timeLeft / (1000 * 60 * 60));
|
||||||
|
const minutes = Math.floor((timeLeft % (1000 * 60 * 60)) / (1000 * 60));
|
||||||
|
const seconds = Math.floor((timeLeft % (1000 * 60)) / 1000);
|
||||||
|
return `${hours}h ${minutes}m ${seconds}s`;
|
||||||
|
};
|
||||||
|
|
||||||
return (<Navbar color='light' className='mb-4 border-bottom py-0'>
|
return (<Navbar color='light' className='mb-4 border-bottom py-0'>
|
||||||
<FilterDropdown {...props.filter}/>
|
<FilterDropdown {...props.filter}/>
|
||||||
<NavbarBrand>{props.title}</NavbarBrand>
|
<NavbarBrand>{props.title}</NavbarBrand>
|
||||||
|
{props.timerEnd && <div className='ml-auto'>Timer: {formatTimeLeft(timeLeft)}</div>}
|
||||||
</Navbar>);
|
</Navbar>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -80,7 +102,8 @@ class Main extends React.Component {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
tournamentMeta: null, matches: [], matchFilter: matchFilters.all, loadedMeta: false, loadedMatches: false
|
tournamentMeta: null, matches: [], matchFilter: matchFilters.all, loadedMeta: false, loadedMatches: false,
|
||||||
|
timerEnd: null, intervalId: null
|
||||||
};
|
};
|
||||||
this.onTournamentRequestSuccess = this.onTournamentRequestSuccess.bind(this);
|
this.onTournamentRequestSuccess = this.onTournamentRequestSuccess.bind(this);
|
||||||
this.onTournamentRequestError = this.onTournamentRequestError.bind(this);
|
this.onTournamentRequestError = this.onTournamentRequestError.bind(this);
|
||||||
|
|
@ -88,6 +111,7 @@ class Main extends React.Component {
|
||||||
this.onTournamentMatchesRequestError = this.onTournamentMatchesRequestError.bind(this);
|
this.onTournamentMatchesRequestError = this.onTournamentMatchesRequestError.bind(this);
|
||||||
this.updateMatches = this.updateMatches.bind(this);
|
this.updateMatches = this.updateMatches.bind(this);
|
||||||
this.selectFilter = this.selectFilter.bind(this);
|
this.selectFilter = this.selectFilter.bind(this);
|
||||||
|
this.updateTimerEnd = this.updateTimerEnd.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
selectFilter(filter) {
|
selectFilter(filter) {
|
||||||
|
|
@ -99,6 +123,7 @@ class Main extends React.Component {
|
||||||
const tournamentId = this.props.query.code;
|
const tournamentId = this.props.query.code;
|
||||||
getTournamentMeta(tournamentId, this.onTournamentRequestSuccess, this.onTournamentRequestError);
|
getTournamentMeta(tournamentId, this.onTournamentRequestSuccess, this.onTournamentRequestError);
|
||||||
this.updateMatches();
|
this.updateMatches();
|
||||||
|
this.updateTimerEnd();
|
||||||
const intervalId = setInterval(this.updateMatches, 10000);
|
const intervalId = setInterval(this.updateMatches, 10000);
|
||||||
this.setState({intervalId: intervalId});
|
this.setState({intervalId: intervalId});
|
||||||
}
|
}
|
||||||
|
|
@ -113,6 +138,19 @@ class Main extends React.Component {
|
||||||
this.state.matchFilter.backend);
|
this.state.matchFilter.backend);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateTimerEnd() {
|
||||||
|
const tournamentId = this.props.query.code;
|
||||||
|
getTournamentTimerEnd(tournamentId, (status, timerEnd) => {
|
||||||
|
const now = new Date();
|
||||||
|
if (timerEnd > now) {
|
||||||
|
this.setState({timerEnd: timerEnd});
|
||||||
|
} else {
|
||||||
|
this.setState({timerEnd: null});
|
||||||
|
}
|
||||||
|
}, error => {
|
||||||
|
console.error('Failed to fetch timer end:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
onTournamentRequestSuccess(requestStatus, tournament) {
|
onTournamentRequestSuccess(requestStatus, tournament) {
|
||||||
this.setState({metaStatus: requestStatus, tournamentMeta: tournament, loadedMeta: true});
|
this.setState({metaStatus: requestStatus, tournamentMeta: tournament, loadedMeta: true});
|
||||||
|
|
@ -138,9 +176,8 @@ class Main extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {metaStatus, matchesStatus, tournamentMeta, matches} = this.state;
|
const {metaStatus, matchesStatus, tournamentMeta, matches, timerEnd} = this.state;
|
||||||
const filter = {
|
const filter = {
|
||||||
selected: this.state.matchFilter, select: this.selectFilter
|
selected: this.state.matchFilter, select: this.selectFilter
|
||||||
};
|
};
|
||||||
|
|
@ -160,7 +197,7 @@ class Main extends React.Component {
|
||||||
<Head>
|
<Head>
|
||||||
<title>{tournamentMeta.name}: turnie.re</title>
|
<title>{tournamentMeta.name}: turnie.re</title>
|
||||||
</Head>
|
</Head>
|
||||||
<FullscreenPage tournamentMeta={tournamentMeta} matches={null} filter={filter}/>
|
<FullscreenPage tournamentMeta={tournamentMeta} matches={null} filter={filter} timerEnd={timerEnd}/>
|
||||||
</div>);
|
</div>);
|
||||||
}
|
}
|
||||||
if (metaStatus === 200 && matchesStatus === 200) {
|
if (metaStatus === 200 && matchesStatus === 200) {
|
||||||
|
|
@ -168,7 +205,7 @@ class Main extends React.Component {
|
||||||
<Head>
|
<Head>
|
||||||
<title>{tournamentMeta.name}: turnie.re</title>
|
<title>{tournamentMeta.name}: turnie.re</title>
|
||||||
</Head>
|
</Head>
|
||||||
<FullscreenPage tournamentMeta={tournamentMeta} matches={matches} filter={filter}/>
|
<FullscreenPage tournamentMeta={tournamentMeta} matches={matches} filter={filter} timerEnd={timerEnd}/>
|
||||||
</div>);
|
</div>);
|
||||||
} else {
|
} else {
|
||||||
return <ErrorPageComponent code={metaStatus}/>;
|
return <ErrorPageComponent code={metaStatus}/>;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue