Implemented components for adding/editing users

This commit is contained in:
Philipp Czora
2018-07-18 17:40:05 +02:00
parent 2889c6598d
commit 3c0ea782aa
7 changed files with 245 additions and 111 deletions

View File

@@ -10,6 +10,8 @@ import Logout from "../containers/Logout";
import { Switch } from "react-router-dom"; import { Switch } from "react-router-dom";
import ProtectedRoute from "../components/ProtectedRoute"; import ProtectedRoute from "../components/ProtectedRoute";
import EditUser from "../users/containers/EditUser";
import AddUser from "../users/containers/AddUser";
type Props = { type Props = {
authenticated?: boolean authenticated?: boolean
@@ -30,10 +32,21 @@ class Main extends React.Component<Props> {
<Route exact path="/login" component={Login} /> <Route exact path="/login" component={Login} />
<Route path="/logout" component={Logout} /> <Route path="/logout" component={Logout} />
<ProtectedRoute <ProtectedRoute
exact
path="/users" path="/users"
component={Users} component={Users}
authenticated={authenticated} authenticated={authenticated}
/> />
<ProtectedRoute
authenticated={authenticated}
path="/users/edit/:name"
component={EditUser}
/>
<ProtectedRoute
authenticated={authenticated}
path="/users/add"
component={AddUser}
/>
</Switch> </Switch>
</div> </div>
); );

View File

@@ -0,0 +1,41 @@
//@flow
import React from "react";
import { connect } from "react-redux";
import UserForm from "./UserForm";
import type { User } from "../types/User";
import { addUser } from "../modules/users";
import { Route, Link } from "react-router-dom";
type Props = {
addUser: User => void
};
class AddUser extends React.Component<Props> {
render() {
const addUser = this.props.addUser;
return (
<div>
<UserForm submitForm={user => addUser(user)} />
</div>
);
}
}
const mapDispatchToProps = dispatch => {
return {
addUser: (user: User) => {
dispatch(addUser(user));
}
};
};
const mapStateToProps = (state, ownProps) => {
return {};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(AddUser);

View File

@@ -0,0 +1,67 @@
//@flow
import React from "react";
import { connect } from "react-redux";
import UserForm from "./UserForm";
import type { User } from "../types/User";
import {
updateUser,
deleteUser,
editUser,
fetchUser,
getUsersFromState
} from "../modules/users";
import { Route, Link } from "react-router-dom";
type Props = {
name: string,
fetchUser: string => void,
usersByNames: Map<string, any>,
updateUser: User => void
};
class EditUser extends React.Component<Props> {
componentDidMount() {
this.props.fetchUser(this.props.name);
}
render() {
const submitUser = this.props.updateUser;
const { usersByNames, name } = this.props;
if (!usersByNames || usersByNames[name].loading) {
return <div>Loading...</div>;
} else {
const user = usersByNames[name].entry;
return (
<div>
<UserForm submitForm={user => submitUser(user)} user={user} />
</div>
);
}
}
}
const mapDispatchToProps = dispatch => {
return {
fetchUser: (name: string) => {
dispatch(fetchUser(name));
},
updateUser: (user: User) => {
dispatch(updateUser(user));
}
};
};
const mapStateToProps = (state, ownProps) => {
return {
usersByNames: state.users.usersByNames,
name: ownProps.match.params.name
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(EditUser);

View File

@@ -3,24 +3,24 @@ import React from "react";
import EditButton from "../../components/EditButton"; import EditButton from "../../components/EditButton";
import type { User } from "../types/User"; import type { User } from "../types/User";
import type { UserEntry } from "../types/UserEntry"; import type { UserEntry } from "../types/UserEntry";
import { Link } from "react-router-dom";
type Props = { type Props = {
entry: UserEntry, entry: UserEntry
editUser: User => void
}; };
class EditUserButton extends React.Component<Props> { class EditUserButton extends React.Component<Props> {
render() { render() {
const { entry } = this.props;
const link = "/users/edit/" + entry.entry.name;
if (!this.isEditable()) { if (!this.isEditable()) {
return ""; return "";
} }
const { entry, editUser } = this.props;
return ( return (
<EditButton <Link to={link}>
label="Edit" <EditButton label="Edit" action={() => {}} loading={entry.loading} />
action={e => editUser(entry.entry)} </Link>
loading={entry.loading}
/>
); );
} }

View File

@@ -23,55 +23,59 @@ class UserForm extends React.Component<Props, User> {
}; };
} }
componentDidMount() {
this.setState({ ...this.props.user });
}
submit = (event: Event) => { submit = (event: Event) => {
event.preventDefault(); event.preventDefault();
this.props.submitForm(this.state); this.props.submitForm(this.state);
}; };
componentWillReceiveProps() {
this.setState(this.props.user);
}
render() { render() {
const user = this.state; const user = this.state;
return ( if (user) {
<div className="container"> return (
<form onSubmit={this.submit}> <div className="container">
<InputField <form onSubmit={this.submit}>
label="Username" <InputField
onChange={this.handleUsernameChange} label="Username"
value={user ? user.name : ""} onChange={this.handleUsernameChange}
/> value={user ? user.name : ""}
<InputField />
label="Display Name" <InputField
onChange={this.handleDisplayNameChange} label="Display Name"
value={user ? user.displayName : ""} onChange={this.handleDisplayNameChange}
/> value={user ? user.displayName : ""}
<InputField />
label="E-Mail" <InputField
onChange={this.handleEmailChange} label="E-Mail"
value={user ? user.mail : ""} onChange={this.handleEmailChange}
/> value={user ? user.mail : ""}
<InputField />
label="Password" <InputField
type="password" label="Password"
onChange={this.handlePasswordChange} type="password"
value={user ? user.password : ""} onChange={this.handlePasswordChange}
/> value={user ? user.password : ""}
<Checkbox />
label="Admin" <Checkbox
onChange={this.handleAdminChange} label="Admin"
checked={user ? user.admin : false} onChange={this.handleAdminChange}
/> checked={user ? user.admin : false}
<Checkbox />
label="Active" <Checkbox
onChange={this.handleActiveChange} label="Active"
checked={user ? user.active : false} onChange={this.handleActiveChange}
/> checked={user ? user.active : false}
<SubmitButton value="Submit" /> />
</form> <SubmitButton value="Submit" />
</div> </form>
); </div>
);
} else {
return <div>Loading...</div>;
}
} }
handleUsernameChange = (name: string) => { handleUsernameChange = (name: string) => {

View File

@@ -2,17 +2,9 @@
import React from "react"; import React from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { import { fetchUsers, deleteUser, getUsersFromState } from "../modules/users";
fetchUsers,
addUser,
updateUser,
deleteUser,
editUser,
getUsersFromState
} from "../modules/users";
import Loading from "../../components/Loading"; import Loading from "../../components/Loading";
import ErrorNotification from "../../components/ErrorNotification"; import ErrorNotification from "../../components/ErrorNotification";
import UserForm from "./UserForm";
import UserTable from "./UserTable"; import UserTable from "./UserTable";
import type { User } from "../types/User"; import type { User } from "../types/User";
import type { UserEntry } from "../types/UserEntry"; import type { UserEntry } from "../types/UserEntry";
@@ -22,11 +14,7 @@ type Props = {
error: Error, error: Error,
userEntries: Array<UserEntry>, userEntries: Array<UserEntry>,
fetchUsers: () => void, fetchUsers: () => void,
deleteUser: User => void, deleteUser: User => void
addUser: User => void,
updateUser: User => void,
editUser: User => void,
userToEdit: User
}; };
class Users extends React.Component<Props, User> { class Users extends React.Component<Props, User> {
@@ -34,28 +22,6 @@ class Users extends React.Component<Props, User> {
this.props.fetchUsers(); this.props.fetchUsers();
} }
addUser = (user: User) => {
this.props.addUser(user);
};
updateUser = (user: User) => {
this.props.updateUser(user);
};
componentDidUpdate(prevProps: Props) {
if (prevProps.userToEdit !== this.props.userToEdit) {
this.setState(this.props.userToEdit);
}
}
submitUser = (user: User) => {
if (user._links && user._links.update) {
this.updateUser(user);
} else {
this.addUser(user);
}
};
render() { render() {
return ( return (
<section className="section"> <section className="section">
@@ -69,20 +35,12 @@ class Users extends React.Component<Props, User> {
} }
renderContent() { renderContent() {
const { userEntries, deleteUser, editUser, userToEdit, error } = this.props; const { userEntries, deleteUser, error } = this.props;
if (userEntries) { if (userEntries) {
return ( return (
<div> <div>
<ErrorNotification error={error} /> <ErrorNotification error={error} />
<UserTable <UserTable entries={userEntries} deleteUser={deleteUser} />
entries={userEntries}
deleteUser={deleteUser}
editUser={user => editUser(user)}
/>
<UserForm
submitForm={user => this.submitUser(user)}
user={userToEdit}
/>
</div> </div>
); );
} else { } else {
@@ -93,13 +51,8 @@ class Users extends React.Component<Props, User> {
const mapStateToProps = state => { const mapStateToProps = state => {
const userEntries = getUsersFromState(state); const userEntries = getUsersFromState(state);
const userToEdit = state.users.editUser;
if (!userEntries) {
return { userToEdit };
}
return { return {
userEntries, userEntries,
userToEdit,
error: state.users.error error: state.users.error
}; };
}; };
@@ -109,17 +62,8 @@ const mapDispatchToProps = dispatch => {
fetchUsers: () => { fetchUsers: () => {
dispatch(fetchUsers()); dispatch(fetchUsers());
}, },
addUser: (user: User) => {
dispatch(addUser(user));
},
updateUser: (user: User) => {
dispatch(updateUser(user));
},
deleteUser: (user: User) => { deleteUser: (user: User) => {
dispatch(deleteUser(user)); dispatch(deleteUser(user));
},
editUser: (user: User) => {
dispatch(editUser(user));
} }
}; };
}; };

View File

@@ -9,6 +9,9 @@ export const FETCH_USERS_SUCCESS = "scm/users/FETCH_SUCCESS";
export const FETCH_USERS_FAILURE = "scm/users/FETCH_FAILURE"; export const FETCH_USERS_FAILURE = "scm/users/FETCH_FAILURE";
export const FETCH_USERS_NOTFOUND = "scm/users/FETCH_NOTFOUND"; export const FETCH_USERS_NOTFOUND = "scm/users/FETCH_NOTFOUND";
export const FETCH_USER = "scm/users/FETCH_USER";
export const FETCH_USER_SUCCESS = "scm/users/FETCH_USER_SUCCESS";
export const ADD_USER = "scm/users/ADD"; export const ADD_USER = "scm/users/ADD";
export const ADD_USER_SUCCESS = "scm/users/ADD_SUCCESS"; export const ADD_USER_SUCCESS = "scm/users/ADD_SUCCESS";
export const ADD_USER_FAILURE = "scm/users/ADD_FAILURE"; export const ADD_USER_FAILURE = "scm/users/ADD_FAILURE";
@@ -24,6 +27,7 @@ export const DELETE_USER_SUCCESS = "scm/users/DELETE_SUCCESS";
export const DELETE_USER_FAILURE = "scm/users/DELETE_FAILURE"; export const DELETE_USER_FAILURE = "scm/users/DELETE_FAILURE";
const USERS_URL = "users"; const USERS_URL = "users";
const USER_URL = "users/";
const CONTENT_TYPE_USER = "application/vnd.scmm-user+json;v=2"; const CONTENT_TYPE_USER = "application/vnd.scmm-user+json;v=2";
@@ -81,6 +85,47 @@ function fetchUsersSuccess(users: any) {
}; };
} }
function requestUser(name: string) {
return {
type: FETCH_USER,
payload: { name }
};
}
export function fetchUser(name: string) {
const userUrl = USER_URL + name;
return function(dispatch: any) {
dispatch(requestUsers());
return apiClient
.get(userUrl)
.then(response => {
return response;
})
.then(response => {
if (response.ok) {
return response.json();
}
})
.then(data => {
dispatch(fetchUserSuccess(data));
})
.catch(err => {
if (err === NOT_FOUND_ERROR) {
dispatch(usersNotFound(userUrl));
} else {
dispatch(failedToFetchUsers(userUrl, err));
}
});
};
}
function fetchUserSuccess(user: User) {
return {
type: FETCH_USER_SUCCESS,
payload: user
};
}
function requestAddUser(user: User) { function requestAddUser(user: User) {
return { return {
type: ADD_USER, type: ADD_USER,
@@ -258,7 +303,13 @@ export default function reducer(state: any = {}, action: any = {}) {
error: null, error: null,
entry: action.payload entry: action.payload
}); });
case FETCH_USER:
return reduceUsersByNames(state, action.payload.name, {
loading: true,
error: null
});
case FETCH_USERS_SUCCESS: case FETCH_USERS_SUCCESS:
// return red(state, action.payload._embedded.users);
const users = action.payload._embedded.users; const users = action.payload._embedded.users;
const userNames = users.map(user => user.name); const userNames = users.map(user => user.name);
const usersByNames = extractUsersByNames( const usersByNames = extractUsersByNames(
@@ -266,7 +317,6 @@ export default function reducer(state: any = {}, action: any = {}) {
userNames, userNames,
state.usersByNames state.usersByNames
); );
return { return {
...state, ...state,
users: { users: {
@@ -276,6 +326,21 @@ export default function reducer(state: any = {}, action: any = {}) {
}, },
usersByNames usersByNames
}; };
case FETCH_USER_SUCCESS:
const ubn = extractUsersByNames(
[action.payload],
[action.payload.name],
state.usersByNames
);
return {
...state,
users: {
error: null,
entries: [action.payload.name],
loading: false
},
usersByNames: ubn
};
case FETCH_USERS_FAILURE: case FETCH_USERS_FAILURE:
case DELETE_USER_FAILURE: case DELETE_USER_FAILURE: