1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/web/ synced 2025-03-09 00:00:01 +01:00

Fixes for editing users

- edit user dialogs behave as expected
- editing own user triggers update of LoginStore and local storage with updated user data
This commit is contained in:
Sonja Happ 2021-05-04 15:13:40 +02:00
parent 3437e582c7
commit 433c0918f2
6 changed files with 125 additions and 127 deletions

View file

@ -19,17 +19,16 @@ import React from 'react';
import { Form, Col } from 'react-bootstrap';
import Dialog from '../common/dialogs/dialog';
import NotificationsDataManager from "../common/data-managers/notifications-data-manager";
import NotificationsFactory from "../common/data-managers/notifications-factory";
class EditOwnUserDialog extends React.Component {
valid: true;
constructor(props) {
super(props);
this.state = {
username: this.props.user.username,
id: this.props.user.id,
username: "",
mail: this.props.user.mail,
password: '',
oldPassword: '',
@ -39,9 +38,29 @@ class EditOwnUserDialog extends React.Component {
onClose(canceled) {
if (canceled === false) {
if (this.valid) {
this.props.onClose(this.state);
let user = {};
user.id = this.props.user.id;
user.password = this.state.password;
user.oldPassword = this.state.oldPassword;
user.confirmPassword = this.state.confirmPassword
if (this.state.username != null && this.state.username !== this.props.user.username){
user.username = this.state.username;
}
if (this.state.mail != null && this.state.mail !== this.props.user.mail){
user.mail = this.state.mail;
}
if (this.state.password !== '' && this.state.oldPassword !== '' && this.state.password === this.state.confirmPassword ) {
user.password = this.state.password;
user.oldPassword = this.state.oldPassword;
} else if (this.state.password !== '' && this.state.password !== this.state.confirmPassword) {
NotificationsDataManager.addNotification(NotificationsFactory.UPDATE_ERROR('New password not correctly confirmed'));
}
this.props.onClose(user);
} else {
this.props.onClose();
}
@ -49,42 +68,11 @@ class EditOwnUserDialog extends React.Component {
handleChange(e) {
this.setState({ [e.target.id]: e.target.value });
// check all controls
let username = true;
let mail = true;
let pw = true;
let oldPassword = true;
let confirmPassword = true;
if (this.state.username === '') {
username = false;
}
if (this.state.mail === '') {
mail = false;
}
if (this.state.password === '') {
pw = false;
}
if (this.state.oldPassword === '') {
oldPassword = false;
}
if (this.state.confirmPassword === '') {
confirmPassword = false;
}
// form is valid if the following condition is met
this.valid = username || mail || (oldPassword && pw && confirmPassword);
}
resetState() {
this.setState({
username: this.props.user.username,
id: this.props.user.id,
mail: this.props.user.mail,
oldPassword: '',
confirmPassword: '',
@ -94,28 +82,28 @@ class EditOwnUserDialog extends React.Component {
render() {
return (
<Dialog show={this.props.show} title="Edit user" buttonTitle="Save" onClose={(c) => this.onClose(c)} onReset={() => this.resetState()} valid={this.valid}>
<Dialog show={this.props.show} title="Edit user" buttonTitle="Save" onClose={(c) => this.onClose(c)} onReset={() => this.resetState()} valid={true}>
<Form>
<Form.Group as={Col} controlId="username">
<Form.Label>Username</Form.Label>
<Form.Control type="text" value={this.state.username} onChange={(e) => this.handleChange(e)} autocomplete="username" />
<Form.Control type="text" placeholder={this.props.user.username} value={this.state.username} onChange={(e) => this.handleChange(e)} autoComplete="username" />
<Form.Control.Feedback />
</Form.Group>
<Form.Group as={Col} controlId="mail">
<Form.Label>E-mail</Form.Label>
<Form.Control type="text" value={this.state.mail} onChange={(e) => this.handleChange(e)} autocomplete="email" />
<Form.Control type="text" placeholder={this.props.user.mail} value={this.state.mail} onChange={(e) => this.handleChange(e)} autoComplete="email" />
</Form.Group>
<Form.Group as={Col} controlId="oldPassword">
<Form.Label>Old Password</Form.Label>
<Form.Control type="password" placeholder="Enter current password" value={this.state.oldPassword} onChange={(e) => this.handleChange(e)} autocomplete="current-password" />
<Form.Control type="password" placeholder="Enter current password" value={this.state.oldPassword} onChange={(e) => this.handleChange(e)} autoComplete="current-password" />
</Form.Group>
<Form.Group as={Col} controlId="password">
<Form.Label>New Password</Form.Label>
<Form.Control type="password" placeholder="Enter new password" value={this.state.password} onChange={(e) => this.handleChange(e)} autocomplete="new-password" />
<Form.Control type="password" placeholder="Enter new password" value={this.state.password} onChange={(e) => this.handleChange(e)} autoComplete="new-password" />
</Form.Group>
<Form.Group as={Col} controlId="confirmPassword">
<Form.Label>Confirm New Password</Form.Label>
<Form.Control type="password" placeholder="Repeat new password" value={this.state.confirmPassword} onChange={(e) => this.handleChange(e)} autocomplete="new-password" />
<Form.Control type="password" placeholder="Repeat new password" value={this.state.confirmPassword} onChange={(e) => this.handleChange(e)} autoComplete="new-password" />
</Form.Group>
</Form>
</Dialog>

View file

@ -77,6 +77,9 @@ class EditUserDialog extends React.Component {
username: this.props.user.username,
mail: this.props.user.mail,
role: this.props.user.role,
password: "",
confirmPassword: "",
oldPassword: "",
});
}

View file

@ -66,11 +66,14 @@ class LoginStore extends ReduceStore {
return Object.assign({}, state, { token: null, currentUser: null, loginMessage: null});
case 'users/logged-in':
// save login in local storage
localStorage.setItem('token', action.token);
// save login data in local storage and loginStore
let newState = state
if (action.token != null){
localStorage.setItem('token', action.token);
newState = Object.assign({}, state, {token: action.token})
}
localStorage.setItem('currentUser', JSON.stringify(action.currentUser));
return Object.assign({}, state, { token: action.token, currentUser: action.currentUser});
return Object.assign({}, newState, { currentUser: action.currentUser});
case 'users/login-error':
if (action.error && !action.error.handled) {

View file

@ -15,100 +15,74 @@
* along with VILLASweb. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
import React, { Component } from 'react';
import React from 'react';
import { Container } from 'flux/utils';
import { Button, Form, Row, Col } from 'react-bootstrap';
import { Form, Row, Col } from 'react-bootstrap';
import AppDispatcher from '../common/app-dispatcher';
import UsersStore from './users-store';
import Icon from '../common/icon';
import EditOwnUserDialog from './edit-own-user'
import NotificationsDataManager from "../common/data-managers/notifications-data-manager"
import NotificationsFactory from "../common/data-managers/notifications-factory";
import IconButton from "../common/icon-button";
import LoginStore from './login-store'
class User extends React.Component {
constructor() {
super();
this.state = {
token: LoginStore.getState().token,
editModal: false,
}
}
class User extends Component {
static getStores() {
return [ UsersStore ];
return [ LoginStore ];
}
static calculateState(prevState, props) {
prevState = prevState || {};
let currentUserID = JSON.parse(localStorage.getItem("currentUser")).id;
let currentUser = UsersStore.getState().find(user => user.id === parseInt(currentUserID, 10));
return {
currentUser,
token: localStorage.getItem("token"),
editModal: false,
};
}
componentDidMount() {
let currentUserID = JSON.parse(localStorage.getItem("currentUser")).id;
AppDispatcher.dispatch({
type: 'users/start-load',
data: parseInt(currentUserID, 10),
token: this.state.token
});
currentUser: LoginStore.getState().currentUser
}
}
closeEditModal(data) {
this.setState({ editModal: false });
let updatedData = {}
let updatedUser = this.state.currentUser;
let hasChanged = false;
let pwChanged = false;
updatedData.id = this.state.currentUser.id;
if (data) {
if (data.username !== this.state.currentUser.username) {
hasChanged = true;
updatedData.username = data.username;
updatedUser.username = data.username
}
if (data.mail !== this.state.currentUser.mail) {
hasChanged = true;
updatedData.mail = data.mail;
updatedUser.mail = data.mail;
}
if (data.password !== '' && data.oldPassword !== '' && data.password === data.confirmPassword ) {
pwChanged = true;
updatedData.password = data.password;
updatedData.oldPassword = data.oldPassword;
} else if (data.password !== '' && data.password !== data.confirmPassword) {
NotificationsDataManager.addNotification(NotificationsFactory.UPDATE_ERROR('New password not correctly confirmed'));
return
}
if (hasChanged || pwChanged) {
if (hasChanged){
this.setState({ currentUser: updatedUser })
}
AppDispatcher.dispatch({
type: 'users/start-edit',
data: updatedData,
token: this.state.token
});
} else {
NotificationsDataManager.addNotification(NotificationsFactory.UPDATE_WARNING('No update requested, no input data'));
}
AppDispatcher.dispatch({
type: 'users/start-edit',
data: data,
token: this.state.token,
currentUser: this.state.currentUser,
});
}
}
render() {
let user = this.state.currentUser;
const buttonStyle = {
marginLeft: '10px',
}
const iconStyle = {
height: '30px',
width: '30px'
}
return (
<div>
<h1>Account</h1>
<h1>Account
<span className='icon-button'>
<IconButton
childKey={0}
tooltip='Edit Account'
onClick={() => this.setState({ editModal: true })}
icon='edit'
buttonStyle={buttonStyle}
iconStyle={iconStyle}
/>
</span>
</h1>
{user ?
<>
@ -116,30 +90,28 @@ class User extends Component {
<Form.Group as={Row} controlId="username">
<Form.Label column sm={2}>Username</Form.Label>
<Col sm={10}>
<Form.Control plaintext readOnly defaultValue={user.username} />
<Form.Control plaintext readOnly value={user.username} />
</Col>
</Form.Group>
<Form.Group as={Row} controlId="mail">
<Form.Label column sm={2}>E-mail</Form.Label>
<Col sm={10}>
<Form.Control plaintext readOnly defaultValue={user.mail} type="email" />
<Form.Control plaintext readOnly value={user.mail} type="email" />
</Col>
</Form.Group>
<Form.Group as={Row} controlId="role">
<Form.Label column sm={2}>Role</Form.Label>
<Col sm={10}>
<Form.Control plaintext readOnly defaultValue={user.role} />
<Form.Control plaintext readOnly value={user.role} />
</Col>
</Form.Group>
<Form.Group as={Row} controlId="formBasicEmail">
<Form.Label column sm={2}>Created at</Form.Label>
<Col sm={10}>
<Form.Control plaintext readOnly defaultValue={user.createdAt} />
<Form.Control plaintext readOnly value={user.createdAt} />
</Col>
</Form.Group>
<Button variant="primary" onClick={() => this.setState({ editModal: true })}>
<Icon icon='edit' /> Edit
</Button>
</Form>
<EditOwnUserDialog

View file

@ -19,10 +19,13 @@ import ArrayStore from '../common/array-store';
import UsersDataManager from './users-data-manager';
import NotificationsDataManager from '../common/data-managers/notifications-data-manager';
import NotificationsFactory from "../common/data-managers/notifications-factory";
import AppDispatcher from "../common/app-dispatcher";
class UsersStore extends ArrayStore {
constructor() {
super('users', UsersDataManager);
this.currentUser = null;
}
reduce(state, action) {
@ -46,6 +49,33 @@ class UsersStore extends ArrayStore {
}
return super.reduce(state, action);
case this.type + '/start-edit':
// save current user on user edit
this.currentUser = action.currentUser;
return super.reduce(state, action)
case this.type + '/edited':
let currentUserID = this.currentUser.id;
// check if own user was updated
for (let u of [action.data]){
if (u.id === currentUserID){
console.log("Detected update of current user, updating login store")
AppDispatcher.dispatch({
type: 'users/logged-in',
token: null,
currentUser: u,
});
break;
}
}
return super.reduce(state, action)
default:
return super.reduce(state, action);
}

View file

@ -20,6 +20,7 @@ import { Container } from 'flux/utils';
import AppDispatcher from '../common/app-dispatcher';
import UsersStore from './users-store';
import LoginStore from './login-store';
import ScenarioStore from '../scenario/scenario-store';
import Icon from '../common/icon';
@ -37,7 +38,7 @@ import NotificationsFactory from "../common/data-managers/notifications-factory"
class Users extends Component {
static getStores() {
return [UsersStore, ScenarioStore];
return [UsersStore, ScenarioStore, LoginStore];
}
static calculateState(prevState, props) {
@ -110,7 +111,8 @@ class Users extends Component {
AppDispatcher.dispatch({
type: 'users/start-edit',
data: data,
token: this.state.token
token: this.state.token,
currentUser: this.state.currentUser,
});
} else {
NotificationsDataManager.addNotification(NotificationsFactory.UPDATE_ERROR("New password not correctly confirmed"))