diff --git a/react/admin-panel/src/AdminDashboard.jsx b/react/admin-panel/src/AdminDashboard.jsx index 436d9b7..d280da5 100644 --- a/react/admin-panel/src/AdminDashboard.jsx +++ b/react/admin-panel/src/AdminDashboard.jsx @@ -13,7 +13,8 @@ import './res/adminlte.min.css'; // views import View404 from "./views/404"; const Overview = lazy(() => import('./views/overview')); -const UserListView = lazy(() => import('./views/user-list')); +const UserListView = lazy(() => import('./views/user/user-list')); +const UserEditView = lazy(() => import('./views/user/user-edit')); const GroupListView = lazy(() => import('./views/group-list')); const EditGroupView = lazy(() => import('./views/group-edit')); @@ -66,6 +67,7 @@ export default function AdminDashboard(props) { }/> }/> }/> + }/> }/> }/> } /> diff --git a/react/admin-panel/src/views/login.jsx b/react/admin-panel/src/views/login.jsx index 279e45e..1fbd39d 100644 --- a/react/admin-panel/src/views/login.jsx +++ b/react/admin-panel/src/views/login.jsx @@ -250,7 +250,7 @@ export default function LoginForm(props) { ? {error} {emailConfirmed === false - ? <> Click here to resend the confirmation email. + ? <> Click here to resend the confirmation email. : <> } diff --git a/react/admin-panel/src/views/user/user-edit.js b/react/admin-panel/src/views/user/user-edit.js new file mode 100644 index 0000000..ebc8883 --- /dev/null +++ b/react/admin-panel/src/views/user/user-edit.js @@ -0,0 +1,89 @@ +import {Link, useNavigate, useParams} from "react-router-dom"; +import {useCallback, useContext, useEffect, useState} from "react"; +import {CircularProgress} from "@material-ui/core"; +import {LocaleContext} from "shared/locale"; +import * as React from "react"; + + +export default function UserEditView(props) { + + const { api, showDialog } = props; + const { userId } = useParams(); + const navigate = useNavigate(); + 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, + } : null); + + useEffect(() => { + requestModules(props.api, ["general", "account"], currentLocale).then(data => { + if (!data.success) { + props.showDialog("Error fetching translations: " + data.msg); + } + }); + }, [currentLocale]); + + const onFetchUser = useCallback((force = false) => { + if (!isNewUser && (force || fetchUser)) { + setFetchUser(false); + api.getUser(userId).then((res) => { + if (!res.success) { + showDialog(res.msg, L("account.error_user_get")); + if (user === null) { + navigate("/admin/users"); + } + } else { + setUser(res.user); + } + }); + } + }, [api, showDialog, fetchUser, isNewUser, userId, user]); + + useEffect(() => { + if (!isNewUser) { + onFetchUser(true); + } + }, []); + + if (user === null) { + return + } + + return
+
+
    +
  1. Home
  2. +
  3. User
  4. +
  5. { isNewUser ? "New" : "Edit" }
  6. +
+
+
+
+

{L(isNewUser ? "Create new User" : "Edit User")}

+
+
+
+ + setUser({...user, name: e.target.value})}/> +
+
+ + setUser({...user, fullName: e.target.value})}/> +
+
+
+
+
+
+} \ No newline at end of file diff --git a/react/admin-panel/src/views/user/user-list.js b/react/admin-panel/src/views/user/user-list.js new file mode 100644 index 0000000..a3402be --- /dev/null +++ b/react/admin-panel/src/views/user/user-list.js @@ -0,0 +1,93 @@ +import {Link, useNavigate} from "react-router-dom"; +import {useCallback, useContext, useEffect, useState} from "react"; +import {LocaleContext} from "shared/locale"; +import { + BoolColumn, + ControlsColumn, + DataColumn, + DataTable, + NumericColumn, + StringColumn +} from "shared/elements/data-table"; +import {Button} from "@material-ui/core"; +import EditIcon from '@mui/icons-material/Edit'; +import {Chip} from "@mui/material"; +import AddIcon from "@mui/icons-material/Add"; +import usePagination from "shared/hooks/pagination"; + + +export default function UserListView(props) { + + const api = props.api; + const showDialog = props.showDialog; + const {translate: L, requestModules, currentLocale} = useContext(LocaleContext); + const navigate = useNavigate(); + const pagination = usePagination(); + const [users, setUsers] = useState([]); + + useEffect(() => { + requestModules(props.api, ["general", "account"], currentLocale).then(data => { + if (!data.success) { + props.showDialog("Error fetching translations: " + data.msg); + } + }); + }, [currentLocale]); + + const onFetchUsers = useCallback((page, count, orderBy, sortOrder) => { + api.fetchUsers(page, count, orderBy, sortOrder).then((res) => { + if (res.success) { + setUsers(res.users); + pagination.update(res.pagination); + } else { + showDialog(res.msg, "Error fetching users"); + return null; + } + }); + }, [api, showDialog]); + + const groupColumn = (() => { + let column = new DataColumn(L("account.groups"), "groups"); + column.renderData = (L, entry) => { + return Object.values(entry.groups).map(group => ) + } + return column; + })(); + + const columnDefinitions = [ + new NumericColumn(L("general.id"), "id"), + new StringColumn(L("account.username"), "name"), + new StringColumn(L("account.full_name"), "fullName"), + new StringColumn(L("account.email"), "email"), + groupColumn, + new BoolColumn(L("account.confirmed"), "confirmed", { align: "center" }), + new ControlsColumn(L("general.controls"), [ + { label: L("general.edit"), element: EditIcon, onClick: (entry) => navigate(`/admin/user/${entry.id}`) } + ]), + ]; + + return
+
+
    +
  1. Home
  2. +
  3. Users
  4. +
+
+
+
+ + + + +
+
+
+} \ No newline at end of file