mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-12 16:35:45 +01:00
Implemented components for adding/editing users
This commit is contained in:
@@ -10,6 +10,8 @@ import Logout from "../containers/Logout";
|
||||
|
||||
import { Switch } from "react-router-dom";
|
||||
import ProtectedRoute from "../components/ProtectedRoute";
|
||||
import EditUser from "../users/containers/EditUser";
|
||||
import AddUser from "../users/containers/AddUser";
|
||||
|
||||
type Props = {
|
||||
authenticated?: boolean
|
||||
@@ -30,10 +32,21 @@ class Main extends React.Component<Props> {
|
||||
<Route exact path="/login" component={Login} />
|
||||
<Route path="/logout" component={Logout} />
|
||||
<ProtectedRoute
|
||||
exact
|
||||
path="/users"
|
||||
component={Users}
|
||||
authenticated={authenticated}
|
||||
/>
|
||||
<ProtectedRoute
|
||||
authenticated={authenticated}
|
||||
path="/users/edit/:name"
|
||||
component={EditUser}
|
||||
/>
|
||||
<ProtectedRoute
|
||||
authenticated={authenticated}
|
||||
path="/users/add"
|
||||
component={AddUser}
|
||||
/>
|
||||
</Switch>
|
||||
</div>
|
||||
);
|
||||
|
||||
41
scm-ui/src/users/containers/AddUser.js
Normal file
41
scm-ui/src/users/containers/AddUser.js
Normal 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);
|
||||
67
scm-ui/src/users/containers/EditUser.js
Normal file
67
scm-ui/src/users/containers/EditUser.js
Normal 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);
|
||||
@@ -3,24 +3,24 @@ import React from "react";
|
||||
import EditButton from "../../components/EditButton";
|
||||
import type { User } from "../types/User";
|
||||
import type { UserEntry } from "../types/UserEntry";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
type Props = {
|
||||
entry: UserEntry,
|
||||
editUser: User => void
|
||||
entry: UserEntry
|
||||
};
|
||||
|
||||
class EditUserButton extends React.Component<Props> {
|
||||
render() {
|
||||
const { entry } = this.props;
|
||||
const link = "/users/edit/" + entry.entry.name;
|
||||
|
||||
if (!this.isEditable()) {
|
||||
return "";
|
||||
}
|
||||
const { entry, editUser } = this.props;
|
||||
return (
|
||||
<EditButton
|
||||
label="Edit"
|
||||
action={e => editUser(entry.entry)}
|
||||
loading={entry.loading}
|
||||
/>
|
||||
<Link to={link}>
|
||||
<EditButton label="Edit" action={() => {}} loading={entry.loading} />
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,17 +23,18 @@ class UserForm extends React.Component<Props, User> {
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.setState({ ...this.props.user });
|
||||
}
|
||||
|
||||
submit = (event: Event) => {
|
||||
event.preventDefault();
|
||||
this.props.submitForm(this.state);
|
||||
};
|
||||
|
||||
componentWillReceiveProps() {
|
||||
this.setState(this.props.user);
|
||||
}
|
||||
|
||||
render() {
|
||||
const user = this.state;
|
||||
if (user) {
|
||||
return (
|
||||
<div className="container">
|
||||
<form onSubmit={this.submit}>
|
||||
@@ -72,6 +73,9 @@ class UserForm extends React.Component<Props, User> {
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return <div>Loading...</div>;
|
||||
}
|
||||
}
|
||||
|
||||
handleUsernameChange = (name: string) => {
|
||||
|
||||
@@ -2,17 +2,9 @@
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import {
|
||||
fetchUsers,
|
||||
addUser,
|
||||
updateUser,
|
||||
deleteUser,
|
||||
editUser,
|
||||
getUsersFromState
|
||||
} from "../modules/users";
|
||||
import { fetchUsers, deleteUser, getUsersFromState } from "../modules/users";
|
||||
import Loading from "../../components/Loading";
|
||||
import ErrorNotification from "../../components/ErrorNotification";
|
||||
import UserForm from "./UserForm";
|
||||
import UserTable from "./UserTable";
|
||||
import type { User } from "../types/User";
|
||||
import type { UserEntry } from "../types/UserEntry";
|
||||
@@ -22,11 +14,7 @@ type Props = {
|
||||
error: Error,
|
||||
userEntries: Array<UserEntry>,
|
||||
fetchUsers: () => void,
|
||||
deleteUser: User => void,
|
||||
addUser: User => void,
|
||||
updateUser: User => void,
|
||||
editUser: User => void,
|
||||
userToEdit: User
|
||||
deleteUser: User => void
|
||||
};
|
||||
|
||||
class Users extends React.Component<Props, User> {
|
||||
@@ -34,28 +22,6 @@ class Users extends React.Component<Props, User> {
|
||||
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() {
|
||||
return (
|
||||
<section className="section">
|
||||
@@ -69,20 +35,12 @@ class Users extends React.Component<Props, User> {
|
||||
}
|
||||
|
||||
renderContent() {
|
||||
const { userEntries, deleteUser, editUser, userToEdit, error } = this.props;
|
||||
const { userEntries, deleteUser, error } = this.props;
|
||||
if (userEntries) {
|
||||
return (
|
||||
<div>
|
||||
<ErrorNotification error={error} />
|
||||
<UserTable
|
||||
entries={userEntries}
|
||||
deleteUser={deleteUser}
|
||||
editUser={user => editUser(user)}
|
||||
/>
|
||||
<UserForm
|
||||
submitForm={user => this.submitUser(user)}
|
||||
user={userToEdit}
|
||||
/>
|
||||
<UserTable entries={userEntries} deleteUser={deleteUser} />
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
@@ -93,13 +51,8 @@ class Users extends React.Component<Props, User> {
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const userEntries = getUsersFromState(state);
|
||||
const userToEdit = state.users.editUser;
|
||||
if (!userEntries) {
|
||||
return { userToEdit };
|
||||
}
|
||||
return {
|
||||
userEntries,
|
||||
userToEdit,
|
||||
error: state.users.error
|
||||
};
|
||||
};
|
||||
@@ -109,17 +62,8 @@ const mapDispatchToProps = dispatch => {
|
||||
fetchUsers: () => {
|
||||
dispatch(fetchUsers());
|
||||
},
|
||||
addUser: (user: User) => {
|
||||
dispatch(addUser(user));
|
||||
},
|
||||
updateUser: (user: User) => {
|
||||
dispatch(updateUser(user));
|
||||
},
|
||||
deleteUser: (user: User) => {
|
||||
dispatch(deleteUser(user));
|
||||
},
|
||||
editUser: (user: User) => {
|
||||
dispatch(editUser(user));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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_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_SUCCESS = "scm/users/ADD_SUCCESS";
|
||||
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";
|
||||
|
||||
const USERS_URL = "users";
|
||||
const USER_URL = "users/";
|
||||
|
||||
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) {
|
||||
return {
|
||||
type: ADD_USER,
|
||||
@@ -258,7 +303,13 @@ export default function reducer(state: any = {}, action: any = {}) {
|
||||
error: null,
|
||||
entry: action.payload
|
||||
});
|
||||
case FETCH_USER:
|
||||
return reduceUsersByNames(state, action.payload.name, {
|
||||
loading: true,
|
||||
error: null
|
||||
});
|
||||
case FETCH_USERS_SUCCESS:
|
||||
// return red(state, action.payload._embedded.users);
|
||||
const users = action.payload._embedded.users;
|
||||
const userNames = users.map(user => user.name);
|
||||
const usersByNames = extractUsersByNames(
|
||||
@@ -266,7 +317,6 @@ export default function reducer(state: any = {}, action: any = {}) {
|
||||
userNames,
|
||||
state.usersByNames
|
||||
);
|
||||
|
||||
return {
|
||||
...state,
|
||||
users: {
|
||||
@@ -276,6 +326,21 @@ export default function reducer(state: any = {}, action: any = {}) {
|
||||
},
|
||||
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 DELETE_USER_FAILURE:
|
||||
|
||||
Reference in New Issue
Block a user