import React, { useState, useEffect } from "react"; import axios from "axios"; import { ListGroup, Row, Col, Dropdown, Spinner, Button, } from "react-bootstrap"; import OperationDialog from "../common/OperationDialog"; import { User, UserWithToken } from "@/services/user"; const apiBaseUrl = "/api"; async function fetchUserList(_token: string): Promise { const res = await axios.get(`${apiBaseUrl}/users`); return res.data; } interface CreateUserInfo { username: string; password: string; administrator: boolean; } async function createUser(user: CreateUserInfo, token: string): Promise { const res = await axios.post( `${apiBaseUrl}/userop/createuser?token=${token}`, user ); return res.data; } function deleteUser(username: string, token: string): Promise { return axios.delete(`${apiBaseUrl}/users/${username}?token=${token}`); } function changeUsername( oldUsername: string, newUsername: string, token: string ): Promise { return axios.patch(`${apiBaseUrl}/users/${oldUsername}?token=${token}`, { username: newUsername, }); } function changePassword( username: string, newPassword: string, token: string ): Promise { return axios.patch(`${apiBaseUrl}/users/${username}?token=${token}`, { password: newPassword, }); } function changePermission( username: string, newPermission: boolean, token: string ): Promise { return axios.patch(`${apiBaseUrl}/users/${username}?token=${token}`, { administrator: newPermission, }); } const kChangeUsername = "changeusername"; const kChangePassword = "changepassword"; const kChangePermission = "changepermission"; const kDelete = "delete"; type TChangeUsername = typeof kChangeUsername; type TChangePassword = typeof kChangePassword; type TChangePermission = typeof kChangePermission; type TDelete = typeof kDelete; type ContextMenuItem = | TChangeUsername | TChangePassword | TChangePermission | TDelete; interface UserCardProps { onContextMenu: (item: ContextMenuItem) => void; user: User; } const UserItem: React.FC = (props) => { const user = props.user; const createClickCallback = (item: ContextMenuItem): (() => void) => { return () => { props.onContextMenu(item); }; }; return (

{user.username}

{user.administrator ? "administrator" : "user"} Manage Change Username Change Password Change Permission Delete
); }; interface DialogProps { open: boolean; close: () => void; } interface CreateUserDialogProps extends DialogProps { process: (user: CreateUserInfo) => Promise; } const CreateUserDialog: React.FC = (props) => { return ( props.process({ username: username as string, password: password as string, administrator: administrator as boolean, }) } close={props.close} open={props.open} /> ); }; const UsernameLabel: React.FC = (props) => { return {props.children}; }; interface UserDeleteDialogProps extends DialogProps { username: string; process: () => Promise; } const UserDeleteDialog: React.FC = (props) => { return ( ( <> {"You are deleting user "} {props.username} {" !"} )} onProcess={props.process} /> ); }; interface UserModifyDialogProps extends DialogProps { username: string; process: (value: T) => Promise; } const UserChangeUsernameDialog: React.FC> = ( props ) => { return ( ( <> {"You are change the username of user "} {props.username} {" !"} )} inputScheme={[{ type: "text", label: "New Username" }]} onProcess={([newUsername]) => { return props.process(newUsername as string); }} /> ); }; const UserChangePasswordDialog: React.FC> = ( props ) => { return ( ( <> {"You are change the password of user "} {props.username} {" !"} )} inputScheme={[{ type: "text", label: "New Password" }]} onProcess={([newPassword]) => { return props.process(newPassword as string); }} /> ); }; interface UserChangePermissionDialogProps extends DialogProps { username: string; newPermission: boolean; process: () => Promise; } const UserChangePermissionDialog: React.FC = ( props ) => { return ( ( <> {"You are change user "} {props.username} {" to "} {props.newPermission ? "administrator" : "normal user"} {" !"} )} onProcess={props.process} /> ); }; interface UserAdminProps { user: UserWithToken; } const UserAdmin: React.FC = (props) => { type DialogInfo = | null | { type: "create"; } | { type: TDelete; username: string } | { type: TChangeUsername; username: string; } | { type: TChangePassword; username: string; } | { type: TChangePermission; username: string; newPermission: boolean; }; const [users, setUsers] = useState(null); const [dialog, setDialog] = useState(null); const token = props.user.token; useEffect(() => { let subscribe = true; void fetchUserList(props.user.token).then((us) => { if (subscribe) { setUsers(us); } }); return () => { subscribe = false; }; }, [props.user]); let dialogNode: React.ReactNode; if (dialog) switch (dialog.type) { case "create": dialogNode = ( setDialog(null)} process={async (user) => { const u = await createUser(user, token); setUsers((oldUsers) => [...(oldUsers ?? []), u]); }} /> ); break; case "delete": dialogNode = ( setDialog(null)} username={dialog.username} process={async () => { await deleteUser(dialog.username, token); setUsers((oldUsers) => (oldUsers ?? []).filter((u) => u.username !== dialog.username) ); }} /> ); break; case kChangeUsername: dialogNode = ( setDialog(null)} username={dialog.username} process={async (newUsername) => { await changeUsername(dialog.username, newUsername, token); setUsers((oldUsers) => { const users = (oldUsers ?? []).slice(); const findedUser = users.find( (u) => u.username === dialog.username ); if (findedUser) findedUser.username = newUsername; return users; }); }} /> ); break; case kChangePassword: dialogNode = ( setDialog(null)} username={dialog.username} process={async (newPassword) => { await changePassword(dialog.username, newPassword, token); }} /> ); break; case kChangePermission: { const newPermission = dialog.newPermission; dialogNode = ( 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; } } if (users) { const userComponents = users.map((user) => { return ( { setDialog( item === kChangePermission ? { type: kChangePermission, username: user.username, newPermission: !user.administrator, } : { type: item, username: user.username, } ); }} /> ); }); return ( <> {userComponents} {dialogNode} ); } else { return ; } }; export default UserAdmin;