diff options
Diffstat (limited to 'FrontEnd/src')
-rw-r--r-- | FrontEnd/src/app/http/user.ts | 8 | ||||
-rw-r--r-- | FrontEnd/src/app/views/admin/Admin.tsx | 64 | ||||
-rw-r--r-- | FrontEnd/src/app/views/admin/AdminSubPage.tsx | 44 | ||||
-rw-r--r-- | FrontEnd/src/app/views/admin/UserAdmin.tsx | 80 |
4 files changed, 80 insertions, 116 deletions
diff --git a/FrontEnd/src/app/http/user.ts b/FrontEnd/src/app/http/user.ts index 9ba6508f..92a6433e 100644 --- a/FrontEnd/src/app/http/user.ts +++ b/FrontEnd/src/app/http/user.ts @@ -49,6 +49,7 @@ export class HttpChangePasswordBadCredentialError extends Error { } export interface IHttpUserClient { + list(): Promise<HttpUser[]>; get(username: string): Promise<HttpUser>; patch( username: string, @@ -75,6 +76,13 @@ export interface IHttpUserClient { } export class HttpUserClient implements IHttpUserClient { + list(): Promise<HttpUser[]> { + return axios + .get<HttpUser[]>(`${apiBaseUrl}/users`) + .then(extractResponseData) + .catch(convertToNetworkError); + } + get(username: string): Promise<HttpUser> { return axios .get<HttpUser>(`${apiBaseUrl}/users/${username}`) diff --git a/FrontEnd/src/app/views/admin/Admin.tsx b/FrontEnd/src/app/views/admin/Admin.tsx index a64a9bc0..e17da5bc 100644 --- a/FrontEnd/src/app/views/admin/Admin.tsx +++ b/FrontEnd/src/app/views/admin/Admin.tsx @@ -1,12 +1,5 @@ import React, { Fragment } from "react"; -import { - Redirect, - Route, - Switch, - useRouteMatch, - useHistory, -} from "react-router"; -import { Nav } from "react-bootstrap"; +import { Redirect, Route, Switch, useRouteMatch, match } from "react-router"; import { AuthUser } from "@/services/user"; @@ -16,57 +9,22 @@ interface AdminProps { user: AuthUser; } -const Admin: React.FC<AdminProps> = (props) => { +const Admin: React.FC<AdminProps> = ({ user }) => { const match = useRouteMatch(); - const history = useHistory(); - type TabNames = "users" | "more"; - - const tabName = history.location.pathname.replace(match.path + "/", ""); - - function toggle(newTab: TabNames): void { - history.push(`${match.url}/${newTab}`); - } - - const createRoute = ( - name: string, - body: React.ReactNode - ): React.ReactNode => { - return ( - <Route path={`${match.path}/${name}`}> - <div style={{ height: 56 }} className="flex-fix-length" /> - <Nav variant="tabs"> - <Nav.Item> - <Nav.Link - active={tabName === "users"} - onClick={() => { - toggle("users"); - }} - > - Users - </Nav.Link> - </Nav.Item> - <Nav.Item> - <Nav.Link - active={tabName === "more"} - onClick={() => { - toggle("more"); - }} - > - More - </Nav.Link> - </Nav.Item> - </Nav> - {body} - </Route> - ); - }; return ( <Fragment> <Switch> <Redirect from={match.path} to={`${match.path}/users`} exact /> - {createRoute("users", <UserAdmin user={props.user} />)} - {createRoute("more", <div>More Page Works</div>)} + <Route path={`${match.path}/:name`}> + {(p) => { + const match = p.match as match<{ name: string }>; + const name = match.params["name"]; + if (name === "users") { + return <UserAdmin user={user} />; + } + }} + </Route> </Switch> </Fragment> ); diff --git a/FrontEnd/src/app/views/admin/AdminSubPage.tsx b/FrontEnd/src/app/views/admin/AdminSubPage.tsx new file mode 100644 index 00000000..5d2df13c --- /dev/null +++ b/FrontEnd/src/app/views/admin/AdminSubPage.tsx @@ -0,0 +1,44 @@ +import React from "react"; +import { Nav } from "react-bootstrap"; +import { useHistory, useRouteMatch } from "react-router"; + +const AdminSubPage: React.FC = ({ children }) => { + const match = useRouteMatch<{ name: string }>(); + const history = useHistory(); + + const name = match.params.name; + + function toggle(newTab: string): void { + history.push(`/admin/${newTab}`); + } + + return ( + <> + <Nav variant="tabs"> + <Nav.Item> + <Nav.Link + active={name === "users"} + onClick={() => { + toggle("users"); + }} + > + Users + </Nav.Link> + </Nav.Item> + <Nav.Item> + <Nav.Link + active={name === "more"} + onClick={() => { + toggle("more"); + }} + > + More + </Nav.Link> + </Nav.Item> + </Nav> + {children} + </> + ); +}; + +export default AdminSubPage; diff --git a/FrontEnd/src/app/views/admin/UserAdmin.tsx b/FrontEnd/src/app/views/admin/UserAdmin.tsx index 4ad9ed09..856e6136 100644 --- a/FrontEnd/src/app/views/admin/UserAdmin.tsx +++ b/FrontEnd/src/app/views/admin/UserAdmin.tsx @@ -10,19 +10,16 @@ import { } from "react-bootstrap"; import OperationDialog from "../common/OperationDialog"; +import AdminSubPage from "./AdminSubPage"; + import { User, AuthUser } from "@/services/user"; +import { getHttpUserClient } from "@/http/user"; const apiBaseUrl = "/api"; -async function fetchUserList(_token: string): Promise<User[]> { - const res = await axios.get<User[]>(`${apiBaseUrl}/users`); - return res.data; -} - interface CreateUserInfo { username: string; password: string; - administrator: boolean; } async function createUser(user: CreateUserInfo, token: string): Promise<User> { @@ -57,16 +54,6 @@ function changePassword( }); } -function changePermission( - username: string, - newPermission: boolean, - token: string -): Promise<void> { - return axios.patch(`${apiBaseUrl}/users/${username}?token=${token}`, { - administrator: newPermission, - }); -} - const kChangeUsername = "changeusername"; const kChangePassword = "changepassword"; const kChangePermission = "changepermission"; @@ -103,9 +90,9 @@ const UserItem: React.FC<UserCardProps> = (props) => { <Col> <p className="mb-0 text-primary">{user.username}</p> <small - className={user.administrator ? "text-danger" : "text-secondary"} + className={user.permissions ? "text-danger" : "text-secondary"} > - {user.administrator ? "administrator" : "user"} + {user.permissions ? "administrator" : "user"} </small> </Col> <Col className="col-auto"> @@ -156,14 +143,12 @@ const CreateUserDialog: React.FC<CreateUserDialogProps> = (props) => { [ { type: "text", label: "Username" }, { type: "text", label: "Password" }, - { type: "bool", label: "Administrator" }, ] as const } - onProcess={([username, password, administrator]) => + onProcess={([username, password]) => props.process({ username: username, password: password, - administrator: administrator, }) } close={props.close} @@ -316,15 +301,17 @@ const UserAdmin: React.FC<UserAdminProps> = (props) => { useEffect(() => { let subscribe = true; - void fetchUserList(props.user.token).then((us) => { - if (subscribe) { - setUsers(us); - } - }); + void getHttpUserClient() + .list() + .then((us) => { + if (subscribe) { + setUsers(us); + } + }); return () => { subscribe = false; }; - }, [props.user]); + }, []); let dialogNode: React.ReactNode; if (dialog) @@ -389,26 +376,6 @@ const UserAdmin: React.FC<UserAdminProps> = (props) => { ); break; case kChangePermission: { - const newPermission = dialog.newPermission; - dialogNode = ( - <UserChangePermissionDialog - open - close={() => setDialog(null)} - username={dialog.username} - newPermission={newPermission} - process={async () => { - await changePermission(dialog.username, newPermission, token); - setUsers((oldUsers) => { - const users = (oldUsers ?? []).slice(); - const findedUser = users.find( - (u) => u.username === dialog.username - ); - if (findedUser) findedUser.administrator = newPermission; - return users; - }); - }} - /> - ); break; } } @@ -419,26 +386,13 @@ const UserAdmin: React.FC<UserAdminProps> = (props) => { <UserItem key={user.username} user={user} - onContextMenu={(item) => { - setDialog( - item === kChangePermission - ? { - type: kChangePermission, - username: user.username, - newPermission: !user.administrator, - } - : { - type: item, - username: user.username, - } - ); - }} + onContextMenu={(item) => {}} /> ); }); return ( - <> + <AdminSubPage> <Button variant="success" onClick={() => @@ -452,7 +406,7 @@ const UserAdmin: React.FC<UserAdminProps> = (props) => { </Button> {userComponents} {dialogNode} - </> + </AdminSubPage> ); } else { return <Spinner animation="border" />; |