diff --git a/.gitignore b/.gitignore index f3be5cb..3d060ad 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /.next/ /node_modules/ -/.idea \ No newline at end of file +/.idea +check-syntax.sh diff --git a/js/CommonComponents.js b/js/CommonComponents.js index 87791dd..b32d412 100644 --- a/js/CommonComponents.js +++ b/js/CommonComponents.js @@ -2,20 +2,27 @@ import { Badge, Button, ButtonGroup, + Card, + CardBody, + Container, Collapse, + Form, + FormGroup, Nav, Navbar, NavbarBrand, NavbarToggler, NavItem, - NavLink + NavLink, + Input, + Label } from 'reactstrap'; import { connect } from 'react-redux'; import React from 'react'; -import { logout } from './api'; +import { login, logout } from './api'; export function BigImage(props) { return ( @@ -95,7 +102,6 @@ class InvisibleLoginLogoutButtons extends React.Component { ); } } - } const mapStateToLoginLogoutButtonProperties = (state) => { @@ -124,3 +130,153 @@ export function Footer() { ); } + +/** + * This component works just like a switch statement, although the conditions of the first items + * are checked first, and the first component with a condition that is true will be shown. + * + * For single conditions and options any kind of component can be taken, while the Option-component + * is dedicated for this job. The only important thing is that this component has to have a condition property. + * + * You should also give a default option with a condition that always evaluates to true. + * + * A quick example would be some content that is only to be shown when the user is logged in: + * + * function SomeRestrictedContent(props) { + * const { isSignedIn } = props; + * + * return ( + * + * + * + * + * ); + * } + * + * In the example you'll have to note that the default option is at the bottom of all the options + * since it would always be taken otherwise (the options' conditions are checked from top to bottom) + */ +export class UserRestrictor extends React.Component { + + render() { + const { children } = this.props; + + for(var i in children) { + var c = children[i]; + + if(c.props.condition) { + return c; + } + } + + return null; + } +} + +export function Option(props) { + return props.children; +} + +export function Login(props) { + return ( + + + +

Login

+ + + +
+
+
+ ); +} + +class LoginErrorList extends React.Component { + render() { + const { error, errorMessages } = this.props; + if(error) { + return ( + + ); + } else { + return null; + } + } +} + +const mapStateToErrorMessages = (state) => { + const { errorMessages, error } = state.userinfo; + return { errorMessages, error }; +}; + +const VisibleLoginErrorList = connect( + mapStateToErrorMessages +)(LoginErrorList); + + +class LoginForm extends React.Component { + + constructor(props) { + super(props); + + this.state = { + email : '', + password : '' + }; + } + + render() { + return ( +
+ + + + + + + + + + + + ); + } + + handlePasswordInput(input) { + this.setState({ password : input.target.value }); + } + + handleEmailInput(input) { + this.setState({ email : input.target.value }); + } +} + +function Hint(props) { + if(props.hint != null) { + return ( +

{ props.hint }

+ ); + } else { + return null; + } +} diff --git a/js/api.js b/js/api.js index 83f281b..92b9753 100644 --- a/js/api.js +++ b/js/api.js @@ -57,6 +57,7 @@ const defaultstate_tournamentinfo = { description : '', id : -1, name : '', + ownerUsername : '', isPublic : '', stages: [], teams : [] @@ -272,6 +273,7 @@ const reducer_tournamentinfo = (state = defaultstate_tournamentinfo, action) => description : action.parameters.description, id : action.parameters.id, name : action.parameters.name, + ownerUsername : action.parameters.owner_username, isPublic : action.parameters.public, stages: action.parameters.stages, teams : action.parameters.teams diff --git a/js/components/ErrorComponents.js b/js/components/ErrorComponents.js index d33190b..2e84ee9 100644 --- a/js/components/ErrorComponents.js +++ b/js/components/ErrorComponents.js @@ -26,7 +26,7 @@ export class ErrorPageComponent extends React.Component { } } -function ErrorPage(props){ +export function ErrorPage(props){ return (
diff --git a/pages/create.js b/pages/create.js index b1606f4..3a25a0b 100644 --- a/pages/create.js +++ b/pages/create.js @@ -1,7 +1,8 @@ import Head from 'next/head'; import '../static/everypage.css'; -import { Footer, TurniereNavigation } from '../js/CommonComponents'; +import { Footer, TurniereNavigation, UserRestrictor, Option, Login } from '../js/CommonComponents'; import React from 'react'; +import { connect } from 'react-redux'; import { Button, @@ -22,28 +23,56 @@ import { import EditableStringList from '../js/EditableStringList'; -export default class CreatePage extends React.Component { +class PrivateCreatePage extends React.Component { componentDidMount() { verifyCredentials(); } render() { + const { isSignedIn } = this.props; + return ( -
- - Turnier erstellen: turnie.re - - -
- -
-
-
+ + + + ); } -} +} +function mapStateToCreatePageProperties(state) { + const { isSignedIn } = state.userinfo; + return { isSignedIn }; +} + +const CreatePage = connect( + mapStateToCreatePageProperties +)(PrivateCreatePage); + +export default CreatePage; function CreateTournamentCard() { return ( diff --git a/pages/login.js b/pages/login.js index 1a58e49..aa43fa5 100644 --- a/pages/login.js +++ b/pages/login.js @@ -1,10 +1,7 @@ import Head from 'next/head'; import '../static/everypage.css'; -import {Footer, TurniereNavigation} from '../js/CommonComponents'; +import { Footer, TurniereNavigation, Login } from '../js/CommonComponents'; import React from 'react'; -import { Button, Card, CardBody, Container, Form, FormGroup, Input, Label } from 'reactstrap'; -import { login } from '../js/api'; -import { connect } from 'react-redux'; import { verifyCredentials @@ -31,92 +28,3 @@ export default class LoginPage extends React.Component { ); } } - -function Login() { - return ( - - - -

Login

- - -
-
-
- ); -} - -class LoginErrorList extends React.Component { - render() { - const { error, errorMessages } = this.props; - if(error) { - return ( -
    - { errorMessages.map((message, index) => -
  • - - {message} -
  • - - ) } -
- ); - } else { - return null; - } - } -} - -const mapStateToErrorMessages = (state) => { - const { errorMessages, error } = state.userinfo; - return { errorMessages, error }; -}; - -const VisibleLoginErrorList = connect( - mapStateToErrorMessages -)(LoginErrorList); - - -class LoginForm extends React.Component { - - constructor(props) { - super(props); - - this.state = { - email : '', - password : '' - }; - } - - render() { - return ( -
- - - - - - - - - - - - ); - } - - handlePasswordInput(input) { - this.setState({ password : input.target.value }); - } - - handleEmailInput(input) { - this.setState({ email : input.target.value }); - } -} \ No newline at end of file diff --git a/pages/tournament-edit.js b/pages/tournament-edit.js index 0c89d91..1d147c1 100644 --- a/pages/tournament-edit.js +++ b/pages/tournament-edit.js @@ -5,7 +5,7 @@ import { connect } from 'react-redux'; import { notify } from 'react-notify-toast'; import { requestTournament } from '../js/api'; -import { BigImage, Footer, TurniereNavigation } from '../js/CommonComponents.js'; +import { BigImage, Footer, TurniereNavigation, Login, UserRestrictor, Option } from '../js/CommonComponents.js'; import { ErrorPageComponent } from '../js/components/ErrorComponents.js'; import { @@ -34,7 +34,7 @@ class EditTournamentPage extends React.Component { super(props); this.state = { - validCode: true + validCode: false }; } @@ -42,7 +42,10 @@ class EditTournamentPage extends React.Component { verifyCredentials(); requestTournament(this.props.query.code, () => { this.setState({ validCode: true }); - this._edittournamentcontent.notifyOfContentUpdate(); + + if(this._edittournamentcontent != null) { + this._edittournamentcontent.notifyOfContentUpdate(); + } }, () => { this.setState({ validCode: false }); }); @@ -50,33 +53,50 @@ class EditTournamentPage extends React.Component { render() { const { validCode } = this.state; - const { name } = this.props; + const { tournamentname, ownerUsername, isSignedIn, username } = this.props; - if(validCode) { - return ( -
- - Turnie.re - Turnier bearbeiten - - - + return ( + +
+ + + + + + ); } } function mapStateToTournamentInfo(state) { - const { name } = state.tournamentinfo; - return { name }; + const { tournamentname, ownerUsername } = state.tournamentinfo; + const { isSignedIn, username } = state.userinfo; + return { tournamentname, ownerUsername, isSignedIn, username }; } export default connect( diff --git a/pages/tournament.js b/pages/tournament.js index 40753f5..779a0ba 100644 --- a/pages/tournament.js +++ b/pages/tournament.js @@ -18,10 +18,12 @@ import { Row, Table } from 'reactstrap'; +import { ErrorPageComponent } from '../js/components/ErrorComponents.js'; import 'bootstrap/dist/css/bootstrap.min.css'; import {BigImage, Footer, TurniereNavigation} from '../js/CommonComponents.js'; import '../static/everypage.css'; import '../static/css/tournament.css'; +import { connect } from 'react-redux'; import { getRequest, @@ -38,7 +40,7 @@ class TournamentPage extends React.Component { return (
- Turnier bearbeiten +

{description}

@@ -57,6 +59,27 @@ class TournamentPage extends React.Component { } } +function PrivateEditButton(props) { + const { id, ownerName, isSignedIn, username } = props; + + if(isSignedIn && ownerName === username) { + return ( + Turnier bearbeiten + ); + } else { + return null; + } +} + +function mapStateToEditButtonProperties(state) { + const { isSignedIn, username } = state.userinfo; + return { isSignedIn, username }; +} + +const EditButton = connect( + mapStateToEditButtonProperties +)(PrivateEditButton); + function getLevelName(levelNumber) { const names = ['Finale', 'Halbfinale', 'Viertelfinale', 'Achtelfinale']; if(levelNumber < names.length){ @@ -66,16 +89,6 @@ function getLevelName(levelNumber) { } } -function TournamentContainer(props) { - const { tournament } = props.data; - - if (tournament === null) { - return null; - } else { - return ; - } -} - function Stage(props) { return (
@@ -371,25 +384,34 @@ class Main extends React.Component { getRequest(getState(), '/tournaments/' + code) .then(response => { - this.setState({tournament: convertTournament(response.data)}); + this.setState({ status : response.status, tournament : convertTournament(response.data)}); }) - .catch(() => { /* TODO: Show some kind of error or smth */ }); + .catch((err) => { + this.setState({ status : err.response.status }); + }); } render() { const tournamentName = this.state.tournament === null ? 'Turnier' : this.state.tournament.name; - return ( -
- - {tournamentName}: turnie.re - - - - -
-
- ); + + const { status, tournament } = this.state; + + if (status == 200) { + return ( +
+ + {tournamentName}: turnie.re + + + + +
+
+ ); + } else { + return ; + } } }