User Create/Edit/Invite frontend + backend
This commit is contained in:
@@ -10,7 +10,6 @@ import {
|
||||
import { Dropdown } from '@mui/base/Dropdown';
|
||||
import ChevronRightIcon from '@mui/icons-material/ChevronRight';
|
||||
import ChevronLeftIcon from '@mui/icons-material/ChevronLeft';
|
||||
import ProfilePicture from "shared/elements/profile-picture";
|
||||
import {Dns, Groups, People, QueryStats, Security, Settings, Route, ArrowBack, Translate} from "@mui/icons-material";
|
||||
import useCurrentPath from "shared/hooks/current-path";
|
||||
import ProfileLink from "./profile-link";
|
||||
|
||||
@@ -107,7 +107,7 @@ export default function EditProfilePicture(props) {
|
||||
|
||||
if (croppedSize < 150) {
|
||||
setImage({ loading: false, file: null, data: null });
|
||||
showDialog(L("account.profile_picture_invalid_dimensions"), L("general.error"));
|
||||
showDialog(L("account.profile_picture_invalid_dimensions"), L("general.error_occurred"));
|
||||
} else {
|
||||
setImage({ loading: false, file: file, data: imageData });
|
||||
}
|
||||
|
||||
@@ -7,17 +7,28 @@ import {
|
||||
CircularProgress,
|
||||
FormControl,
|
||||
FormControlLabel,
|
||||
FormLabel,
|
||||
TextField
|
||||
FormLabel, Grid,
|
||||
TextField,
|
||||
FormGroup as MuiFormGroup
|
||||
} from "@mui/material";
|
||||
import {LocaleContext} from "shared/locale";
|
||||
import * as React from "react";
|
||||
import ViewContent from "../../elements/view-content";
|
||||
import FormGroup from "../../elements/form-group";
|
||||
import ButtonBar from "../../elements/button-bar";
|
||||
import {RestartAlt, Save} from "@mui/icons-material";
|
||||
import {parseBool} from "shared/util";
|
||||
import SpacedFormGroup from "../../elements/form-group";
|
||||
import {RestartAlt, Save, Send} from "@mui/icons-material";
|
||||
import PasswordStrength from "shared/elements/password-strength";
|
||||
|
||||
const initialUser = {
|
||||
name: "",
|
||||
fullName: "",
|
||||
email: "",
|
||||
password: "",
|
||||
passwordConfirm: "",
|
||||
groups: [],
|
||||
confirmed: false,
|
||||
active: true,
|
||||
};
|
||||
|
||||
export default function UserEditView(props) {
|
||||
|
||||
@@ -30,19 +41,12 @@ export default function UserEditView(props) {
|
||||
const isNewUser = userId === "new";
|
||||
const {translate: L, requestModules, currentLocale} = useContext(LocaleContext);
|
||||
const [fetchUser, setFetchUser] = useState(!isNewUser);
|
||||
const [user, setUser] = useState(isNewUser ? {
|
||||
name: "",
|
||||
fullName: "",
|
||||
email: "",
|
||||
password: "",
|
||||
groups: [],
|
||||
confirmed: false,
|
||||
active: true,
|
||||
} : null);
|
||||
const [user, setUser] = useState(isNewUser ? initialUser : null);
|
||||
|
||||
// ui
|
||||
const [hasChanged, setChanged] = useState(isNewUser);
|
||||
const [isSaving, setSaving] = useState(false);
|
||||
const [sendInvite, setSetInvite] = useState(isNewUser);
|
||||
|
||||
useEffect(() => {
|
||||
requestModules(props.api, ["general", "account"], currentLocale).then(data => {
|
||||
@@ -52,14 +56,6 @@ export default function UserEditView(props) {
|
||||
});
|
||||
}, [currentLocale]);
|
||||
|
||||
const onReset = useCallback(() => {
|
||||
|
||||
}, []);
|
||||
|
||||
const onSaveUser = useCallback(() => {
|
||||
|
||||
}, []);
|
||||
|
||||
const onFetchUser = useCallback((force = false) => {
|
||||
if (!isNewUser && (force || fetchUser)) {
|
||||
setFetchUser(false);
|
||||
@@ -76,9 +72,60 @@ export default function UserEditView(props) {
|
||||
}
|
||||
}, [api, showDialog, fetchUser, isNewUser, userId, user]);
|
||||
|
||||
const onChangeValue = useCallback((name, value) => {
|
||||
const onReset = useCallback(() => {
|
||||
if (isNewUser) {
|
||||
setUser({...initialUser});
|
||||
} else {
|
||||
onFetchUser(true);
|
||||
}
|
||||
}, [isNewUser, onFetchUser]);
|
||||
|
||||
}, []);
|
||||
const onSaveUser = useCallback(() => {
|
||||
if (!isSaving) {
|
||||
setSaving(true);
|
||||
if (isNewUser) {
|
||||
if (sendInvite) {
|
||||
api.inviteUser(user.name, user.fullName, user.email).then(res => {
|
||||
setSaving(false);
|
||||
if (res.success) {
|
||||
setChanged(false);
|
||||
navigate("/admin/user/" + res.userId);
|
||||
} else {
|
||||
showDialog(res.msg, L("account.invite_user_error"));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
api.createUser(user.name, user.fullName, user.email, user.password, user.passwordConfirm).then(res => {
|
||||
setSaving(false);
|
||||
if (res.success) {
|
||||
setChanged(false);
|
||||
navigate("/admin/user/" + res.userId);
|
||||
} else {
|
||||
showDialog(res.msg, L("account.create_user_error"));
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
api.editUser(
|
||||
userId, user.name, user.email, user.password,
|
||||
user.groups, user.confirmed, user.active
|
||||
).then(res => {
|
||||
setSaving(false);
|
||||
if (res.success) {
|
||||
setChanged(false);
|
||||
} else {
|
||||
showDialog(res.msg, L("account.save_user_error"));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}, [isSaving, sendInvite, isNewUser, userId, showDialog]);
|
||||
|
||||
const onChangeValue = useCallback((name, value) => {
|
||||
setUser({...user, [name]: value});
|
||||
setChanged(true);
|
||||
}, [user]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isNewUser) {
|
||||
@@ -95,7 +142,8 @@ export default function UserEditView(props) {
|
||||
<Link key={"users"} to={"/admin/users"}>User</Link>,
|
||||
<span key={"action"}>{isNewUser ? "New" : "Edit"}</span>
|
||||
]}>
|
||||
<Box>
|
||||
<Grid container>
|
||||
<Grid item xs={12} lg={6}>
|
||||
<FormGroup>
|
||||
<FormLabel>{L("account.name")}</FormLabel>
|
||||
<FormControl>
|
||||
@@ -124,12 +172,22 @@ export default function UserEditView(props) {
|
||||
{ !isNewUser ?
|
||||
<>
|
||||
<FormGroup>
|
||||
<FormLabel>{L("account.password")}</FormLabel>
|
||||
<FormControl>
|
||||
<TextField size={"small"} variant={"outlined"}
|
||||
value={user.password}
|
||||
type={"password"}
|
||||
placeholder={"(" + L("general.unchanged") + ")"}
|
||||
onChange={e => setUser({...user, password: e.target.value})} />
|
||||
</FormControl>
|
||||
</FormGroup>
|
||||
<MuiFormGroup>
|
||||
<FormControlLabel
|
||||
control={<Checkbox
|
||||
checked={!!user.active}
|
||||
onChange={(e, v) => onChangeValue("active", v)} />}
|
||||
label={L("account.active")} />
|
||||
</FormGroup>
|
||||
</MuiFormGroup>
|
||||
<FormGroup>
|
||||
<FormControlLabel
|
||||
control={<Checkbox
|
||||
@@ -138,18 +196,52 @@ export default function UserEditView(props) {
|
||||
label={L("account.confirmed")} />
|
||||
</FormGroup>
|
||||
</> : <>
|
||||
|
||||
|
||||
<FormGroup>
|
||||
<FormControlLabel
|
||||
control={<Checkbox
|
||||
checked={sendInvite}
|
||||
onChange={(e, v) => setSetInvite(v)} />}
|
||||
label={L("account.send_invite")} />
|
||||
</FormGroup>
|
||||
{!sendInvite && <>
|
||||
<FormGroup>
|
||||
<FormLabel>{L("account.password")}</FormLabel>
|
||||
<FormControl>
|
||||
<TextField size={"small"} variant={"outlined"}
|
||||
value={user.password}
|
||||
type={"password"}
|
||||
onChange={e => setUser({...user, password: e.target.value})} />
|
||||
</FormControl>
|
||||
</FormGroup>
|
||||
<FormGroup>
|
||||
<FormLabel>{L("account.password_confirm")}</FormLabel>
|
||||
<FormControl>
|
||||
<TextField size={"small"} variant={"outlined"}
|
||||
value={user.passwordConfirm}
|
||||
type={"password"}
|
||||
onChange={e => setUser({...user, passwordConfirm: e.target.value})} />
|
||||
</FormControl>
|
||||
</FormGroup>
|
||||
<Box mb={2}>
|
||||
<PasswordStrength password={user.password} />
|
||||
</Box>
|
||||
</>
|
||||
}
|
||||
</>
|
||||
}
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<ButtonBar>
|
||||
<Button color={"primary"}
|
||||
onClick={onSaveUser}
|
||||
disabled={isSaving || !(isNewUser ? api.hasPermission("user/create") : api.hasPermission("user/edit"))}
|
||||
startIcon={isSaving ? <CircularProgress size={14} /> : <Save />}
|
||||
startIcon={isSaving ?
|
||||
<CircularProgress size={14} /> :
|
||||
(sendInvite ? <Send /> : <Save /> )}
|
||||
variant={"outlined"} title={L(hasChanged ? "general.unsaved_changes" : "general.save")}>
|
||||
{isSaving ? L("general.saving") + "…" : (L("general.save") + (hasChanged ? " *" : ""))}
|
||||
{isSaving ?
|
||||
L(sendInvite ? "general.sending" : "general.saving") + "…" :
|
||||
(L(sendInvite ? "general.send" : "general.save") + (hasChanged ? " *" : ""))}
|
||||
</Button>
|
||||
<Button color={"error"}
|
||||
onClick={onReset}
|
||||
|
||||
@@ -127,10 +127,11 @@ export default class API {
|
||||
return res;
|
||||
}
|
||||
|
||||
async editUser(id, username, email, password, groups, confirmed) {
|
||||
async editUser(id, username, email, password, groups, confirmed, active) {
|
||||
return this.apiCall("user/edit", {
|
||||
id: id, username: username, email: email,
|
||||
password: password, groups: groups, confirmed: confirmed
|
||||
password: password, groups: groups,
|
||||
confirmed: confirmed, active: active
|
||||
});
|
||||
}
|
||||
|
||||
@@ -158,12 +159,15 @@ export default class API {
|
||||
return this.apiCall("user/fetch", { page: pageNum, count: count, orderBy: orderBy, sortOrder: sortOrder });
|
||||
}
|
||||
|
||||
async inviteUser(username, email) {
|
||||
return this.apiCall("user/invite", { username: username, email: email });
|
||||
async inviteUser(username, fullName, email) {
|
||||
return this.apiCall("user/invite", { username: username, fullName: fullName, email: email });
|
||||
}
|
||||
|
||||
async createUser(username, email, password, confirmPassword) {
|
||||
return this.apiCall("user/create", { username: username, email: email, password: password, confirmPassword: confirmPassword });
|
||||
async createUser(username, fullName, email, password, confirmPassword) {
|
||||
return this.apiCall("user/create", { username: username, email: email,
|
||||
fullName: fullName,
|
||||
password: password, confirmPassword: confirmPassword
|
||||
});
|
||||
}
|
||||
|
||||
async searchUser(query) {
|
||||
|
||||
Reference in New Issue
Block a user