From 0b35c6c84da0b55b23a60046a9a8fefc1a864037 Mon Sep 17 00:00:00 2001 From: Felix Hamme Date: Wed, 17 Apr 2019 09:59:09 +0200 Subject: [PATCH 1/7] Begin implementing page for private tournaments --- js/api.js | 84 ++++++++++++++++++++++++++++-- pages/private.js | 130 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 211 insertions(+), 3 deletions(-) create mode 100644 pages/private.js diff --git a/js/api.js b/js/api.js index a065064..0db5c10 100644 --- a/js/api.js +++ b/js/api.js @@ -32,7 +32,7 @@ const actiontypes_userinfo = { 'STORE_AUTH_HEADERS' : 'STORE_AUTH_HEADERS', 'REHYDRATE' : 'USERINFO_REHYDRATE', - 'CLEAR' : 'USERINFO_CLEAR', + 'CLEAR' : 'USERINFO_CLEAR' }; const defaultstate_userinfo = { @@ -72,6 +72,17 @@ const defaultstate_tournamentinfo = { teams : [] }; +const actiontypes_tournamentlist = { + 'FETCH': 'FETCH', + 'FETCH_SUCCESS': 'FETCH_SUCCESS', + 'FETCH_ERROR': 'FETCH_ERROR', + 'REHYDRATE': 'REHYDRATE' +}; + +const defaultstate_tournamentlist = { + tournaments: [] +}; + export function postRequest(state, url, data) { return axios.post(api_url + url, data, { headers : generateHeaders(state) @@ -263,6 +274,27 @@ const reducer_userinfo = (state = defaultstate_userinfo, action) => { expiry : null, uid : null }); + case actiontypes_userinfo.GET_TOURNAMENT_LIST: + getRequest(action.state, '/tournaments?type=' + action.parameters.type).then((resp) => { + __store.dispatch({ + type: actiontypes_tournamentinfo.GET_TOURNAMENT_LIST_SUCCESS, + parameters: resp + }); + storeOptionalToken(resp); + action.parameters.successCallback(); + }).catch((error) => { + __store.dispatch({ + type: actiontypes_tournamentinfo.GET_TOURNAMENT_LIST_ERROR, + parameters: {error: error} + }); + storeOptionalToken(error.response); + action.parameters.errorCallback(); + }); + return Object.assign({}, state, {}); + case actiontypes_userinfo.GET_TOURNAMENT_LIST_ERROR: + return Object.assign({}, state, {}); + case actiontypes_userinfo.GET_TOURNAMENT_LIST_SUCCESS: + return Object.assign({}, state, {...action.parameters}); default: return state; } }; @@ -329,14 +361,44 @@ const reducer_tournamentinfo = (state = defaultstate_tournamentinfo, action) => } }; +const reducer_tournamentlist = (state = defaultstate_tournamentlist, action) => { + switch (action.type) { + case actiontypes_tournamentlist.FETCH: + getRequest(action.state, '/tournaments?type=' + action.parameters.type).then((resp) => { + __store.dispatch({ + type: actiontypes_tournamentlist.FETCH_SUCCESS, + parameters: resp + }); + storeOptionalToken(resp); + action.parameters.successCallback(); + }).catch((error) => { + __store.dispatch({ + type: actiontypes_tournamentlist.FETCH_ERROR, + parameters: {error: error} + }); + storeOptionalToken(error.response); + action.parameters.errorCallback(); + }); + return state; + case actiontypes_tournamentlist.FETCH_SUCCESS: + return Object.assign({}, state, {...action.parameters}); + case actiontypes_tournamentlist.FETCH_ERROR: + return state; + default: + return state; + } +}; + const reducers = { userinfo: reducer_userinfo, - tournamentinfo: reducer_tournamentinfo + tournamentinfo: reducer_tournamentinfo, + tournamentlist: reducer_tournamentlist }; const default_applicationstate = { userinfo : defaultstate_userinfo, - tournamentinfo: defaultstate_tournamentinfo + tournamentinfo: defaultstate_tournamentinfo, + tournamentlist: defaultstate_tournamentlist }; var __store; @@ -444,6 +506,18 @@ export function getState() { return __store.getState(); } +export function requestTournamentList(myType, successCallback, errorCallback) { + __store.dispatch({ + type: actiontypes_tournamentlist.FETCH, + parameters: { + type: myType, + successCallback: successCallback, + errorCallback: errorCallback + }, + state: __store.getState() + }); +} + function rehydrateApplicationState() { const persistedState = localStorage.getItem('reduxState') ? JSON.parse(localStorage.getItem('reduxState')) : @@ -458,6 +532,10 @@ function rehydrateApplicationState() { type : actiontypes_tournamentinfo.REHYDRATE, parameters : Object.assign({}, persistedState.tournamentinfo) }); + __store.dispatch({ + type : actiontypes_tournamentlist.REHYDRATE, + parameters : Object.assign({}, persistedState.tournamentlist) + }); applicationHydrated = true; } } diff --git a/pages/private.js b/pages/private.js new file mode 100644 index 0000000..8d732b1 --- /dev/null +++ b/pages/private.js @@ -0,0 +1,130 @@ +import Head from 'next/head'; +import React from 'react'; +import {connect} from 'react-redux'; + +import {Card, CardBody, Container,} from 'reactstrap'; + +import {TurniereNavigation} from '../js/components/Navigation'; +import {Footer} from '../js/components/Footer'; +import {Option, UserRestrictor} from '../js/components/UserRestrictor'; +import {Login} from '../js/components/Login'; +import {requestTournamentList} from '../js/api'; + +import '../static/everypage.css'; + +class PrivateTournamentsPage extends React.Component { + + render() { + const {isSignedIn} = this.props; + + return ( + + + + + ); + } +} + +function mapStateToCreatePageProperties(state) { + const {isSignedIn} = state.userinfo; + return {isSignedIn}; +} + +const CreatePage = connect( + mapStateToCreatePageProperties, +)(PrivateTournamentsPage); + +export default CreatePage; + + + +class PrivateTournamentsListCard extends React.Component { + constructor(props) { + super(props); + this.state = { + error: null, + isLoaded: false, + items: [] + }; + } + + componentDidMount() { + requestTournamentList('private', response => { + this.setState({ + isLoaded: true, + items: response.data + }); + }, + error => { + this.setState({ + isLoaded: true, + error + }); + }); + /* + getRequest(getState(), '/tournaments?type=private') + .then( + response => { + this.setState({ + isLoaded: true, + items: response.data + }); + }, + error => { + this.setState({ + isLoaded: true, + error + }); + } + ); + */ + } + + render() { + return ( + + + +

Private Turniere

+ {this.state.items.map(item => ( + //The code should be item.code but the api just supports it this way by now + + ))} +
+
+
+ ); + } +} + +function TournamentListEntry(props) { + return ( + + {props.name} + + ); +} \ No newline at end of file From 0aa1660cd1c6c2cecb1c7080c1e863805f2021e4 Mon Sep 17 00:00:00 2001 From: Felix Hamme Date: Wed, 17 Apr 2019 09:59:51 +0200 Subject: [PATCH 2/7] Link private tournament list in navigation bar if the user is signed in --- js/components/Navigation.js | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/js/components/Navigation.js b/js/components/Navigation.js index b9d0775..a58a33f 100644 --- a/js/components/Navigation.js +++ b/js/components/Navigation.js @@ -40,11 +40,7 @@ export class TurniereNavigation extends React.Component { - + @@ -60,6 +56,18 @@ function Navlink(props) { ); } +class SmartNavLinks extends React.Component { + + render() { + return (); + } +} + function Betabadge() { return (BETA); } @@ -87,12 +95,15 @@ class InvisibleLoginLogoutButtons extends React.Component { } } -const mapStateToLoginLogoutButtonProperties = (state) => { +const mapStateToUserinfo = (state) => { const { isSignedIn, username } = state.userinfo; return { isSignedIn, username }; }; const LoginLogoutButtons = connect( - mapStateToLoginLogoutButtonProperties + mapStateToUserinfo )(InvisibleLoginLogoutButtons); +const NavLinks = connect( + mapStateToUserinfo +)(SmartNavLinks); \ No newline at end of file From 6aeb97ae99868213c63139f4c2ebcd8cf6c70044 Mon Sep 17 00:00:00 2001 From: Felix Hamme Date: Sun, 28 Apr 2019 02:33:36 +0200 Subject: [PATCH 3/7] Remove unused code --- js/api.js | 21 --------------------- pages/private.js | 17 ----------------- 2 files changed, 38 deletions(-) diff --git a/js/api.js b/js/api.js index a4ab3d3..88a9795 100644 --- a/js/api.js +++ b/js/api.js @@ -274,27 +274,6 @@ const reducer_userinfo = (state = defaultstate_userinfo, action) => { expiry : null, uid : null }); - case actiontypes_userinfo.GET_TOURNAMENT_LIST: - getRequest(action.state, '/tournaments?type=' + action.parameters.type).then((resp) => { - __store.dispatch({ - type: actiontypes_tournamentinfo.GET_TOURNAMENT_LIST_SUCCESS, - parameters: resp - }); - storeOptionalToken(resp); - action.parameters.successCallback(); - }).catch((error) => { - __store.dispatch({ - type: actiontypes_tournamentinfo.GET_TOURNAMENT_LIST_ERROR, - parameters: {error: error} - }); - storeOptionalToken(error.response); - action.parameters.errorCallback(); - }); - return Object.assign({}, state, {}); - case actiontypes_userinfo.GET_TOURNAMENT_LIST_ERROR: - return Object.assign({}, state, {}); - case actiontypes_userinfo.GET_TOURNAMENT_LIST_SUCCESS: - return Object.assign({}, state, {...action.parameters}); default: return state; } }; diff --git a/pages/private.js b/pages/private.js index 8d732b1..1d6c20c 100644 --- a/pages/private.js +++ b/pages/private.js @@ -85,23 +85,6 @@ class PrivateTournamentsListCard extends React.Component { error }); }); - /* - getRequest(getState(), '/tournaments?type=private') - .then( - response => { - this.setState({ - isLoaded: true, - items: response.data - }); - }, - error => { - this.setState({ - isLoaded: true, - error - }); - } - ); - */ } render() { From dac0c3327254b723180ed5c38251c1e5e2804027 Mon Sep 17 00:00:00 2001 From: Felix Hamme Date: Sun, 28 Apr 2019 04:18:18 +0200 Subject: [PATCH 4/7] Implement page for displaying the list of private tournaments --- js/api.js | 10 ++-- js/components/TournamentList.js | 45 ++++++++++++++++++ pages/private.js | 82 +++++++++++---------------------- 3 files changed, 76 insertions(+), 61 deletions(-) create mode 100644 js/components/TournamentList.js diff --git a/js/api.js b/js/api.js index 88a9795..2e7d1a4 100644 --- a/js/api.js +++ b/js/api.js @@ -346,10 +346,10 @@ const reducer_tournamentlist = (state = defaultstate_tournamentlist, action) => getRequest(action.state, '/tournaments?type=' + action.parameters.type).then((resp) => { __store.dispatch({ type: actiontypes_tournamentlist.FETCH_SUCCESS, - parameters: resp + parameters: resp.data }); storeOptionalToken(resp); - action.parameters.successCallback(); + action.parameters.successCallback(resp.data); }).catch((error) => { __store.dispatch({ type: actiontypes_tournamentlist.FETCH_ERROR, @@ -360,7 +360,7 @@ const reducer_tournamentlist = (state = defaultstate_tournamentlist, action) => }); return state; case actiontypes_tournamentlist.FETCH_SUCCESS: - return Object.assign({}, state, {...action.parameters}); + return Object.assign({}, state, {tournaments: action.parameters}); case actiontypes_tournamentlist.FETCH_ERROR: return state; default: @@ -485,11 +485,11 @@ export function getState() { return __store.getState(); } -export function requestTournamentList(myType, successCallback, errorCallback) { +export function requestTournamentList(type, successCallback, errorCallback) { __store.dispatch({ type: actiontypes_tournamentlist.FETCH, parameters: { - type: myType, + type: type, successCallback: successCallback, errorCallback: errorCallback }, diff --git a/js/components/TournamentList.js b/js/components/TournamentList.js new file mode 100644 index 0000000..53055b8 --- /dev/null +++ b/js/components/TournamentList.js @@ -0,0 +1,45 @@ +import React from 'react'; +import {requestTournamentList} from '../api'; + +export default class TournamentList extends React.Component { + constructor(props) { + super(props); + this.state = { + error: null, + tournaments: [] + }; + } + + componentDidMount() { + requestTournamentList(this.props.type, tournaments => { + this.setState({ + tournaments: tournaments + }); + }, + error => { + this.setState({ + error + }); + }); + } + + render() { + if (this.state.tournaments.length === 0) { + return

keine + Turniere vorhanden

; + } else { + return this.state.tournaments.map(item => ( + //The code should be item.code but the api just supports it this way by now + + )); + } + } +} + +function TournamentListEntry(props) { + return ( + + {props.name} + + ); +} \ No newline at end of file diff --git a/pages/private.js b/pages/private.js index 1d6c20c..63eaae0 100644 --- a/pages/private.js +++ b/pages/private.js @@ -8,9 +8,9 @@ import {TurniereNavigation} from '../js/components/Navigation'; import {Footer} from '../js/components/Footer'; import {Option, UserRestrictor} from '../js/components/UserRestrictor'; import {Login} from '../js/components/Login'; -import {requestTournamentList} from '../js/api'; import '../static/everypage.css'; +import TournamentList from '../js/components/TournamentList'; class PrivateTournamentsPage extends React.Component { @@ -25,9 +25,7 @@ class PrivateTournamentsPage extends React.Component { Private Turniere: turnie.re -
- -
+