Skip to content

Commit f8a243b

Browse files
committed
Merge remote-tracking branch 'origin/feature/add-user-management-admin'
2 parents 4670928 + 5ac0660 commit f8a243b

File tree

4 files changed

+110
-7
lines changed

4 files changed

+110
-7
lines changed

apps/pyconkr-admin/src/components/layouts/admin_list.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import { BackendAdminSignInGuard } from "../elements/admin_signin_guard";
2121
type AdminListProps = {
2222
app: string;
2323
resource: string;
24+
hideCreatedAt?: boolean;
25+
hideUpdatedAt?: boolean;
2426
};
2527

2628
type ListRowType = {
@@ -32,7 +34,7 @@ type ListRowType = {
3234

3335
const InnerAdminList: React.FC<AdminListProps> = ErrorBoundary.with(
3436
{ fallback: Common.Components.ErrorFallback },
35-
Suspense.with({ fallback: <CircularProgress /> }, ({ app, resource }) => {
37+
Suspense.with({ fallback: <CircularProgress /> }, ({ app, resource, hideCreatedAt, hideUpdatedAt }) => {
3638
const navigate = useNavigate();
3739
const backendAdminClient = Common.Hooks.BackendAdminAPI.useBackendAdminClient();
3840
const listQuery = Common.Hooks.BackendAdminAPI.useListQuery<ListRowType>(backendAdminClient, app, resource);
@@ -53,8 +55,8 @@ const InnerAdminList: React.FC<AdminListProps> = ErrorBoundary.with(
5355
<TableRow>
5456
<TableCell sx={{ width: "25%" }}>ID</TableCell>
5557
<TableCell sx={{ width: "40%" }}>이름</TableCell>
56-
<TableCell sx={{ width: "17.5%" }}>생성 시간</TableCell>
57-
<TableCell sx={{ width: "17.5%" }}>수정 시간</TableCell>
58+
{hideCreatedAt === true && <TableCell sx={{ width: "17.5%" }}>생성 시간</TableCell>}
59+
{hideUpdatedAt === true && <TableCell sx={{ width: "17.5%" }}>수정 시간</TableCell>}
5860
</TableRow>
5961
</TableHead>
6062
<TableBody>
@@ -66,8 +68,8 @@ const InnerAdminList: React.FC<AdminListProps> = ErrorBoundary.with(
6668
<TableCell>
6769
<Link to={`/${app}/${resource}/${item.id}`}>{item.str_repr}</Link>
6870
</TableCell>
69-
<TableCell>{new Date(item.created_at).toLocaleString()}</TableCell>
70-
<TableCell>{new Date(item.updated_at).toLocaleString()}</TableCell>
71+
{hideCreatedAt === true && <TableCell>{new Date(item.created_at).toLocaleString()}</TableCell>}
72+
{hideUpdatedAt === true && <TableCell>{new Date(item.updated_at).toLocaleString()}</TableCell>}
7173
</TableRow>
7274
))}
7375
</TableBody>

apps/pyconkr-admin/src/components/pages/account/sign_in.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,16 @@ import { useNavigate } from "react-router-dom";
66

77
import { addErrorSnackbar, addSnackbar } from "../../../utils/snackbar";
88

9+
type PageStateType = {
10+
userJustSignedIn: boolean;
11+
};
12+
913
export const SignInPage: React.FC = () => {
1014
const navigate = useNavigate();
1115
const formRef = React.useRef<HTMLFormElement>(null);
16+
const [pageState, setPageState] = React.useState<PageStateType>({ userJustSignedIn: false });
17+
const setUserJustSignedIn = () => setPageState((ps) => ({ ...ps, userJustSignedIn: true }));
18+
1219
const backendAdminAPIClient = Common.Hooks.BackendAdminAPI.useBackendAdminClient();
1320
const signInMutation = Common.Hooks.BackendAdminAPI.useSignInMutation(backendAdminAPIClient);
1421

@@ -22,6 +29,7 @@ export const SignInPage: React.FC = () => {
2229
}>({ form: formRef.current });
2330
signInMutation.mutate(formData, {
2431
onSuccess: (data) => {
32+
setUserJustSignedIn();
2533
addSnackbar(`안녕하세요, ${data.username}님!`, "success");
2634
navigate("/");
2735
},
@@ -31,13 +39,15 @@ export const SignInPage: React.FC = () => {
3139

3240
React.useEffect(() => {
3341
(async () => {
42+
if (pageState.userJustSignedIn) return;
43+
3444
const userInfo = await Common.BackendAdminAPIs.me(backendAdminAPIClient)();
3545
if (userInfo) {
3646
addSnackbar(`이미 ${userInfo.username}님으로 로그인되어 있습니다!`, "success");
3747
navigate("/");
3848
}
3949
})();
40-
}, [backendAdminAPIClient, navigate]);
50+
}, [backendAdminAPIClient, navigate, pageState.userJustSignedIn]);
4151

4252
return (
4353
<Stack sx={{ width: "100%", height: "100%", flexGrow: 1 }}>
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import * as Common from "@frontend/common";
2+
import { KeyOff } from "@mui/icons-material";
3+
import {
4+
Button,
5+
ButtonProps,
6+
CircularProgress,
7+
Dialog,
8+
DialogActions,
9+
DialogContent,
10+
DialogContentText,
11+
DialogTitle,
12+
} from "@mui/material";
13+
import { ErrorBoundary, Suspense } from "@suspensive/react";
14+
import * as React from "react";
15+
import { useParams } from "react-router-dom";
16+
17+
import { addErrorSnackbar, addSnackbar } from "../../../utils/snackbar";
18+
import { AdminEditor } from "../../layouts/admin_editor";
19+
20+
type PageStateType = {
21+
isDialogOpen: boolean;
22+
};
23+
24+
export const AdminUserExtEditor: React.FC = ErrorBoundary.with(
25+
{ fallback: Common.Components.ErrorFallback },
26+
Suspense.with({ fallback: <CircularProgress /> }, () => {
27+
const { id } = useParams<{ id?: string }>();
28+
const [pageState, setPageState] = React.useState<PageStateType>({ isDialogOpen: false });
29+
const openDialog = () => setPageState((ps) => ({ ...ps, isDialogOpen: true }));
30+
const closeDialog = () => setPageState((ps) => ({ ...ps, isDialogOpen: false }));
31+
32+
const backendAdminClient = Common.Hooks.BackendAdminAPI.useBackendAdminClient();
33+
const useResetPasswordMutation = Common.Hooks.BackendAdminAPI.useResetUserPasswordMutation(
34+
backendAdminClient,
35+
id || ""
36+
);
37+
38+
const resetUserPassword = () => {
39+
closeDialog();
40+
if (id) {
41+
useResetPasswordMutation.mutate(undefined, {
42+
onSuccess: () => addSnackbar("비밀번호가 초기화되었습니다.", "success"),
43+
onError: addErrorSnackbar,
44+
});
45+
}
46+
};
47+
48+
const resetUserPasswordButton: ButtonProps = {
49+
variant: "outlined",
50+
color: "error",
51+
size: "small",
52+
startIcon: <KeyOff />,
53+
children: "비밀번호 초기화",
54+
onClick: () => id && openDialog(),
55+
};
56+
57+
return (
58+
<>
59+
<Dialog open={pageState.isDialogOpen}>
60+
<DialogTitle>비밀번호 초기화</DialogTitle>
61+
<DialogContent>
62+
<DialogContentText>정말 이 사용자의 비밀번호를 초기화하시겠습니까?</DialogContentText>
63+
</DialogContent>
64+
<DialogActions>
65+
<Button color="error" onClick={closeDialog} autoFocus>
66+
취소
67+
</Button>
68+
<Button onClick={resetUserPassword}>초기화</Button>
69+
</DialogActions>
70+
</Dialog>
71+
<AdminEditor app="user" resource="userext" id={id} extraActions={[resetUserPasswordButton]} />
72+
</>
73+
);
74+
})
75+
);

apps/pyconkr-admin/src/routes.tsx

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { AccountCircle, AccountTree, Article, FilePresent } from "@mui/icons-material";
1+
import { AccountCircle, AccountTree, Article, FilePresent, ManageAccounts } from "@mui/icons-material";
22

33
import { AdminEditorCreateRoutePage, AdminEditorModifyRoutePage } from "./components/layouts/admin_editor";
44
import { AdminList } from "./components/layouts/admin_list";
@@ -8,6 +8,7 @@ import { AccountManagementPage } from "./components/pages/account/manage";
88
import { SignInPage } from "./components/pages/account/sign_in";
99
import { PublicFileUploadPage } from "./components/pages/file/upload";
1010
import { AdminCMSPageEditor } from "./components/pages/page/editor";
11+
import { AdminUserExtEditor } from "./components/pages/user/editor";
1112

1213
export const RouteDefinitions: RouteDef[] = [
1314
{
@@ -44,9 +45,22 @@ export const RouteDefinitions: RouteDef[] = [
4445
app: "file",
4546
resource: "publicfile",
4647
},
48+
{
49+
type: "separator",
50+
key: "user-separator",
51+
title: "사용자",
52+
},
4753
{
4854
type: "routeDefinition",
4955
key: "user-userext",
56+
icon: ManageAccounts,
57+
title: "사용자 관리",
58+
app: "user",
59+
resource: "userext",
60+
},
61+
{
62+
type: "routeDefinition",
63+
key: "user-account",
5064
icon: AccountCircle,
5165
title: "로그인 / 로그아웃",
5266
app: "user",
@@ -78,6 +92,8 @@ export const RegisteredRoutes = {
7892
"/cms/page/:id": <AdminCMSPageEditor />,
7993
"/file/publicfile/create": <PublicFileUploadPage />,
8094
"/file/publicfile/:id": <AdminEditorModifyRoutePage app="file" resource="publicfile" notModifiable notDeletable />,
95+
"/user/userext": <AdminList app="user" resource="userext" hideCreatedAt hideUpdatedAt />,
96+
"/user/userext/:id": <AdminUserExtEditor />,
8197
"/account": <AccountRedirectPage />,
8298
"/account/sign-in": <SignInPage />,
8399
"/account/manage": <AccountManagementPage />,

0 commit comments

Comments
 (0)