From 645a88e7e35d15cec6106709c42b071bec045e0d Mon Sep 17 00:00:00 2001 From: crupest Date: Wed, 2 Aug 2023 02:52:07 +0800 Subject: ... --- FrontEnd/src/migrating/admin/Admin.tsx | 27 +++ FrontEnd/src/migrating/admin/AdminNav.tsx | 29 +++ FrontEnd/src/migrating/admin/MoreAdmin.tsx | 7 + FrontEnd/src/migrating/admin/UserAdmin.tsx | 301 +++++++++++++++++++++++++++++ FrontEnd/src/migrating/admin/index.css | 33 ++++ FrontEnd/src/migrating/admin/index.tsx | 7 + 6 files changed, 404 insertions(+) create mode 100644 FrontEnd/src/migrating/admin/Admin.tsx create mode 100644 FrontEnd/src/migrating/admin/AdminNav.tsx create mode 100644 FrontEnd/src/migrating/admin/MoreAdmin.tsx create mode 100644 FrontEnd/src/migrating/admin/UserAdmin.tsx create mode 100644 FrontEnd/src/migrating/admin/index.css create mode 100644 FrontEnd/src/migrating/admin/index.tsx (limited to 'FrontEnd/src/migrating/admin') diff --git a/FrontEnd/src/migrating/admin/Admin.tsx b/FrontEnd/src/migrating/admin/Admin.tsx new file mode 100644 index 00000000..986c36b4 --- /dev/null +++ b/FrontEnd/src/migrating/admin/Admin.tsx @@ -0,0 +1,27 @@ +import { Route, Routes } from "react-router-dom"; +import { useTranslation } from "react-i18next"; + +import AdminNav from "./AdminNav"; +import UserAdmin from "./UserAdmin"; +import MoreAdmin from "./MoreAdmin"; + +import "./index.css"; + +const Admin: React.FC = () => { + useTranslation("admin"); + + return ( + <> +
+ + + } /> + } /> + } /> + +
+ + ); +}; + +export default Admin; diff --git a/FrontEnd/src/migrating/admin/AdminNav.tsx b/FrontEnd/src/migrating/admin/AdminNav.tsx new file mode 100644 index 00000000..b7385e5c --- /dev/null +++ b/FrontEnd/src/migrating/admin/AdminNav.tsx @@ -0,0 +1,29 @@ +import { useLocation } from "react-router-dom"; + +import Tabs from "../common/tab/Tabs"; + +export function AdminNav({ className }: { className?: string }) { + const location = useLocation(); + const name = location.pathname.split("/")[2] ?? "user"; + + return ( + + ); +} + +export default AdminNav; diff --git a/FrontEnd/src/migrating/admin/MoreAdmin.tsx b/FrontEnd/src/migrating/admin/MoreAdmin.tsx new file mode 100644 index 00000000..d49d211f --- /dev/null +++ b/FrontEnd/src/migrating/admin/MoreAdmin.tsx @@ -0,0 +1,7 @@ +import * as React from "react"; + +const MoreAdmin: React.FC = () => { + return <>More...; +}; + +export default MoreAdmin; diff --git a/FrontEnd/src/migrating/admin/UserAdmin.tsx b/FrontEnd/src/migrating/admin/UserAdmin.tsx new file mode 100644 index 00000000..08560c87 --- /dev/null +++ b/FrontEnd/src/migrating/admin/UserAdmin.tsx @@ -0,0 +1,301 @@ +// eslint-disable +// @ts-nocheck + +import { useState, useEffect } from "react"; +import * as React from "react"; +import { Trans, useTranslation } from "react-i18next"; +import classnames from "classnames"; + +import { getHttpUserClient, HttpUser, kUserPermissionList } from "@/http/user"; + +import OperationDialog from "../common/dialog/OperationDialog"; +import Button from "../common/button/Button"; +import Spinner from "../common/Spinner"; +import FlatButton from "../common/button/FlatButton"; +import IconButton from "../common/button/IconButton"; + +const CreateUserDialog: React.FC<{ + open: boolean; + close: () => void; + onSuccess: (user: HttpUser) => void; +}> = ({ open, close, onSuccess }) => { + return ( + + getHttpUserClient().post({ + username: username as string, + password: password as string, + }) + } + onClose={close} + open={open} + onSuccessAndClose={onSuccess} + /> + ); +}; + +const UsernameLabel: React.FC<{ children: React.ReactNode }> = (props) => { + return {props.children}; +}; + +const UserDeleteDialog: React.FC<{ + open: boolean; + close: () => void; + user: HttpUser; + onSuccess: () => void; +}> = ({ open, close, user, onSuccess }) => { + return ( + ( + + 0{user.username}2 + + )} + onProcess={() => getHttpUserClient().delete(user.username)} + onSuccessAndClose={onSuccess} + /> + ); +}; + +const UserModifyDialog: React.FC<{ + open: boolean; + close: () => void; + user: HttpUser; + onSuccess: () => void; +}> = ({ open, close, user, onSuccess }) => { + return ( + + 0{user.username}2 + + } + inputs={ + [ + { + type: "text", + label: "admin:user.username", + initValue: user.username, + }, + { type: "text", label: "admin:user.password" }, + { + type: "text", + label: "admin:user.nickname", + initValue: user.nickname, + }, + ] as const + } + onProcess={([username, password, nickname]) => + getHttpUserClient().patch(user.username, { + username: username !== user.username ? username : undefined, + password: password !== "" ? password : undefined, + nickname: nickname !== user.nickname ? nickname : undefined, + }) + } + onSuccessAndClose={onSuccess} + /> + ); +}; + +const UserPermissionModifyDialog: React.FC<{ + open: boolean; + close: () => void; + user: HttpUser; + onSuccess: () => void; +}> = ({ open, close, user, onSuccess }) => { + const oldPermissionBoolList: boolean[] = kUserPermissionList.map( + (permission) => user.permissions.includes(permission), + ); + + return ( + ( + + 0{user.username}2 + + )} + inputScheme={kUserPermissionList.map( + (permission, index) => ({ + type: "bool", + label: { type: "custom", value: permission }, + initValue: oldPermissionBoolList[index], + }), + )} + onProcess={async (newPermissionBoolList): Promise => { + for (let index = 0; index < kUserPermissionList.length; index++) { + const oldValue = oldPermissionBoolList[index]; + const newValue = newPermissionBoolList[index]; + const permission = kUserPermissionList[index]; + if (oldValue === newValue) continue; + if (newValue) { + await getHttpUserClient().putUserPermission( + user.username, + permission, + ); + } else { + await getHttpUserClient().deleteUserPermission( + user.username, + permission, + ); + } + } + return newPermissionBoolList; + }} + onSuccessAndClose={onSuccess} + /> + ); +}; + +interface UserItemProps { + user: HttpUser; + onChange: () => void; +} + +const UserItem: React.FC = ({ user, onChange }) => { + const { t } = useTranslation(); + + const [dialog, setDialog] = useState< + "delete" | "modify" | "permission" | null + >(null); + + const [editMaskVisible, setEditMaskVisible] = React.useState(false); + + return ( + <> +
+ setEditMaskVisible(true)} + /> +
{user.username}
+ + {t("admin:user.nickname")} + {user.nickname} + + + {t("admin:user.uniqueId")} + {user.uniqueId} + + + {t("admin:user.permissions")} + {user.permissions.map((permission) => { + return ( + + {permission} + + ); + })} + +
setEditMaskVisible(false)} + > + setDialog("modify")} + /> + setDialog("permission")} + /> + setDialog("delete")} + /> +
+
+ setDialog(null)} + user={user} + onSuccess={onChange} + /> + setDialog(null)} + user={user} + onSuccess={onChange} + /> + setDialog(null)} + user={user} + onSuccess={onChange} + /> + + ); +}; + +const UserAdmin: React.FC = () => { + const [users, setUsers] = useState(null); + const [dialog, setDialog] = useState<"create" | null>(null); + const [usersVersion, setUsersVersion] = useState(0); + const updateUsers = (): void => { + setUsersVersion(usersVersion + 1); + }; + + useEffect(() => { + let subscribe = true; + void getHttpUserClient() + .list() + .then((us) => { + if (subscribe) { + setUsers(us.items); + } + }); + return () => { + subscribe = false; + }; + }, [usersVersion]); + + if (users) { + const userComponents = users.map((user) => { + return ( + + ); + }); + + return ( + <> +
+
+
+
+ {userComponents} + setDialog(null)} + onSuccess={updateUsers} + /> + + ); + } else { + return ; + } +}; + +export default UserAdmin; diff --git a/FrontEnd/src/migrating/admin/index.css b/FrontEnd/src/migrating/admin/index.css new file mode 100644 index 00000000..17e24586 --- /dev/null +++ b/FrontEnd/src/migrating/admin/index.css @@ -0,0 +1,33 @@ +.admin-user-item { + position: relative; + border: var(--cru-primary-color) solid; + border-width: 1px 1px 0; + padding: 1em; +} + +.admin-user-item:last-of-type { + border-bottom-width: 1px; +} + +.admin-user-item .edit-mask { + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + background: rgba(255, 255, 255, 0.9); + position: absolute; + display: flex; + justify-content: space-around; + align-items: center; +} + +@media (max-width: 576px) { + .admin-user-item .edit-mask { + flex-direction: column; + } +} + +.admin-user-item .edit-mask button { + margin: 0.5em 2em; +} diff --git a/FrontEnd/src/migrating/admin/index.tsx b/FrontEnd/src/migrating/admin/index.tsx new file mode 100644 index 00000000..0467711d --- /dev/null +++ b/FrontEnd/src/migrating/admin/index.tsx @@ -0,0 +1,7 @@ +import { lazy } from "react"; + +const Admin = lazy( + () => import(/* webpackChunkName: "admin" */ "./Admin") +); + +export default Admin; -- cgit v1.2.3