Merge pull request #36 from turniere/ticket/TURNIERE-135

Create User Profile Page (Ticket/turniere 135)
This commit is contained in:
betanummeric 2019-06-10 21:06:04 +02:00 committed by GitHub
commit a716f27dc8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 134 additions and 1 deletions

View File

@ -7,7 +7,7 @@ import {errorMessages} from './constants';
import {actionTypesUserinfo, defaultStateUserinfo} from './redux/userInfo';
import {actionTypesTournamentinfo, defaultStateTournamentinfo} from './redux/tournamentInfo';
import {actionTypesTournamentlist, defaultStateTournamentlist} from './redux/tournamentList';
import {deleteRequest, getRequest, patchRequest, postRequest} from './redux/backendApi';
import {deleteRequest, getRequest, patchRequest, postRequest, putRequest} from './redux/backendApi';
function storeOptionalToken(response) {
@ -149,6 +149,16 @@ const reducerUserinfo = (state = defaultStateUserinfo, action) => {
__store.dispatch({type: actionTypesUserinfo.CLEAR});
});
return Object.assign({}, state, {});
case actionTypesUserinfo.CHANGE_MAIL:
putRequest(action.state, '/users', {
email: action.parameters.newMail
}).then(resp => {
storeOptionalToken(resp);
action.parameters.successCallback();
}).catch(() => {
action.parameters.errorCallback();
});
return Object.assign({}, state, {});
case actionTypesUserinfo.REHYDRATE:
return Object.assign({}, state, action.parameters, {error: false, errorMessages: []});
case actionTypesUserinfo.CLEAR:
@ -378,6 +388,18 @@ export function logout(successCallback) {
});
}
export function changeMail(newMail, successCallback, errorCallback) {
__store.dispatch({
type: actionTypesUserinfo.CHANGE_MAIL,
parameters: {
newMail: newMail,
successCallback: successCallback,
errorCallback: errorCallback
},
state: __store.getState()
});
}
export function createTournament(data, successCallback, errorCallback) {
__store.dispatch({
type: actionTypesTournamentinfo.CREATE_TOURNAMENT,

View File

@ -29,6 +29,12 @@ export function patchRequest(state, url, data) {
});
}
export function putRequest(state, url, data) {
return axios.put(apiUrl + url, data, {
headers: generateHeaders(state)
});
}
function generateHeaders(state) {
if (state.userinfo.isSignedIn) {
return {

View File

@ -13,6 +13,8 @@ export const actionTypesUserinfo = {
'VERIFY_CREDENTIALS_SUCCESS': 'VERIFY_CREDENTIALS_SUCCESS',
'VERIFY_CREDENTIALS_ERROR': 'VERIFY_CREDENTIALS_ERROR',
'CHANGE_MAIL': 'CHANGE_MAIL',
'STORE_AUTH_HEADERS': 'STORE_AUTH_HEADERS',
'REHYDRATE': 'USERINFO_REHYDRATE',

100
pages/profile.js Normal file
View File

@ -0,0 +1,100 @@
import Head from 'next/head';
import React, {Component} from 'react';
import {Button, Container, Form, Input, InputGroup, InputGroupAddon, Table} from 'reactstrap';
import {TurniereNavigation} from '../js/components/Navigation';
import {BigImage} from '../js/components/BigImage';
import {Footer} from '../js/components/Footer';
import 'bootstrap/dist/css/bootstrap.min.css';
import '../static/css/everypage.css';
import '../static/css/profile.css';
import {connect} from 'react-redux';
import {changeMail} from '../js/api';
import {notify} from 'react-notify-toast';
import RequireLogin from '../js/components/RequireLogin';
function ContentContainer(props) {
return (<Container className="pb-5">
<UserData name={props.name} email={props.email}/>
<h3 className='custom-font mt-5'>E-Mail-Adresse ändern</h3>
<NewMailAddressInput email={props.email}/>
</Container>);
}
export default class ProfilePage extends React.Component {
render() {
return (<RequireLogin loginMessage='Sie müssen angemeldet sein, um Ihr Profil einzusehen.'>
<Head>
<title>Profil: turnie.re</title>
</Head>
<TurniereNavigation/>
<BigImage text="turnie.re-Account"/>
<div className='main'>
<Content/>
</div>
<Footer/>
</RequireLogin>);
}
}
const Content = connect(state => {
return {email: state.userinfo.uid, name: state.userinfo.username};
})(ContentContainer);
function UserData(props) {
return (<Table>
<tbody>
<tr>
<th className='w-small'>Name</th>
<td className='w-100'>{props.name}</td>
</tr>
<tr>
<th className='w-small'>E-Mail-Adresse</th>
<td className='mw-100'>{props.email}</td>
</tr>
</tbody>
</Table>);
}
class NewMailAddressInput extends Component {
constructor(props) {
super(props);
this.state = {email: ''};
this.submit = this.submit.bind(this);
this.onChange = this.onChange.bind(this);
this.onSubmitSuccess = this.onSubmitSuccess.bind(this);
NewMailAddressInput.onSubmitError = NewMailAddressInput.onSubmitError.bind(this);
}
submit(event) {
event.preventDefault();
changeMail(this.state.email, this.onSubmitSuccess, NewMailAddressInput.onSubmitError);
}
onSubmitSuccess() {
this.setState({email: ''});
notify.show('E-Mail-Adresse geändert.', 'success', 2500);
}
static onSubmitError() {
notify.show('Die E-Mail-Adresse konnte nicht geändert werden.', 'error', 3000);
}
onChange(input) {
this.setState({email: input.target.value});
}
render() {
return (<Form onSubmit={this.submit}>
<InputGroup>
<Input type='email' placeholder={this.props.email} onChange={this.onChange} value={this.state.email}
required/>
<InputGroupAddon addonType='append'>
<Button color='primary' type='submit'>eintragen</Button>
</InputGroupAddon>
</InputGroup>
</Form>);
}
}

3
static/css/profile.css Normal file
View File

@ -0,0 +1,3 @@
.w-small {
min-width: 10em;
}