diff --git a/js/components/GroupStage.js b/js/components/GroupStage.js
new file mode 100644
index 0000000..76f371e
--- /dev/null
+++ b/js/components/GroupStage.js
@@ -0,0 +1,100 @@
+import {Button, Card, CardBody, Col, Collapse, Row, Table} from 'reactstrap';
+import {Match} from './Match';
+import React, {Component} from 'react';
+import {getGroup} from '../redux/tournamentApi';
+import {notify} from 'react-notify-toast';
+
+export default class GroupStage extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {showMatches: this.props.showMatches};
+ this.toggleShowMatches = this.toggleShowMatches.bind(this);
+ }
+
+ toggleShowMatches() {
+ this.setState({showMatches: !this.state.showMatches});
+ }
+
+ render() {
+ return (
+
+ Gruppenphase
+
+
+
+ {this.props.groups.map(group => )}
+
+ );
+ }
+}
+
+function ShowMatchesToggleButton(props) {
+ return ();
+}
+
+class Group extends Component {
+ constructor(props) {
+ super(props);
+ this.state = props.group;
+ this.reload = this.reload.bind(this);
+ this.onReloadSuccess = this.onReloadSuccess.bind(this);
+ this.onReloadError = this.onReloadError.bind(this);
+ }
+
+ reload() {
+ getGroup(this.state.id, this.onReloadSuccess, this.onReloadError);
+ }
+
+ onReloadSuccess(status, updatedGroup) {
+ this.setState(updatedGroup);
+ }
+
+ onReloadError() {
+ notify.show('Die Gruppe konnte nicht aktualisiert werden.', 'warning', 2000);
+ }
+
+ render() {
+ return (
+
+
+ Gruppe {this.state.number}
+
+ {this.state.matches.map((match => (
+ )))}
+
+
+
+
+ );
+ }
+}
+
+function GroupScoresTable(props) {
+ return (
+
+
+ | Team |
+ Punkte |
+ erzielt |
+ kassiert |
+
+
+
+ {props.scores.map(groupScore => )}
+
+
);
+}
+
+
+function GroupScoresTableRow(props) {
+ return (
+ | {props.score.team.name} |
+ {props.score.group_points} |
+ {props.score.received_points} |
+ {props.score.scored_points} |
+
);
+}
diff --git a/js/components/Match.js b/js/components/Match.js
index 95293d8..e9e01b8 100644
--- a/js/components/Match.js
+++ b/js/components/Match.js
@@ -70,6 +70,7 @@ export class Match extends React.Component {
updatedMatch.team1.score = scoreTeam1;
updatedMatch.team2.score = scoreTeam2;
this.setState({match: updatedMatch});
+ this.props.onChange !== undefined && this.props.onChange();
}
getMatchFinishedMessage() {
diff --git a/js/components/PlayoffStages.js b/js/components/PlayoffStages.js
new file mode 100644
index 0000000..5387bab
--- /dev/null
+++ b/js/components/PlayoffStages.js
@@ -0,0 +1,18 @@
+import {Stage} from './Stage';
+import React from 'react';
+
+export function PlayoffStages(props) {
+ return (
+ {props.playoffStages.map(stage => )}
+
);
+}
+
+function getLevelName(levelNumber) {
+ const names = ['Finale', 'Halbfinale', 'Viertelfinale', 'Achtelfinale'];
+ if (levelNumber < names.length) {
+ return names[levelNumber];
+ } else {
+ return Math.pow(2, levelNumber) + 'tel-Finale';
+ }
+}
diff --git a/js/components/Stage.js b/js/components/Stage.js
new file mode 100644
index 0000000..32a128c
--- /dev/null
+++ b/js/components/Stage.js
@@ -0,0 +1,18 @@
+import {Col, Container, Row} from 'reactstrap';
+import {Match} from './Match';
+import React from 'react';
+
+export function Stage(props) {
+ const {isSignedIn, isOwner} = props;
+
+ return (
+
+ {props.level}
+
+ {props.matches.map((match => (
+ )))}
+
+
+
);
+}
diff --git a/js/redux/tournamentApi.js b/js/redux/tournamentApi.js
new file mode 100644
index 0000000..92e7d72
--- /dev/null
+++ b/js/redux/tournamentApi.js
@@ -0,0 +1,100 @@
+import {getRequest} from './backendApi';
+import {getState} from '../api';
+
+export function getTournament(code, successCallback, errorCallback) {
+ getRequest(getState(), '/tournaments/' + code)
+ .then(response => {
+ successCallback(response.status, convertTournament(response.data));
+ })
+ .catch(errorCallback);
+}
+
+export function getGroup(groupId, successCallback, errorCallback) {
+ getRequest(getState(), '/groups/' + groupId)
+ .then(response => {
+ successCallback(response.status, convertGroup(response.data));
+ })
+ .catch(errorCallback);
+}
+
+function convertTournament(apiTournament) {
+ let groupStage = null;
+ const playoffStages = [];
+ for (const stage of apiTournament.stages) {
+ if (stage.groups.length > 0) {
+ // group stage
+ groupStage = {groups: stage.groups.map(group => convertGroup(group))};
+ } else {
+ // playoff stage
+ playoffStages.push({
+ id: stage.id, level: stage.level, matches: stage.matches.map(match => convertMatch(match, false))
+ });
+ }
+ }
+ return {
+ id: apiTournament.id,
+ code: apiTournament.code,
+ description: apiTournament.description,
+ name: apiTournament.name,
+ isPublic: apiTournament.public,
+ ownerUsername: apiTournament.owner_username,
+ groupStage: groupStage,
+ playoffStages: playoffStages
+ };
+}
+
+function convertGroup(apiGroup) {
+ return {
+ id: apiGroup.id,
+ number: apiGroup.number,
+ scores: apiGroup.group_scores,
+ matches: apiGroup.matches.map(match => convertMatch(match, true))
+ };
+}
+
+function convertMatch(apiMatch, allowUndecided) {
+ const result = {
+ id: apiMatch.id, state: apiMatch.state, allowUndecided: allowUndecided,
+ winnerTeamId: apiMatch.winner === null ? null : apiMatch.winner.id
+ };
+
+ if (apiMatch.match_scores.length === 2) {
+ result.team1 = {
+ name: apiMatch.match_scores[0].team.name,
+ id: apiMatch.match_scores[0].team.id,
+ score: apiMatch.match_scores[0].points,
+ scoreId: apiMatch.match_scores[0].id
+ };
+ result.team2 = {
+ name: apiMatch.match_scores[1].team.name,
+ id: apiMatch.match_scores[1].team.id,
+ score: apiMatch.match_scores[1].points,
+ scoreId: apiMatch.match_scores[1].id
+ };
+ } else if (apiMatch.match_scores.length === 1) {
+ result.team1 = {
+ name: apiMatch.match_scores[0].team.name,
+ id: apiMatch.match_scores[0].team.id,
+ score: apiMatch.match_scores[0].points,
+ scoreId: apiMatch.match_scores[0].id
+ };
+ result.team2 = {
+ name: 'TBD',
+ id: null,
+ score: 0
+ };
+ } else {
+ result.team1 = {
+ name: 'TBD',
+ id: null,
+ score: 0
+ };
+ result.team2 = {
+ name: 'TBD',
+ id: null,
+ score: 0
+ };
+ }
+
+ return result;
+}
diff --git a/pages/tournament.js b/pages/tournament.js
index bd0de1b..fcffa8e 100644
--- a/pages/tournament.js
+++ b/pages/tournament.js
@@ -1,25 +1,26 @@
import Head from 'next/head';
import React from 'react';
import {connect} from 'react-redux';
-import {Col, Container, ListGroup, ListGroupItem, Row} from 'reactstrap';
+import {Container, ListGroup, ListGroupItem} from 'reactstrap';
import {ErrorPageComponent} from '../js/components/ErrorComponents';
import {Footer} from '../js/components/Footer';
import {TurniereNavigation} from '../js/components/Navigation';
import {BigImage} from '../js/components/BigImage';
-import {getState} from '../js/api';
-import {getRequest} from '../js/redux/backendApi';
import 'bootstrap/dist/css/bootstrap.min.css';
import '../static/css/everypage.css';
import '../static/css/tournament.css';
-import {Match} from '../js/components/Match';
+import {getTournament} from '../js/redux/tournamentApi';
+import {PlayoffStages} from '../js/components/PlayoffStages';
+import GroupStage from '../js/components/GroupStage';
class PrivateTournamentPage extends React.Component {
render() {
- const {id, description, isPublic, code, ownerUsername, playoffStages} = this.props.tournament;
+ const {id, description, isPublic, code, ownerUsername, playoffStages, groupStage} = this.props.tournament;
const {isSignedIn, username} = this.props;
+ const isOwner = username === ownerUsername;
// TODO: Change href-prop of the anchor tag to contain the tournament code
return (
@@ -35,9 +36,11 @@ class PrivateTournamentPage extends React.Component {
- {playoffStages.map(stage =>
)}
+ {groupStage != null &&
+
}
+
);
}
@@ -60,112 +63,6 @@ function EditButton(props) {
}
}
-function getLevelName(levelNumber) {
- const names = ['Finale', 'Halbfinale', 'Viertelfinale', 'Achtelfinale'];
- if (levelNumber < names.length) {
- return names[levelNumber];
- } else {
- return Math.pow(2, levelNumber) + 'tel-Finale';
- }
-}
-
-function Stage(props) {
- const {isSignedIn, isOwner} = props;
-
- return (
-
- {props.level}
-
- {props.matches.map((match => (
- )))}
-
-
-
);
-}
-
-function convertTournament(apiTournament) {
- let groupStage = null;
- const playoffStages = [];
- for (const stage of apiTournament.stages) {
- if (stage.groups.length > 0) {
- // group stage
- groupStage = {groups: stage.groups.map(group => convertGroup(group))};
- } else {
- // playoff stage
- playoffStages.push({
- id: stage.id, level: stage.level, matches: stage.matches.map(match => convertMatch(match, false))
- });
- }
- }
- return {
- id: apiTournament.id,
- code: apiTournament.code,
- description: apiTournament.description,
- name: apiTournament.name,
- isPublic: apiTournament.public,
- ownerUsername: apiTournament.owner_username,
- groupStage: groupStage,
- playoffStages: playoffStages
- };
-}
-
-function convertGroup(apiGroup) {
- return {
- id: apiGroup.id,
- number: apiGroup.number,
- scores: apiGroup.group_scores,
- matches: apiGroup.matches.map(match => convertMatch(match, true))
- };
-}
-
-function convertMatch(apiMatch, allowUndecided) {
- const result = {
- id: apiMatch.id, state: apiMatch.state, allowUndecided: allowUndecided,
- winnerTeamId: apiMatch.winner === null ? null : apiMatch.winner.id
- };
-
- if (apiMatch.match_scores.length === 2) {
- result.team1 = {
- name: apiMatch.match_scores[0].team.name,
- id: apiMatch.match_scores[0].team.id,
- score: apiMatch.match_scores[0].points,
- scoreId: apiMatch.match_scores[0].id
- };
- result.team2 = {
- name: apiMatch.match_scores[1].team.name,
- id: apiMatch.match_scores[1].team.id,
- score: apiMatch.match_scores[1].points,
- scoreId: apiMatch.match_scores[1].id
- };
- } else if (apiMatch.match_scores.length === 1) {
- result.team1 = {
- name: apiMatch.match_scores[0].team.name,
- id: apiMatch.match_scores[0].team.id,
- score: apiMatch.match_scores[0].points,
- scoreId: apiMatch.match_scores[0].id
- };
- result.team2 = {
- name: 'TBD',
- id: null,
- score: 0
- };
- } else {
- result.team1 = {
- name: 'TBD',
- id: null,
- score: 0
- };
- result.team2 = {
- name: 'TBD',
- id: null,
- score: 0
- };
- }
-
- return result;
-}
-
class Main extends React.Component {
static async getInitialProps({query}) {
return {query};
@@ -177,22 +74,24 @@ class Main extends React.Component {
this.state = {
tournament: null
};
+ this.onTournamentRequestSuccess = this.onTournamentRequestSuccess.bind(this);
+ this.onTournamentRequestError = this.onTournamentRequestError.bind(this);
}
componentDidMount() {
- const code = this.props.query.code;
+ getTournament(this.props.query.code, this.onTournamentRequestSuccess, this.onTournamentRequestError);
+ }
- getRequest(getState(), '/tournaments/' + code)
- .then(response => {
- this.setState({status: response.status, tournament: convertTournament(response.data)});
- })
- .catch(err => {
- if (err.response) {
- this.setState({status: err.response.status});
- } else {
- this.setState({status: -1});
- }
- });
+ onTournamentRequestSuccess(requestStatus, tournament) {
+ this.setState({status: requestStatus, tournament: tournament});
+ }
+
+ onTournamentRequestError(error) {
+ if (error.response) {
+ this.setState({status: error.response.status});
+ } else {
+ this.setState({status: -1});
+ }
}
diff --git a/static/css/everypage.css b/static/css/everypage.css
index 4943630..5c46239 100644
--- a/static/css/everypage.css
+++ b/static/css/everypage.css
@@ -7,6 +7,10 @@
font-family: Halt, sans-serif;
}
+.default-font-family {
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+}
+
.navbar-brand {
font-family: Halt, sans-serif;
font-size: 2em;
@@ -67,4 +71,4 @@ footer {
background: url("/static/images/tennis-blurred.jpg") no-repeat top;
background-size: cover;
min-height: 100vh;
-}
\ No newline at end of file
+}
diff --git a/static/css/tournament.css b/static/css/tournament.css
index b00bdef..63b476a 100644
--- a/static/css/tournament.css
+++ b/static/css/tournament.css
@@ -6,7 +6,7 @@
text-decoration: line-through;
}
-.stages > div:nth-child(odd) {
+.stages > div > div:nth-child(odd) {
background-color: #f8f8f8;
}
@@ -25,4 +25,4 @@
.scoreInput {
width: 11rem;
-}
\ No newline at end of file
+}