diff --git a/js/api.js b/js/api.js index 7d5c8d6..7d81418 100644 --- a/js/api.js +++ b/js/api.js @@ -40,6 +40,28 @@ const defaultstate_userinfo = { uid : null }; +const actiontypes_tournamentinfo = { + 'REQUEST_TOURNAMENT' : 'REQUEST_TOURNAMENT', + 'REQUEST_TOURNAMENT_SUCCESS' : 'REQUEST_TOURNAMENT_SUCCESS', + + 'MODIFY_TOURNAMENT' : 'MODIFY_TOURNAMENT', + 'MODIFY_TOURNAMENT_SUCCESS' : 'MODIFY_TOURNAMENT_SUCCESS', + 'MODIFY_TOURNAMENT_ERROR' : 'MODIFY_TOURNAMENT_ERROR', + + 'REHYDRATE' : 'TOURNAMENTINFO_REHYDRATE', + 'CLEAR' : 'TOURNAMENTINFO_CLEAR', +}; + +const defaultstate_tournamentinfo = { + code : '', + description : '', + id : -1, + name : '', + isPublic : '', + stages: [], + teams : [] +} + export function postRequest(state, url, data) { return axios.post(api_url + url, data, { headers : generateHeaders(state) @@ -58,6 +80,9 @@ export function deleteRequest(state, url) { }); } +// PATCH /teams/{ id } +// { 'name' : ... } + function generateHeaders(state) { if(state.userinfo.isSignedIn) { return { @@ -224,12 +249,59 @@ const reducer_userinfo = (state = defaultstate_userinfo, action) => { } }; +const reducer_tournamentinfo = (state = defaultstate_tournamentinfo, action) => { + switch(action.type) { + case actiontypes_tournamentinfo.REQUEST_TOURNAMENT: + getRequest(action.state, '/tournaments/' + action.parameters.code).then((resp) => { + __store.dispatch({ + type: actiontypes_tournamentinfo.REQUEST_TOURNAMENT_SUCCESS, + parameters: resp.data + }); + storeOptionalToken(resp); + action.parameters.successCallback(); + }).catch((error) => { + console.log(error); + action.parameters.errorCallback(); + }); + return Object.assign({}, state, {}); + case actiontypes_tournamentinfo.REQUEST_TOURNAMENT_SUCCESS: + return Object.assign({}, state, { + code : action.parameters.code, + description : action.parameters.description, + id : action.parameters.id, + name : action.parameters.name, + isPublic : action.parameters.public, + stages: action.parameters.stages, + teams : action.parameters.teams + }); + case actiontypes_tournamentinfo.MODIFY_TOURNAMENT: + + return Object.assign({}, state, {}); + case actiontypes_tournamentinfo.MODIFY_TOURNAMENT_SUCCESS: + + return Object.assign({}, state, {}); + case actiontypes_tournamentinfo.MODIFY_TOURNAMENT_ERROR: + + return Object.assign({}, state, {}); + + case actiontypes_tournamentinfo.REHYDRATE: + + return Object.assign({}, state, {}); + case actiontypes_tournamentinfo.CLEAR: + + return Object.assign({}, state, {}); + default: return state; + } +} + const reducers = { - userinfo: reducer_userinfo + userinfo: reducer_userinfo, + tournamentinfo: reducer_tournamentinfo }; const default_applicationstate = { - userinfo : defaultstate_userinfo + userinfo : defaultstate_userinfo, + tournamentinfo: defaultstate_tournamentinfo }; var __store; @@ -287,6 +359,18 @@ export function logout() { }); } +export function requestTournament(code, successCallback, errorCallback) { + __store.dispatch({ + type: actiontypes_tournamentinfo.REQUEST_TOURNAMENT, + parameters: { + code: code, + successCallback: successCallback, + errorCallback: errorCallback + }, + state: __store.getState() + }); +} + function rehydrateApplicationState() { const persistedState = localStorage.getItem('reduxState') ? JSON.parse(localStorage.getItem('reduxState')) : @@ -297,6 +381,10 @@ function rehydrateApplicationState() { type : actiontypes_userinfo.REHYDRATE, parameters : Object.assign({}, persistedState.userinfo, {}) }); + __store.dispatch({ + type : actiontypes_tournamentinfo.REHYDRATE, + parameters : Object.assign({}, persistedState.tournamentinfo, {}) + }); } } diff --git a/js/components/ErrorComponents.js b/js/components/ErrorComponents.js new file mode 100644 index 0000000..d33190b --- /dev/null +++ b/js/components/ErrorComponents.js @@ -0,0 +1,86 @@ +import Head from 'next/head'; +import React from 'react'; +import {Footer, TurniereNavigation} from '../CommonComponents'; +import 'bootstrap/dist/css/bootstrap.min.css'; +import {Container} from 'reactstrap'; +import '../../static/everypage.css'; +import '../../static/css/error.css'; + +export class ErrorPageComponent extends React.Component { + + static getInitialProps({ statusCode }) { + return { statusCode }; + } + + render() { + return ( +
+ + turnie.re - Error {this.props.statusCode} + + + +
+ ); + } +} + +function ErrorPage(props){ + return ( + +
+
+ +
+
+

{props.statusCode}

+
+
+ +
+ ); +} + +function ErrorMessage(props) { + switch (props.code) { + case 400: + return (
+

Deine Anfrage ist fehlerhaft.

+

+ Wir empfehlen, die eingegebene Seite über die Startseite zu suchen. +

+
); + case 403: + return (
+

Du bist nicht autorisiert, diese Seite aufzurufen.

+

+ Bitte stelle sicher, dass Du angemeldet bist und auf dieses Turnier oder dieses Match zugreifen darfst. +

+

+ Wir empfehlen, die eingegebene Seite über die Startseite zu suchen. +

+
); + case 404: + return (
+

Die aufgerufene Seite wurde leider nicht gefunden.

+

+ Entweder hast Du dich vertippt, oder die gesuchte Seite gibt es nicht. +

+

+ Wir empfehlen, die eingegebene Seite über die Startseite zu suchen. +

+
); + case 500: + return (
+

Diese Seite funktioniert nicht.

+

+ turnie.re kann Deine Anfrage im Moment nicht verarbeiten. Bitte versuche es später erneut. +

+
); + default: + return (
+

Ein unbekannter Fehler ist aufgetreten.

+
); + } +} diff --git a/pages/_error.js b/pages/_error.js index 202f1ca..0a1bf26 100644 --- a/pages/_error.js +++ b/pages/_error.js @@ -1,10 +1,4 @@ -import Head from 'next/head'; -import React from 'react'; -import {Footer, TurniereNavigation} from '../js/CommonComponents'; -import 'bootstrap/dist/css/bootstrap.min.css'; -import {Container} from 'reactstrap'; -import '../static/everypage.css'; -import '../static/css/error.css'; +import { ErrorPageComponent } from '../js/components/ErrorComponents.js'; export default class Error extends React.Component { static getInitialProps({ res, err }) { @@ -14,73 +8,7 @@ export default class Error extends React.Component { render() { return ( -
- - turnie.re - Error {this.props.statusCode} - - - -
+ ); } } - -function ErrorPage(props){ - return ( - -
-
- -
-
-

{props.statusCode}

-
-
- -
- ); -} - -function ErrorMessage(props) { - switch (props.code) { - case 400: - return (
-

Deine Anfrage ist fehlerhaft.

-

- Wir empfehlen, die eingegebene Seite über die Startseite zu suchen. -

-
); - case 403: - return (
-

Du bist nicht autorisiert, diese Seite aufzurufen.

-

- Bitte stelle sicher, dass Du angemeldet bist und auf dieses Turnier oder dieses Match zugreifen darfst. -

-

- Wir empfehlen, die eingegebene Seite über die Startseite zu suchen. -

-
); - case 404: - return (
-

Die aufgerufene Seite wurde leider nicht gefunden.

-

- Entweder hast Du dich vertippt, oder die gesuchte Seite gibt es nicht. -

-

- Wir empfehlen, die eingegebene Seite über die Startseite zu suchen. -

-
); - case 500: - return (
-

Diese Seite funktioniert nicht.

-

- turnie.re kann Deine Anfrage im Moment nicht verarbeiten. Bitte versuche es später erneut. -

-
); - default: - return (
-

Ein unbekannter Fehler ist aufgetreten.

-
); - } -} \ No newline at end of file diff --git a/pages/index.js b/pages/index.js index dee8a02..7d043df 100644 --- a/pages/index.js +++ b/pages/index.js @@ -114,7 +114,7 @@ function PromotedLinkTournamentCode() {
- +

Gib hier einen Turnier Code ein, um direkt zum entsprechenden Turnier zu gelangen.

diff --git a/pages/tournament-edit.js b/pages/tournament-edit.js new file mode 100644 index 0000000..5545c22 --- /dev/null +++ b/pages/tournament-edit.js @@ -0,0 +1,273 @@ +import Head from 'next/head'; +import React from 'react'; + +import { requestTournament } from '../js/api'; +import { BigImage, Footer, TurniereNavigation } from '../js/CommonComponents.js'; +import { ErrorPageComponent } from '../js/components/ErrorComponents.js'; + +import { + Container, + Button, + Card, + CardBody, + CardTitle, + Table +} from 'reactstrap'; + +import { connect } from 'react-redux'; + +import '../static/everypage.css'; +import '../static/css/index.css'; + +class EditTournamentPage extends React.Component { + + static async getInitialProps({query}) { + return {query}; + } + + constructor(props) { + super(props); + + this.state = { + validCode: true + }; + } + + componentDidMount() { + requestTournament(this.props.query.code, () => { + this.setState({ validCode: true }); + this._edittournamentcontent.notifyOfContentUpdate(); + }, () => { + this.setState({ validCode: false }); + }); + } + + render() { + const { validCode } = this.state; + const { name } = this.props; + + if(validCode) { + return ( +
+ + Turnie.re - Turnier bearbeiten + + + + + { this._edittournamentcontent = edittournamentcontent; }}/> + +
+
+ ); + } else { + return ( + + ); + } + } +} + +function mapStateToTournamentInfo(state) { + const { name } = state.tournamentinfo; + return { name }; +} + +export default connect( + mapStateToTournamentInfo +)(EditTournamentPage); + +class EditTournamentContent extends React.Component { + + render() { + const { code } = this.props; + + return ( +
+ + { this._edittournamentpropertiesfield = field; }}/> + { this._editteamfield = field; }}/> +
+ ); + } + + notifyOfContentUpdate() { + this._edittournamentpropertiesfield.notifyOfContentUpdate(); + this._editteamfield.notifyOfContentUpdate(); + } +} + +function ReturnToTournamentButton() { + return ( + + + + ); +} + +class EditTournamentPropertiesField extends React.Component { + + render() { + return ( + + +

Turnier-Eigenschaften ändern

+ { this._visibleedittournamentform = form; }}/> +
+
+ ); + } + + notifyOfContentUpdate() { + this._visibleedittournamentform.getWrappedInstance().notifyOfContentUpdate(); + } +} + +class EditTournamentForm extends React.Component { + + constructor(props) { + super(props); + + this.state = { + name : '', + description : '', + isPublic : false + }; + } + + render() { + const { name, description, isPublic } = this.state; + + return ( +
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+
+
+ ); + } + + notifyOfContentUpdate() { + const { name, description, isPublic } = this.props; + + this.setState({ + name : name? name : '', + description : description? description : '', + isPublic : isPublic + }); + } + + handleClick(input) { + // TODO: Apply changes to the tournament properties + } + + handleNameInput(input) { + this.setState({ name : input.target.value }); + } + + handleDescriptionInput(input) { + this.setState({ description : input.target.value }); + } + + handlePublicInput(input) { + this.setState({ public : input.target.value }); + } +} + +function mapStateToTournamentFormProps(state) { + const { name, description, isPublic } = state.tournamentinfo; + return { name, description, isPublic }; +} + +const VisibleEditTournamentForm = connect( + mapStateToTournamentFormProps, + null, null, { withRef : true} +)(EditTournamentForm); + +class EditTeamField extends React.Component { + + render() { + return ( + + +

Team-Namen ändern

+ { this._visibleeditteamnamesform = form; }}/> +
+
+ ); + } + + notifyOfContentUpdate() { + this._visibleeditteamnamesform.getWrappedInstance().notifyOfContentUpdate(); + } +} + +class EditTeamNamesForm extends React.Component { + + constructor(props) { + super(props); + + this.state = { + teams : [] + }; + } + + render() { + const { teams } = this.state; + + return ( +
+ + + { + teams.map((team, index) => { + + }) + } + +
+
+ ); + } + + notifyOfContentUpdate() { + const { teams } = this.props; + + this.setState({ + teams : teams + }); + } + + handleClick(input) { + // TODO: Apply changes to the tournament properties + } + + handleNameInput(input) { + this.setState({ name : input.target.value }); + } +} + +function mapStateToTeamFormProps(state) { + const { teams } = state.tournamentinfo; + return { teams }; +} + +const VisibleEditTeamNamesForm = connect( + mapStateToTeamFormProps, + null, null, { withRef : true } +)(EditTeamNamesForm); + diff --git a/server.js b/server.js index daccc7d..188d268 100644 --- a/server.js +++ b/server.js @@ -8,7 +8,7 @@ const handle = app.getRequestHandler(); app.prepare() .then(() => { const server = express(); - + server.get('/t/:code', (req, res) => { const actualPage = '/tournament'; const queryParam = { code: req.params.code }; @@ -21,6 +21,12 @@ app.prepare() app.render(req, res, actualPage, queryParam); }); + server.get('/t/:code/edit', (req, res) => { + const actualPage = '/tournament-edit'; + const queryParam = { code: req.params.code }; + app.render(req, res, actualPage, queryParam); + }); + server.get('*', (req, res) => { return handle(req, res); }); diff --git a/static/css/index.css b/static/css/index.css index 0ae4d38..665ccab 100644 --- a/static/css/index.css +++ b/static/css/index.css @@ -1,4 +1,8 @@ .index-cards { background: url("/static/images/tennis-blurred.jpg") no-repeat center; background-size: cover; +} + +h2, h3, h4 { + font-family: Halt, sans-serif; } \ No newline at end of file