Merge pull request #20 from turniere/ticket/TURNIERE-141
Ticket/turniere 141
This commit is contained in:
commit
e5788281c2
58
js/api.js
58
js/api.js
|
|
@ -32,7 +32,7 @@ const actiontypes_userinfo = {
|
||||||
'STORE_AUTH_HEADERS' : 'STORE_AUTH_HEADERS',
|
'STORE_AUTH_HEADERS' : 'STORE_AUTH_HEADERS',
|
||||||
|
|
||||||
'REHYDRATE' : 'USERINFO_REHYDRATE',
|
'REHYDRATE' : 'USERINFO_REHYDRATE',
|
||||||
'CLEAR' : 'USERINFO_CLEAR',
|
'CLEAR' : 'USERINFO_CLEAR'
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultstate_userinfo = {
|
const defaultstate_userinfo = {
|
||||||
|
|
@ -72,6 +72,16 @@ const defaultstate_tournamentinfo = {
|
||||||
teams : []
|
teams : []
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const actiontypes_tournamentlist = {
|
||||||
|
'FETCH': 'FETCH',
|
||||||
|
'FETCH_SUCCESS': 'FETCH_SUCCESS',
|
||||||
|
'REHYDRATE': 'REHYDRATE'
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultstate_tournamentlist = {
|
||||||
|
tournaments: []
|
||||||
|
};
|
||||||
|
|
||||||
export function postRequest(state, url, data) {
|
export function postRequest(state, url, data) {
|
||||||
return axios.post(api_url + url, data, {
|
return axios.post(api_url + url, data, {
|
||||||
headers : generateHeaders(state)
|
headers : generateHeaders(state)
|
||||||
|
|
@ -332,14 +342,40 @@ 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.data
|
||||||
|
});
|
||||||
|
storeOptionalToken(resp);
|
||||||
|
action.parameters.successCallback(resp.data);
|
||||||
|
}).catch((error) => {
|
||||||
|
if(error.response) {
|
||||||
|
storeOptionalToken(error.response);
|
||||||
|
}
|
||||||
|
action.parameters.errorCallback();
|
||||||
|
});
|
||||||
|
return state;
|
||||||
|
case actiontypes_tournamentlist.FETCH_SUCCESS:
|
||||||
|
return Object.assign({}, state, {tournaments: action.parameters});
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const reducers = {
|
const reducers = {
|
||||||
userinfo: reducer_userinfo,
|
userinfo: reducer_userinfo,
|
||||||
tournamentinfo: reducer_tournamentinfo
|
tournamentinfo: reducer_tournamentinfo,
|
||||||
|
tournamentlist: reducer_tournamentlist
|
||||||
};
|
};
|
||||||
|
|
||||||
const default_applicationstate = {
|
const default_applicationstate = {
|
||||||
userinfo : defaultstate_userinfo,
|
userinfo : defaultstate_userinfo,
|
||||||
tournamentinfo: defaultstate_tournamentinfo
|
tournamentinfo: defaultstate_tournamentinfo,
|
||||||
|
tournamentlist: defaultstate_tournamentlist
|
||||||
};
|
};
|
||||||
|
|
||||||
var __store;
|
var __store;
|
||||||
|
|
@ -451,6 +487,18 @@ export function getState() {
|
||||||
return __store.getState();
|
return __store.getState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function requestTournamentList(type, successCallback, errorCallback) {
|
||||||
|
__store.dispatch({
|
||||||
|
type: actiontypes_tournamentlist.FETCH,
|
||||||
|
parameters: {
|
||||||
|
type: type,
|
||||||
|
successCallback: successCallback,
|
||||||
|
errorCallback: errorCallback
|
||||||
|
},
|
||||||
|
state: __store.getState()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function rehydrateApplicationState() {
|
function rehydrateApplicationState() {
|
||||||
const persistedState = localStorage.getItem('reduxState') ?
|
const persistedState = localStorage.getItem('reduxState') ?
|
||||||
JSON.parse(localStorage.getItem('reduxState')) :
|
JSON.parse(localStorage.getItem('reduxState')) :
|
||||||
|
|
@ -465,6 +513,10 @@ function rehydrateApplicationState() {
|
||||||
type : actiontypes_tournamentinfo.REHYDRATE,
|
type : actiontypes_tournamentinfo.REHYDRATE,
|
||||||
parameters : Object.assign({}, persistedState.tournamentinfo)
|
parameters : Object.assign({}, persistedState.tournamentinfo)
|
||||||
});
|
});
|
||||||
|
__store.dispatch({
|
||||||
|
type : actiontypes_tournamentlist.REHYDRATE,
|
||||||
|
parameters : Object.assign({}, persistedState.tournamentlist)
|
||||||
|
});
|
||||||
applicationHydrated = true;
|
applicationHydrated = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,11 +41,7 @@ export class TurniereNavigation extends React.Component {
|
||||||
<Betabadge/>
|
<Betabadge/>
|
||||||
<NavbarToggler onClick={this.toggle} />
|
<NavbarToggler onClick={this.toggle} />
|
||||||
<Collapse isOpen={!this.state.collapsed} navbar>
|
<Collapse isOpen={!this.state.collapsed} navbar>
|
||||||
<Nav navbar className="mr-auto">
|
<NavLinks/>
|
||||||
<Navlink target="/create" text="Turnier erstellen"/>
|
|
||||||
<Navlink target="/list" text="Öffentliche Turniere"/>
|
|
||||||
<Navlink target="/faq" text="FAQ"/>
|
|
||||||
</Nav>
|
|
||||||
<LoginLogoutButtons/>
|
<LoginLogoutButtons/>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
</Navbar>
|
</Navbar>
|
||||||
|
|
@ -61,6 +57,18 @@ function Navlink(props) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SmartNavLinks extends React.Component {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (<Nav navbar className="mr-auto">
|
||||||
|
<Navlink target="/create" text="Turnier erstellen"/>
|
||||||
|
<Navlink target="/list" text="Öffentliche Turniere"/>
|
||||||
|
{this.props.isSignedIn && <Navlink target="/private" text="Private Turniere"/>}
|
||||||
|
<Navlink target="/faq" text="FAQ"/>
|
||||||
|
</Nav>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function Betabadge() {
|
function Betabadge() {
|
||||||
return (<Badge color="danger" className="mr-2">BETA</Badge>);
|
return (<Badge color="danger" className="mr-2">BETA</Badge>);
|
||||||
}
|
}
|
||||||
|
|
@ -92,12 +100,15 @@ class InvisibleLoginLogoutButtons extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToLoginLogoutButtonProperties = (state) => {
|
const mapStateToUserinfo = (state) => {
|
||||||
const { isSignedIn, username } = state.userinfo;
|
const { isSignedIn, username } = state.userinfo;
|
||||||
return { isSignedIn, username };
|
return { isSignedIn, username };
|
||||||
};
|
};
|
||||||
|
|
||||||
const LoginLogoutButtons = connect(
|
const LoginLogoutButtons = connect(
|
||||||
mapStateToLoginLogoutButtonProperties
|
mapStateToUserinfo
|
||||||
)(InvisibleLoginLogoutButtons);
|
)(InvisibleLoginLogoutButtons);
|
||||||
|
|
||||||
|
const NavLinks = connect(
|
||||||
|
mapStateToUserinfo
|
||||||
|
)(SmartNavLinks);
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
import React from 'react';
|
||||||
|
import {requestTournamentList} from '../api';
|
||||||
|
|
||||||
|
export default class TournamentList extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
tournaments: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
requestTournamentList(this.props.type, tournaments => {
|
||||||
|
this.setState({
|
||||||
|
tournaments: tournaments
|
||||||
|
});
|
||||||
|
}, () => {});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if (this.state.tournaments.length === 0) {
|
||||||
|
return <p className="text-center border-light font-italic text-secondary border-top border-bottom p-1">keine
|
||||||
|
Turniere vorhanden</p>;
|
||||||
|
} else {
|
||||||
|
return this.state.tournaments.map(item => (
|
||||||
|
//The code should be item.code but the api just supports it this way by now
|
||||||
|
<TournamentListEntry name={item.name} code={item.id} key={item.id}/>
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function TournamentListEntry(props) {
|
||||||
|
return (
|
||||||
|
<a className="w-100 d-inline-block mt-2 text-left btn btn-outline-primary" href={'/t/' + props.code}>
|
||||||
|
{props.name}
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -1,21 +1,15 @@
|
||||||
import Head from 'next/head';
|
import Head from 'next/head';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {
|
import {Card, CardBody, Container} from 'reactstrap';
|
||||||
Card,
|
|
||||||
CardBody,
|
|
||||||
Container
|
|
||||||
} from 'reactstrap';
|
|
||||||
|
|
||||||
import { TurniereNavigation } from '../js/components/Navigation';
|
import {TurniereNavigation} from '../js/components/Navigation';
|
||||||
import { Footer } from '../js/components/Footer';
|
import {Footer} from '../js/components/Footer';
|
||||||
import {
|
|
||||||
getRequest,
|
|
||||||
getState
|
|
||||||
} from '../js/api';
|
|
||||||
|
|
||||||
import '../static/everypage.css';
|
import '../static/everypage.css';
|
||||||
|
import TournamentList from '../js/components/TournamentList';
|
||||||
|
import {connect} from 'react-redux';
|
||||||
|
|
||||||
export default class ListPage extends React.Component {
|
export default class PublicTournamentsPage extends React.Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
|
|
@ -25,7 +19,7 @@ export default class ListPage extends React.Component {
|
||||||
</Head>
|
</Head>
|
||||||
<TurniereNavigation/>
|
<TurniereNavigation/>
|
||||||
<div>
|
<div>
|
||||||
<TournamentList/>
|
<PublicTournamentPageContent/>
|
||||||
</div>
|
</div>
|
||||||
<Footer/>
|
<Footer/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -33,55 +27,38 @@ export default class ListPage extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TournamentList extends React.Component {
|
function mapStateToProperties(state) {
|
||||||
constructor(props) {
|
const {isSignedIn} = state.userinfo;
|
||||||
super(props);
|
return {isSignedIn};
|
||||||
this.state = {
|
}
|
||||||
error: null,
|
|
||||||
isLoaded: false,
|
|
||||||
items: []
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
const PublicTournamentPageContent = connect(
|
||||||
getRequest(getState(), '/tournaments?type=public')
|
mapStateToProperties,
|
||||||
.then(
|
)(PublicTournaments);
|
||||||
response => {
|
|
||||||
this.setState({
|
|
||||||
isLoaded: true,
|
|
||||||
items: response.data
|
|
||||||
});
|
|
||||||
},
|
|
||||||
error => {
|
|
||||||
this.setState({
|
|
||||||
isLoaded: true,
|
|
||||||
error
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
function PublicTournaments(props) {
|
||||||
return (
|
if (props.isSignedIn) {
|
||||||
<Container className="py-5">
|
return (<div>
|
||||||
<Card className="shadow">
|
<Container className='pt-5'>
|
||||||
<CardBody>
|
<PublicTournamentsCard/>
|
||||||
<h1 className="custom-font">Öffentliche Turniere</h1>
|
|
||||||
{this.state.items.map(item => (
|
|
||||||
//The code should be item.code but the api just supports it this way by now
|
|
||||||
<TournamentListEntry name={item.name} code={item.id} key={item.id}/>
|
|
||||||
))}
|
|
||||||
</CardBody>
|
|
||||||
</Card>
|
|
||||||
</Container>
|
</Container>
|
||||||
);
|
<Container className="pb-5 pt-3">
|
||||||
|
<a href='/private' className="btn btn-success shadow">zu den privaten Turnieren</a>
|
||||||
|
</Container>
|
||||||
|
</div>);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return (<Container className='py-5'>
|
||||||
|
<PublicTournamentsCard/>
|
||||||
|
</Container>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function TournamentListEntry(props) {
|
function PublicTournamentsCard() {
|
||||||
return (
|
return (<Card className="shadow">
|
||||||
<a className="w-100 d-inline-block mt-2 text-left btn btn-outline-primary" href={ '/t/' + props.code }>
|
<CardBody>
|
||||||
{props.name}
|
<h1 className="custom-font">Öffentliche Turniere</h1>
|
||||||
</a>
|
<TournamentList type='public'/>
|
||||||
);
|
</CardBody>
|
||||||
|
</Card>);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
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 '../static/everypage.css';
|
||||||
|
import TournamentList from '../js/components/TournamentList';
|
||||||
|
|
||||||
|
class PrivateTournamentsPage extends React.Component {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {isSignedIn} = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<UserRestrictor>
|
||||||
|
<Option condition={isSignedIn}>
|
||||||
|
<div className="main generic-fullpage-bg">
|
||||||
|
<Head>
|
||||||
|
<title>Private Turniere: turnie.re</title>
|
||||||
|
</Head>
|
||||||
|
<TurniereNavigation/>
|
||||||
|
<PrivateTournamentsPageContent/>
|
||||||
|
<Footer/>
|
||||||
|
</div>
|
||||||
|
</Option>
|
||||||
|
<Option condition={true}>
|
||||||
|
<div className="main generic-fullpage-bg">
|
||||||
|
<Head>
|
||||||
|
<title>Anmeldung</title>
|
||||||
|
</Head>
|
||||||
|
<TurniereNavigation/>
|
||||||
|
<div>
|
||||||
|
<Login
|
||||||
|
hint="Sie müssen angemeldet sein, um diesen Inhalt anzuzeigen!"/>
|
||||||
|
</div>
|
||||||
|
<Footer/>
|
||||||
|
</div>
|
||||||
|
</Option>
|
||||||
|
</UserRestrictor>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapStateToProperties(state) {
|
||||||
|
const {isSignedIn} = state.userinfo;
|
||||||
|
return {isSignedIn};
|
||||||
|
}
|
||||||
|
|
||||||
|
const PrivateTournamentListPage = connect(
|
||||||
|
mapStateToProperties,
|
||||||
|
)(PrivateTournamentsPage);
|
||||||
|
|
||||||
|
export default PrivateTournamentListPage;
|
||||||
|
|
||||||
|
function PrivateTournamentsPageContent() {
|
||||||
|
return (<div>
|
||||||
|
<Container className="pt-5">
|
||||||
|
<PrivateTournamentsCard/>
|
||||||
|
</Container>
|
||||||
|
<Container className="pb-5 pt-3">
|
||||||
|
<a href='/list' className="btn btn-success shadow">zu den öffentlichen Turnieren</a>
|
||||||
|
</Container>
|
||||||
|
</div>);
|
||||||
|
}
|
||||||
|
|
||||||
|
class PrivateTournamentsCard extends React.Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Card className="shadow">
|
||||||
|
<CardBody>
|
||||||
|
<h1 className="custom-font">Private Turniere</h1>
|
||||||
|
<TournamentList type='private'/>
|
||||||
|
</CardBody>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue