Merge branch 'master' into ticket/TURNIERE-138

This commit is contained in:
Felix Hamme 2019-04-16 11:23:11 +02:00
commit 8b32604f7e
14 changed files with 164 additions and 102 deletions

View File

@ -21,6 +21,8 @@ const actiontypes_userinfo = {
'LOGIN_RESULT_SUCCESS' : 'LOGIN_RESULT_SUCCESS',
'LOGIN_RESULT_ERROR' : 'LOGIN_RESULT_ERROR',
'CLEAR_ERRORS' : 'CLEAR_ERRORS',
'LOGOUT' : 'LOGOUT',
'VERIFY_CREDENTIALS' : 'VERIFY_CREDENTIALS',
@ -49,6 +51,8 @@ const actiontypes_tournamentinfo = {
'REQUEST_TOURNAMENT' : 'REQUEST_TOURNAMENT',
'REQUEST_TOURNAMENT_SUCCESS' : 'REQUEST_TOURNAMENT_SUCCESS',
'CREATE_TOURNAMENT' : 'CREATE_TOURNAMENT',
'MODIFY_TOURNAMENT' : 'MODIFY_TOURNAMENT',
'MODIFY_TOURNAMENT_SUCCESS' : 'MODIFY_TOURNAMENT_SUCCESS',
'MODIFY_TOURNAMENT_ERROR' : 'MODIFY_TOURNAMENT_ERROR',
@ -219,6 +223,11 @@ const reducer_userinfo = (state = defaultstate_userinfo, action) => {
error : true,
errorMessages : action.parameters.errorMessages
});
case actiontypes_userinfo.CLEAR_ERRORS:
return Object.assign({}, state, {
error : false,
errorMessages : []
});
case actiontypes_userinfo.LOGOUT:
deleteRequest(action.state, '/users/sign_out').then(() => {
__store.dispatch({ type : actiontypes_userinfo.CLEAR });
@ -260,6 +269,14 @@ const reducer_userinfo = (state = defaultstate_userinfo, action) => {
const reducer_tournamentinfo = (state = defaultstate_tournamentinfo, action) => {
switch(action.type) {
case actiontypes_tournamentinfo.CREATE_TOURNAMENT:
postRequest(action.state, '/tournaments', action.parameters.tournament).then((resp) => {
storeOptionalToken(resp);
action.parameters.successCallback();
}).catch(() => {
action.parameters.errorCallback();
});
return Object.assign({}, state, {});
case actiontypes_tournamentinfo.REQUEST_TOURNAMENT:
getRequest(action.state, '/tournaments/' + action.parameters.code).then((resp) => {
__store.dispatch({
@ -302,7 +319,6 @@ const reducer_tournamentinfo = (state = defaultstate_tournamentinfo, action) =>
case actiontypes_tournamentinfo.MODIFY_TOURNAMENT_ERROR:
return Object.assign({}, state, {});
case actiontypes_tournamentinfo.REHYDRATE:
return Object.assign({}, state, {});
@ -348,6 +364,12 @@ export function verifyCredentials() {
}
}
export function clearErrors() {
__store.dispatch({
type: actiontypes_userinfo.CLEAR_ERRORS
});
}
export function register(username, email, password) {
__store.dispatch({
type: actiontypes_userinfo.REGISTER,
@ -378,6 +400,18 @@ export function logout() {
});
}
export function createTournament(data, successCallback, errorCallback) {
__store.dispatch({
type: actiontypes_tournamentinfo.CREATE_TOURNAMENT,
parameters: {
tournament: data,
successCallback: successCallback,
errorCallback: errorCallback
},
state: __store.getState()
});
}
export function requestTournament(code, successCallback, errorCallback) {
__store.dispatch({
type: actiontypes_tournamentinfo.REQUEST_TOURNAMENT,
@ -423,7 +457,3 @@ function rehydrateApplicationState() {
});
}
}

View File

@ -3,7 +3,10 @@ import React from 'react';
import {connect} from 'react-redux';
import Router from 'next/router';
import {login} from '../api';
import {
login,
clearErrors
} from '../api';
export function Login(props) {
return (
@ -84,6 +87,10 @@ class LoginForm extends React.Component {
};
}
componentDidMount() {
clearErrors();
}
tryLogin(event) {
event.preventDefault();
login(this.state.email, this.state.password);

View File

@ -1,13 +1,18 @@
import App, { Container } from 'next/app';
import React from 'react';
import { Provider } from 'react-redux';
import Notifications from 'react-notify-toast';
import Favicon from 'react-favicon';
import App, { Container } from 'next/app';
import React from 'react';
import { Provider } from 'react-redux';
import Notifications from 'react-notify-toast';
import Favicon from 'react-favicon';
import withReduxStore from '../js/redux/reduxStoreBinder';
import withReduxStore from '../js/redux/reduxStoreBinder';
import { verifyCredentials } from '../js/api.js';
class TurniereApp extends App {
componentDidMount() {
verifyCredentials();
}
render () {
const {Component, pageProps, reduxStore} = this.props;
return (

View File

@ -1,5 +1,6 @@
import Head from 'next/head';
import React from 'react';
import { notify } from 'react-notify-toast';
import { connect } from 'react-redux';
import {
@ -19,17 +20,13 @@ import { TurniereNavigation } from '../js/components/Navigation';
import { Footer } from '../js/components/Footer';
import { UserRestrictor, Option } from '../js/components/UserRestrictor';
import { Login } from '../js/components/Login';
import { verifyCredentials } from '../js/api';
import EditableStringList from '../js/components/EditableStringList';
import { createTournament } from '../js/api';
import '../static/everypage.css';
class PrivateCreatePage extends React.Component {
componentDidMount() {
verifyCredentials();
}
render() {
const { isSignedIn } = this.props;
@ -91,9 +88,22 @@ function CreateTournamentCard() {
class CreateTournamentForm extends React.Component {
constructor(props) {
super(props);
this.state = {fadeIn: false, teams: []};
this.state = {
fadeIn: false,
name: '',
description: '',
public: false,
teams: []
};
this.toggle = this.toggle.bind(this);
this.teamListUpdate = this.teamListUpdate.bind(this);
this.create = this.create.bind(this);
this.handleNameInput = this.handleNameInput.bind(this);
this.handleDescriptionInput = this.handleDescriptionInput.bind(this);
this.handlePublicInput = this.handlePublicInput.bind(this);
this.create = this.create.bind(this);
}
render() {
@ -102,15 +112,15 @@ class CreateTournamentForm extends React.Component {
<Form>
<FormGroup>
<Label for="name">Name des Turniers</Label>
<Input type="text" name="name" size="255" required/>
<Input type="text" name="name" size="255" required value={this.state.name} onChange={this.handleNameInput}/>
</FormGroup>
<FormGroup>
<Label for="description">Beschreibung (optional)</Label>
<Input type="text" name="description" size="255"/>
<Input type="text" name="description" size="255" value={this.state.description} onChange={this.handleDescriptionInput}/>
</FormGroup>
<FormGroup>
<CustomInput type="checkbox" id="public"
label="Turnier öffentlich anzeigen (schreibgeschützt)"/>
label="Turnier öffentlich anzeigen (schreibgeschützt)" checked={this.state.public} onChange={this.handlePublicInput}/>
<CustomInput type="checkbox" id="mix-teams" label="Teams mischen"/>
<CustomInput type="checkbox" id="group-phase" label="Gruppenphase" onClick={this.toggle}/>
</FormGroup>
@ -130,7 +140,7 @@ class CreateTournamentForm extends React.Component {
<h3 className="custom-font mt-4">Teams</h3>
<EditableStringList addButtonText="hinzufügen" placeholder="Keine Teams hinzugefügt!" entries={[]}
onChange={this.teamListUpdate} inputPlaceholder="Teamname"/>
<Button color="success" size="lg" className="w-100 shadow-sm mt-4">Turnier erstellen</Button>
<Button color="success" size="lg" className="w-100 shadow-sm mt-4" onClick={this.create}>Turnier erstellen</Button>
</div>
);
}
@ -144,4 +154,39 @@ class CreateTournamentForm extends React.Component {
fadeIn: !this.state.fadeIn
});
}
}
handleNameInput(input) {
this.setState({ name: input.target.value });
}
handleDescriptionInput(input) {
this.setState({ description: input.target.value });
}
handlePublicInput(input) {
this.setState({ public: input.target.checked });
}
create() {
createTournament({
'name': this.state.name,
'description': this.state.description,
'public': this.state.public,
'teams': this.createTeamArray(this.state.teams)
}, () => {
notify.show('Das Turnier wurde erfolgreich erstellt.', 'success', 5000);
}, () => {
notify.show('Das Turnier konnte nicht erstellt werden.', 'warning', 5000);
});
}
createTeamArray(teamnames) {
var result = [];
for(var i = 0; i < teamnames.length; i++) {
result[i] = { 'name': teamnames[i] };
}
return result;
}
}

View File

@ -5,7 +5,6 @@ import { Col, Container, Row } from 'reactstrap';
import { TurniereNavigation } from '../js/components/Navigation';
import { BigImage } from '../js/components/BigImage';
import { Footer } from '../js/components/Footer';
import { verifyCredentials } from '../js/api';
import 'bootstrap/dist/css/bootstrap.min.css';
@ -224,10 +223,6 @@ function TournamentFaq() {
export default class FaqPage extends React.Component {
componentDidMount() {
verifyCredentials();
}
render() {
return (
<div>

View File

@ -5,7 +5,6 @@ import { Container } from 'reactstrap';
import { TurniereNavigation } from '../js/components/Navigation';
import { BigImage } from '../js/components/BigImage';
import { Footer } from '../js/components/Footer';
import { verifyCredentials } from '../js/api';
import 'bootstrap/dist/css/bootstrap.min.css';
import '../static/everypage.css';
@ -76,10 +75,6 @@ function ImprintText(){
export default class ImprintPage extends React.Component {
componentDidMount() {
verifyCredentials();
}
render() {
return (
<div>

View File

@ -11,9 +11,6 @@ import {
import { TurniereNavigation } from '../js/components/Navigation';
import { BigImage } from '../js/components/BigImage';
import { Footer } from '../js/components/Footer';
import {
verifyCredentials
} from '../js/api';
import 'bootstrap/dist/css/bootstrap.min.css';
@ -174,10 +171,6 @@ function PromotedLinkCreateTournament() {
class Index extends React.Component {
componentDidMount() {
verifyCredentials();
}
render () {
return (
<div>

View File

@ -10,17 +10,12 @@ import { TurniereNavigation } from '../js/components/Navigation';
import { Footer } from '../js/components/Footer';
import {
getRequest,
getState,
verifyCredentials
getState
} from '../js/api';
import '../static/everypage.css';
export default class ListPage extends React.Component {
componentDidMount() {
verifyCredentials();
}
render() {
return (

View File

@ -4,16 +4,11 @@ import React from 'react';
import { TurniereNavigation } from '../js/components/Navigation';
import { Footer } from '../js/components/Footer';
import { Login } from '../js/components/Login';
import { verifyCredentials } from '../js/api';
import '../static/everypage.css';
export default class LoginPage extends React.Component {
componentDidMount() {
verifyCredentials();
}
render() {
return (
<div className="main generic-fullpage-bg">

View File

@ -5,7 +5,6 @@ import { Container } from 'reactstrap';
import { TurniereNavigation } from '../js/components/Navigation';
import { BigImage } from '../js/components/BigImage';
import { Footer } from '../js/components/Footer';
import { verifyCredentials } from '../js/api';
import 'bootstrap/dist/css/bootstrap.min.css';
@ -496,10 +495,6 @@ function PrivacyText(){
export default class PrivacyPage extends React.Component {
componentDidMount() {
verifyCredentials();
}
render() {
return (
<div>

View File

@ -15,17 +15,15 @@ import {
import { TurniereNavigation } from '../js/components/Navigation';
import { Footer } from '../js/components/Footer';
import { register } from '../js/api';
import { verifyCredentials } from '../js/api';
import {
register,
clearErrors
} from '../js/api';
import '../static/everypage.css';
export default class RegisterPage extends React.Component {
componentDidMount() {
verifyCredentials();
}
render() {
return (
<div className="main generic-fullpage-bg">
@ -43,20 +41,27 @@ export default class RegisterPage extends React.Component {
}
}
function Register() {
return (
<Container className="py-5">
<Card className="shadow">
<CardBody>
<h1 className="custom-font">Account anlegen</h1>
<RegisterForm/>
<div className="mt-3">
<a href="/login" className="mr-3">Ich habe bereits einen Account!</a>
</div>
</CardBody>
</Card>
</Container>
);
class Register extends React.Component {
componentDidMount() {
clearErrors();
}
render() {
return (
<Container className="py-5">
<Card className="shadow">
<CardBody>
<h1 className="custom-font">Account anlegen</h1>
<RegisterForm/>
<div className="mt-3">
<a href="/login" className="mr-3">Ich habe bereits einen Account!</a>
</div>
</CardBody>
</Card>
</Container>
);
}
}
class RegisterErrorList extends React.Component {
@ -156,4 +161,4 @@ function AccountRequirementMarketing() {
</Card>
</Container>
);
}
}

View File

@ -17,10 +17,7 @@ import { UserRestrictor, Option } from '../js/components/UserRestrictor';
import { Footer } from '../js/components/Footer';
import { Login } from '../js/components/Login';
import { ErrorPageComponent } from '../js/components/ErrorComponents';
import {
verifyCredentials,
updateTeamName
} from '../js/api';
import { updateTeamName } from '../js/api';
import 'bootstrap/dist/css/bootstrap.min.css';
@ -42,7 +39,6 @@ class EditTournamentPage extends React.Component {
}
componentDidMount() {
verifyCredentials();
requestTournament(this.props.query.code, () => {
this.setState({ validCode: true });

View File

@ -1,19 +1,11 @@
import Head from 'next/head';
import React from 'react';
import {
verifyCredentials
} from '../js/api';
class FullscreenTournamentPage extends React.Component {
static async getInitialProps({query}) {
return {query};
}
componentDidMount() {
verifyCredentials();
}
render() {
return (

View File

@ -26,8 +26,7 @@ import { TurniereNavigation } from '../js/components/Navigation';
import { BigImage } from '../js/components/BigImage';
import {
getRequest,
getState,
verifyCredentials
getState
} from '../js/api';
import 'bootstrap/dist/css/bootstrap.min.css';
@ -95,12 +94,14 @@ function getLevelName(levelNumber) {
}
function Stage(props) {
const { isSignedIn, isOwner } = props;
return (<div>
<Container className='py-5'>
<h1 className='custom-font'>{props.level}</h1>
<Row>
{props.matches.map((match => (
<Col className='minw-25' key={match.id}><Match match={match}/></Col>
<Col className='minw-25' key={match.id}><Match match={match} isSignedIn={isSignedIn} isOwner={isOwner}/></Col>
)))}
</Row>
</Container>
@ -345,7 +346,7 @@ function convertTournament(apiTournament) {
code: apiTournament.code,
description: apiTournament.description,
name: apiTournament.name,
public: apiTournament.public,
isPublic: apiTournament.public,
ownerUsername: apiTournament.owner_username,
groupStage: groupStage,
playoffStages: playoffStages
@ -362,14 +363,29 @@ function convertGroup(apiGroup) {
}
function convertMatch(apiMatch) {
return {
var result = {
id: apiMatch.id,
state: apiMatch.state,
team1: apiMatch.match_scores[0].team.name,
team2: apiMatch.match_scores[1].team.name,
scoreTeam1: apiMatch.match_scores[0].points,
scoreTeam2: apiMatch.match_scores[1].points
state: apiMatch.state
};
if(apiMatch.match_scores.length == 2) {
result.team1 = apiMatch.match_scores[0].team.name;
result.scoreTeam1 = apiMatch.match_scores[0].points;
result.team2 = apiMatch.match_scores[1].team.name;
result.scoreTeam2 = apiMatch.match_scores[1].points;
} else if(apiMatch.match_scores.length == 1) {
result.team1 = apiMatch.match_scores[0].team.name;
result.scoreTeam1 = apiMatch.match_scores[0].points;
result.team2 = 'TBD';
result.scoreTeam2 = 0;
} else {
result.team1 = 'TBD';
result.scoreTeam1 = 0;
result.team2 = 'TBD';
result.scoreTeam2 = 0;
}
return result;
}
class Main extends React.Component {
@ -387,8 +403,6 @@ class Main extends React.Component {
}
componentDidMount() {
verifyCredentials();
const code = this.props.query.code;
getRequest(getState(), '/tournaments/' + code)