diff --git a/js/redux/tournamentApi.js b/js/redux/tournamentApi.js
index 7d9576d..f9a7c27 100644
--- a/js/redux/tournamentApi.js
+++ b/js/redux/tournamentApi.js
@@ -46,6 +46,14 @@ export function getTournamentMatches(tournamentId, successCallback, errorCallbac
.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) {
let groupStage = null;
diff --git a/pages/tournament-fullscreen.js b/pages/tournament-fullscreen.js
index 5819389..9144772 100644
--- a/pages/tournament-fullscreen.js
+++ b/pages/tournament-fullscreen.js
@@ -1,7 +1,7 @@
import Head from 'next/head';
import React from 'react';
import {ErrorPageComponent} from '../js/components/ErrorComponents';
-import {getTournamentMatches, getTournamentMeta} from '../js/redux/tournamentApi';
+import {getTournamentMatches, getTournamentMeta, getTournamentTimerEnd} from '../js/redux/tournamentApi';
import {
Col, Container, DropdownItem, DropdownMenu, DropdownToggle, Navbar, NavbarBrand, NavItem, Row, UncontrolledDropdown,
Spinner
@@ -12,7 +12,7 @@ import {sortMatchesByPositionAscending} from '../js/utils/sorting';
function FullscreenPage(props) {
return (
-
+
);
}
@@ -55,9 +55,31 @@ function FilterDropdown(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 (
{props.title}
+ {props.timerEnd && Timer: {formatTimeLeft(timeLeft)}
}
);
}
@@ -80,7 +102,8 @@ class Main extends React.Component {
super(props);
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.onTournamentRequestError = this.onTournamentRequestError.bind(this);
@@ -88,6 +111,7 @@ class Main extends React.Component {
this.onTournamentMatchesRequestError = this.onTournamentMatchesRequestError.bind(this);
this.updateMatches = this.updateMatches.bind(this);
this.selectFilter = this.selectFilter.bind(this);
+ this.updateTimerEnd = this.updateTimerEnd.bind(this);
}
selectFilter(filter) {
@@ -99,6 +123,7 @@ class Main extends React.Component {
const tournamentId = this.props.query.code;
getTournamentMeta(tournamentId, this.onTournamentRequestSuccess, this.onTournamentRequestError);
this.updateMatches();
+ this.updateTimerEnd();
const intervalId = setInterval(this.updateMatches, 10000);
this.setState({intervalId: intervalId});
}
@@ -113,6 +138,19 @@ class Main extends React.Component {
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) {
this.setState({metaStatus: requestStatus, tournamentMeta: tournament, loadedMeta: true});
@@ -138,9 +176,8 @@ class Main extends React.Component {
}
}
-
render() {
- const {metaStatus, matchesStatus, tournamentMeta, matches} = this.state;
+ const {metaStatus, matchesStatus, tournamentMeta, matches, timerEnd} = this.state;
const filter = {
selected: this.state.matchFilter, select: this.selectFilter
};
@@ -160,7 +197,7 @@ class Main extends React.Component {
{tournamentMeta.name}: turnie.re
-
+
);
}
if (metaStatus === 200 && matchesStatus === 200) {
@@ -168,7 +205,7 @@ class Main extends React.Component {
{tournamentMeta.name}: turnie.re
-
+
);
} else {
return ;