web-base/react/adminPanel.old/src/views/edituser.js

322 lines
14 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import * as React from "react";
import Icon from "../elements/icon";
import Alert from "../elements/alert";
import {Link} from "react-router-dom";
import "../include/select2.min.css";
export default class EditUser extends React.Component {
constructor(props) {
super(props);
this.parent = {
api: props.api,
showDialog: props.showDialog,
};
this.state = {
user: {},
alerts: [],
fetchError: null,
loaded: false,
isSaving: false,
isDeleting: false,
groups: { },
searchString: "",
searchActive: false
};
this.searchBox = React.createRef();
}
removeAlert(i) {
if (i >= 0 && i < this.state.alerts.length) {
let alerts = this.state.alerts.slice();
alerts.splice(i, 1);
this.setState({...this.state, alerts: alerts});
}
}
componentDidMount() {
this.parent.api.getUser(this.props.match.params["userId"]).then((res) => {
if (res.success) {
this.setState({ ...this.state, user: {
name: res.user.name,
email: res.user.email || "",
groups: res.user.groups,
password: "",
confirmed: res.user.confirmed
}
});
this.parent.api.fetchGroups(1, 50).then((res) => {
if (res.success) {
this.setState({ ...this.state, groups: res.groups, loaded: true });
} else {
this.setState({ ...this.state, fetchError: res.msg, loaded: true });
}
});
} else {
this.setState({ ...this.state, fetchError: res.msg, loaded: true });
}
});
}
onChangeInput(event) {
const target = event.target;
let value = target.value;
const name = target.name;
if (target.type === "checkbox") {
value = !!target.checked;
}
if (name === "search") {
this.setState({...this.state, searchString: value});
} else {
this.setState({ ...this.state, user: { ...this.state.user, [name]: value } });
}
}
onToggleSearch(e) {
e.stopPropagation();
this.setState({ ...this.state, searchActive: !this.state.searchActive });
this.searchBox.current.focus();
}
onSubmitForm(event) {
event.preventDefault();
event.stopPropagation();
const id = this.props.match.params["userId"];
const username = this.state.user["name"];
const email = this.state.user["email"];
let password = this.state.user["password"].length > 0 ? this.state.user["password"] : null;
let groups = Object.keys(this.state.user.groups);
let confirmed = this.state.user["confirmed"];
this.setState({ ...this.state, isSaving: true});
this.parent.api.editUser(id, username, email, password, groups, confirmed).then((res) => {
let alerts = this.state.alerts.slice();
if (res.success) {
alerts.push({ title: "Success", message: "User was successfully updated.", type: "success" });
this.setState({ ...this.state, isSaving: false, alerts: alerts, user: { ...this.state.user, password: "" } });
} else {
alerts.push({ title: "Error updating user", message: res.msg, type: "danger" });
this.setState({ ...this.state, isSaving: false, alerts: alerts, user: { ...this.state.user, password: "" } });
}
});
}
onDeleteUser(event) {
event.preventDefault();
event.stopPropagation();
const id = this.props.match.params["userId"];
this.parent.showDialog("Are you sure you want to delete this user permanently?", "Delete User?", ["Yes", "No"], (btn) => {
if (btn === "Yes") {
this.parent.api.deleteUser(id).then((res) => {
if (res.success) {
this.props.history.push("/admin/users");
} else {
let alerts = this.state.alerts.slice();
alerts.push({ title: "Error deleting user", message: res.msg, type: "danger" });
this.setState({ ...this.state, isSaving: false, alerts: alerts, user: { ...this.state.user, password: "" } });
}
})
}
});
}
onRemoveGroup(event, groupId) {
event.stopPropagation();
if (this.state.user.groups.hasOwnProperty(groupId)) {
let groups = { ...this.state.user.groups };
delete groups[groupId];
this.setState({ ...this.state, user: { ...this.state.user, groups: groups }});
}
}
onAddGroup(event, groupId) {
event.stopPropagation();
if (!this.state.user.groups.hasOwnProperty(groupId)) {
let groups = { ...this.state.user.groups, [groupId]: { ...this.state.groups[groupId] } };
this.setState({ ...this.state, user: { ...this.state.user, groups: groups }, searchActive: false, searchString: "" });
}
}
render() {
if (!this.state.loaded) {
return <h2 className={"text-center"}>
Loading<br/>
<Icon icon={"spinner"} className={"mt-3 text-muted fa-2x"}/>
</h2>
}
let alerts = [];
let form = null;
if(this.state.fetchError) {
alerts.push(
<Alert key={"error-fetch"} title={"Error fetching data"} type={"danger"} message={
<div>{this.state.fetchError}<br/>You can meanwhile return to the&nbsp;
<Link to={"/admin/users"}>user overview</Link>
</div>
}/>
)
} else {
for (let i = 0; i < this.state.alerts.length; i++) {
alerts.push(<Alert key={"error-" + i} onClose={() => this.removeAlert(i)} {...this.state.alerts[i]}/>)
}
let possibleOptions = [];
let renderedOptions = [];
for (let groupId in this.state.groups) {
if (this.state.groups.hasOwnProperty(groupId)) {
let groupName = this.state.groups[groupId].name;
let groupColor = this.state.groups[groupId].color;
if (this.state.user.groups.hasOwnProperty(groupId)) {
renderedOptions.push(
<li className={"select2-selection__choice"} key={"group-" + groupId} title={groupName} style={{backgroundColor: groupColor}}>
<span className="select2-selection__choice__remove" role="presentation"
onClick={(e) => this.onRemoveGroup(e, groupId)}>
×
</span>
{groupName}
</li>
);
} else {
if (this.state.searchString.length === 0 || groupName.toLowerCase().includes(this.state.searchString.toLowerCase())) {
possibleOptions.push(
<li className={"select2-results__option"} role={"option"} key={"group-" + groupId} aria-selected={false}
onClick={(e) => this.onAddGroup(e, groupId)}>
{groupName}
</li>
);
}
}
}
}
let searchWidth = "100%";
let placeholder = "Select Groups";
let searchVisible = (this.state.searchString.length > 0 || this.state.searchActive) ? "block" : "none";
if (renderedOptions.length > 0) {
searchWidth = (0.75 + this.state.searchString.length * 0.75) + "em";
placeholder = "";
}
if (this.state.searchString.length > 0 && possibleOptions.length === 0) {
possibleOptions.push(
<li className={"select2-results__option"} role={"option"} key={"group-notfound"} aria-selected={true}>
Group not found
</li>
);
}
form = <form role={"form"} onSubmit={(e) => e.preventDefault()}>
<div className={"form-group"}>
<label htmlFor={"username"}>Username</label>
<input type={"text"} className={"form-control"} placeholder={"Enter username"}
name={"username"} id={"username"} maxLength={32} value={this.state.user.name}
onChange={this.onChangeInput.bind(this)}/>
</div>
<div className={"form-group"}>
<label htmlFor={"email"}>E-Mail</label>
<input type={"email"} className={"form-control"} placeholder={"E-Mail address"}
id={"email"} name={"email"} maxLength={64} value={this.state.user.email}
onChange={this.onChangeInput.bind(this)}/>
</div>
<div className={"form-group"}>
<label htmlFor={"password"}>Password</label>
<input type={"password"} className={"form-control"} placeholder={"(unchanged)"}
id={"password"} name={"password"} value={this.state.user.password}
onChange={this.onChangeInput.bind(this)}/>
</div>
<div className={"form-group position-relative"}>
<label>Groups</label>
<span className={"select2 select2-container select2-container--default select2-container--below"}
dir={"ltr"} style={{width: "100%"}} >
<span className="selection">
<span className={"select2-selection select2-selection--multiple"} role={"combobox"} aria-haspopup={"true"}
aria-expanded={false} aria-disabled={false} onClick={this.onToggleSearch.bind(this)}>
<ul className={"select2-selection__rendered"}>
{renderedOptions}
<li className={"select2-search select2-search--inline"}>
<input className={"select2-search__field"} type={"search"} tabIndex={0}
autoComplete={"off"} autoCorrect={"off"} autoCapitalize={"none"} spellCheck={false}
role={"searchbox"} aria-autocomplete={"list"} placeholder={placeholder}
name={"search"} style={{width: searchWidth}} value={this.state.searchString}
onChange={this.onChangeInput.bind(this)} ref={this.searchBox} />
</li>
</ul>
</span>
</span>
<span className="dropdown-wrapper" aria-hidden="true"/>
</span>
<span className={"select2-container select2-container--default select2-container--open"}
style={{position: "absolute", bottom: 0, left: 0, width: "100%", display: searchVisible}}>
<span className={"select2-dropdown select2-dropdown--below"} dir={"ltr"}>
<span className={"select2-results"}>
<ul className={"select2-results__options"} role={"listbox"}
aria-multiselectable={true} aria-expanded={true} aria-hidden={false}>
{possibleOptions}
</ul>
</span>
</span>
</span>
</div>
<div className={"form-check"}>
<input type={"checkbox"} className={"form-check-input"}
onChange={this.onChangeInput.bind(this)}
id={"confirmed"} name={"confirmed"} checked={this.state.user.confirmed}/>
<label className={"form-check-label"} htmlFor={"confirmed"}>
Confirmed
</label>
</div>
<Link to={"/admin/users"} className={"btn btn-info mt-2 mr-2"}>
<Icon icon={"arrow-left"}/>
&nbsp;Back
</Link>
{ this.state.isSaving
? <button type={"submit"} className={"btn btn-primary mt-2 mr-2"} disabled>Saving&nbsp;<Icon icon={"circle-notch"} /></button>
: <button type={"submit"} className={"btn btn-primary mt-2 mr-2"} onClick={this.onSubmitForm.bind(this)}>Save</button>
}
{ this.state.isDeleting
? <button type={"submit"} className={"btn btn-danger mt-2"} disabled>Deleting&nbsp;<Icon icon={"circle-notch"} /></button>
: <button type={"submit"} className={"btn btn-danger mt-2"} onClick={this.onDeleteUser.bind(this)}>Delete</button>
}
</form>
}
return <>
<div className="content-header">
<div className="container-fluid">
<div className="row mb-2">
<div className="col-sm-6">
<h1 className="m-0 text-dark">Edit User</h1>
</div>
<div className="col-sm-6">
<ol className="breadcrumb float-sm-right">
<li className="breadcrumb-item"><Link to={"/admin/dashboard"}>Home</Link></li>
<li className="breadcrumb-item"><Link to={"/admin/users"}>Users</Link></li>
<li className="breadcrumb-item active">Add User</li>
</ol>
</div>
</div>
</div>
</div>
<div className={"content"}>
<div className={"row"}>
<div className={"col-lg-6 pl-5 pr-5"}>
{alerts}
{form}
</div>
</div>
</div>
</>
}
}