Merge branch 'main' of https://www.onasys.co.kr:3000/ONAANDALL/frontend into iipbs_cs
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { memo } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||
import {
|
||||
Button,
|
||||
@@ -37,7 +37,7 @@ type ManagementLwpoCodeDialogProps = {
|
||||
upCd?: string;
|
||||
children?: React.ReactNode;
|
||||
open?: boolean;
|
||||
onOpenChange?: (open: boolean) => void;
|
||||
onOpenChange?: (open: boolean) => void;
|
||||
onAfterSave?: () => void; // 콜백 추가
|
||||
};
|
||||
|
||||
@@ -47,21 +47,20 @@ const LwpoCodeManagementDialog = memo(
|
||||
upCd,
|
||||
children,
|
||||
open,
|
||||
onOpenChange,
|
||||
onOpenChange,
|
||||
onAfterSave, // 콜백 사용
|
||||
...props
|
||||
}: ManagementLwpoCodeDialogProps) => {
|
||||
const isRegistration = !lwpoCd;
|
||||
|
||||
const { confirm } = useConfirm();
|
||||
const alert = useAlertStore((state) => state.setMessage);
|
||||
// 상세 데이터
|
||||
const queryClient = useQueryClient();
|
||||
const alert = useAlertStore((state) => state.setMessage);
|
||||
|
||||
const { data: detailData } = useQuery({
|
||||
queryKey: [ENDPOINT.CMS_SERVICE.LWPO_CODE, upCd, lwpoCd],
|
||||
queryFn: () => LwpoCodeApi.lwpoCodeDetail(upCd!, lwpoCd!),
|
||||
enabled: !!upCd && !isRegistration && open,
|
||||
});
|
||||
|
||||
|
||||
const { data: upCodeData } = useQuery({
|
||||
queryKey: [ENDPOINT.CMS_SERVICE.UP_CODE, upCd],
|
||||
@@ -71,22 +70,25 @@ const LwpoCodeManagementDialog = memo(
|
||||
|
||||
const { mutateAsync: createLwpoCode } = useMutationWrapper({
|
||||
mutationFn: (data: LwpoCodeFormData) => LwpoCodeApi.createLwpoCode(data),
|
||||
onSuccess: async () => {
|
||||
onSuccess: () => {
|
||||
alert("등록되었습니다.", () => {
|
||||
onOpenChange?.(false);
|
||||
if (onAfterSave) onAfterSave();
|
||||
});
|
||||
onOpenChange?.(false);
|
||||
onAfterSave?.();
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: [ENDPOINT.CMS_SERVICE.LWPO_CODE, upCd],
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const { mutateAsync: updateLwpoCode } = useMutationWrapper({
|
||||
mutationFn: (data: LwpoCodeFormData) =>
|
||||
LwpoCodeApi.updateLwpoCode(upCd!, lwpoCd!, data),
|
||||
onSuccess: async () => {
|
||||
onSuccess: () => {
|
||||
alert("수정되었습니다.", () => {
|
||||
onOpenChange?.(false);
|
||||
if (onAfterSave) onAfterSave();
|
||||
});
|
||||
onOpenChange?.(false);
|
||||
onAfterSave?.();
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -104,7 +106,6 @@ const LwpoCodeManagementDialog = memo(
|
||||
delYn: "N",
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
const handleRegister = async () => {
|
||||
if (!upCd) {
|
||||
@@ -119,7 +120,7 @@ const LwpoCodeManagementDialog = memo(
|
||||
upCd: upCd,
|
||||
sortSeq: Number(rawValues.sortSeq) || 0,
|
||||
};
|
||||
await createLwpoCode(values);
|
||||
await createLwpoCode(values);
|
||||
}
|
||||
};
|
||||
const handleSave = async () => {
|
||||
@@ -135,7 +136,7 @@ const LwpoCodeManagementDialog = memo(
|
||||
upCd: upCd,
|
||||
sortSeq: Number(rawValues.sortSeq) || 0,
|
||||
};
|
||||
await updateLwpoCode(values);
|
||||
await updateLwpoCode(values);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -289,6 +290,9 @@ const LwpoCodeManagementDialog = memo(
|
||||
{...field}
|
||||
type="number"
|
||||
value={field.value ?? 0}
|
||||
onChange={(e) => {
|
||||
field.onChange(parseInt(e.target.value));
|
||||
}}
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="정렬순서를 입력해주세요"
|
||||
/>
|
||||
|
||||
@@ -24,7 +24,7 @@ function LwpoCodeSection({ upCd }: LwpoCodeSectionProps) {
|
||||
pageIndex: 0,
|
||||
pageSize: 10,
|
||||
});
|
||||
|
||||
|
||||
const query = useQuery({
|
||||
queryKey: [ENDPOINT.CMS_SERVICE.LWPO_CODE, upCd, searchParams, pagination],
|
||||
queryFn: () =>
|
||||
@@ -34,17 +34,16 @@ function LwpoCodeSection({ upCd }: LwpoCodeSectionProps) {
|
||||
page: pagination.pageIndex,
|
||||
size: pagination.pageSize,
|
||||
}),
|
||||
enabled: !!upCd ,
|
||||
enabled: !!upCd,
|
||||
placeholderData: keepPreviousData,
|
||||
});
|
||||
});
|
||||
|
||||
// 등록/수정 후 목록 재조회 콜백
|
||||
const handleAfterSave = () => {
|
||||
const handleAfterSave = () => {
|
||||
query.refetch();
|
||||
};
|
||||
const columns = getColumns(handleAfterSave);
|
||||
|
||||
|
||||
|
||||
const { mutateAsync: codeRefreshAll } = useMutation({
|
||||
mutationFn: LwpoCodeApi.codeRefreshAll,
|
||||
onSuccess: () => {
|
||||
@@ -123,9 +122,9 @@ function LwpoCodeSection({ upCd }: LwpoCodeSectionProps) {
|
||||
코드갱신
|
||||
</Button>
|
||||
<LwpoCodeManagementDialog
|
||||
open={dialogOpen}
|
||||
upCd={upCd}
|
||||
onOpenChange={setDialogOpen}
|
||||
open={dialogOpen}
|
||||
onOpenChange={setDialogOpen}
|
||||
onAfterSave={handleAfterSave}
|
||||
>
|
||||
<Button>등록</Button>
|
||||
|
||||
@@ -4,15 +4,11 @@ import { type GroupListResponseDto } from "@/entities/group";
|
||||
import { MenuAuthorityDialog } from "../ui/menu-authority-dialog";
|
||||
import { GroupsDialog } from "../ui/groups-dialog";
|
||||
|
||||
|
||||
declare module "@tanstack/react-table" {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
interface TableMeta<TData> {
|
||||
onDelete?: (groupId: string , row?: TData) => void;
|
||||
}
|
||||
}
|
||||
|
||||
export const columns: ColumnDef<GroupListResponseDto>[] = [
|
||||
export const createColumns = ({
|
||||
onDelete,
|
||||
}: {
|
||||
onDelete: (groupId: string) => void;
|
||||
}): ColumnDef<GroupListResponseDto>[] => [
|
||||
{
|
||||
accessorKey: "groupId",
|
||||
header: "그룹코드",
|
||||
@@ -28,12 +24,10 @@ export const columns: ColumnDef<GroupListResponseDto>[] = [
|
||||
{
|
||||
id: "actions",
|
||||
header: "관리",
|
||||
cell: ({ row, table }) => {
|
||||
const onDelete = table.options.meta?.onDelete as (groupId: string) => void;
|
||||
|
||||
cell: ({ row }) => {
|
||||
const handleDelete = (e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
if (onDelete) onDelete(row.original.groupId);
|
||||
onDelete(row.original.groupId);
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { keepPreviousData, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import {
|
||||
keepPreviousData,
|
||||
useQuery,
|
||||
useQueryClient,
|
||||
} from "@tanstack/react-query";
|
||||
import { getCoreRowModel, type PaginationState } from "@tanstack/react-table";
|
||||
import { Button, Input, Label } from "@common/components";
|
||||
import { GroupApi , type GroupSearchParams} from "@/entities/group";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
import { useDataTable } from "@/shared/lib";
|
||||
import { columns } from "../model/groups-table-columns";
|
||||
import { createColumns } from "../model/groups-table-columns";
|
||||
import { GroupsDialog } from "./groups-dialog";
|
||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||
import { useAlertStore, useMutationWrapper } from "@/shared/lib";
|
||||
@@ -40,8 +44,8 @@ function GroupsSection({ handleSelectedGroup }: GroupsSectionProps) {
|
||||
size: pagination.pageSize,
|
||||
}),
|
||||
placeholderData: keepPreviousData,
|
||||
});
|
||||
const { confirm } = useConfirm();
|
||||
});
|
||||
const { confirm } = useConfirm();
|
||||
const alert = useAlertStore((state) => state.setMessage);
|
||||
const queryClient = useQueryClient();
|
||||
const { mutateAsync: deleteGroup } = useMutationWrapper({
|
||||
@@ -82,22 +86,19 @@ function GroupsSection({ handleSelectedGroup }: GroupsSectionProps) {
|
||||
};
|
||||
const handleRowClick = (row: { groupId: string }) => {
|
||||
table.setRowSelection({ [row.groupId]: true });
|
||||
handleSelectedGroup(row.groupId); // 1. 리스트에서 선택된 groupId 저장
|
||||
handleSelectedGroup(row.groupId); // 1. 리스트에서 선택된 groupId 저장
|
||||
};
|
||||
|
||||
const { tableComponent, tableInstance: table } = useDataTable({
|
||||
query,
|
||||
tableOptions: {
|
||||
columns,
|
||||
columns: createColumns({ onDelete: handleDelete }),
|
||||
state: { pagination },
|
||||
manualPagination: true,
|
||||
enableMultiRowSelection: false,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
onPaginationChange: setPagination,
|
||||
getRowId: (row) => row.groupId,
|
||||
meta: {
|
||||
onDelete: handleDelete,
|
||||
},
|
||||
},
|
||||
dataTableOptions: {
|
||||
onRowClick: handleRowClick,
|
||||
|
||||
@@ -153,6 +153,7 @@ export const filterUserOrganizationTreeDataByKeyword = (
|
||||
): NodeModel<TreeUserOrganization | TreeUser>[] => {
|
||||
return Array.from(
|
||||
treeData.reduce((matchedNodes, node) => {
|
||||
if (node.data && "ognzSn" in node.data) return matchedNodes; // 조직 노드는 필터링 제외
|
||||
if (!node.text.includes(keyword)) return matchedNodes;
|
||||
|
||||
matchedNodes.add(node);
|
||||
|
||||
@@ -12,7 +12,9 @@ import {
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
@@ -52,10 +54,22 @@ function OrganizationSearchDialog({
|
||||
});
|
||||
|
||||
const handleSelectNode = (node: NodeModel<TreeModel>) => {
|
||||
if (node.data && "ognzSn" in node.data) return;
|
||||
setSelectedNode(node);
|
||||
handleUserSelect(node.data as TreeUser);
|
||||
};
|
||||
|
||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setTree(filterUserOrganizationTreeDataByKeyword(treeData ?? [], keyword));
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
setKeyword("");
|
||||
setTree(treeData ?? []);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setTree(treeData ?? []);
|
||||
}, [treeData]);
|
||||
@@ -73,21 +87,25 @@ function OrganizationSearchDialog({
|
||||
<DialogTitle>담당자 조회</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="card card-border !m-0 flex w-full items-center gap-2">
|
||||
<Input
|
||||
className="h-[2.5rem] !text-[1.3rem]"
|
||||
value={keyword}
|
||||
onChange={(e) => setKeyword(e.target.value)}
|
||||
/>
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={() =>
|
||||
setTree(filterUserOrganizationTreeDataByKeyword(tree, keyword))
|
||||
}
|
||||
>
|
||||
<i className="diveicon di-search text-base" />
|
||||
조회
|
||||
</Button>
|
||||
<div className="card card-border !m-0 w-full">
|
||||
<form onSubmit={handleSubmit} className="flex items-center gap-2">
|
||||
<Input
|
||||
className="h-[2.5rem] !text-[1.3rem]"
|
||||
value={keyword}
|
||||
onChange={(e) => setKeyword(e.target.value)}
|
||||
/>
|
||||
<Button type="submit" size="sm">
|
||||
조회
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
color="white"
|
||||
onClick={handleReset}
|
||||
>
|
||||
초기화
|
||||
</Button>
|
||||
</form>
|
||||
</div>
|
||||
<div className="h-[36rem] overflow-auto">
|
||||
<DndProvider backend={MultiBackend} options={getBackendOptions()}>
|
||||
@@ -116,6 +134,16 @@ function OrganizationSearchDialog({
|
||||
</DndProvider>
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<DialogClose asChild>
|
||||
<Button color="white" onClick={() => setSelectedNode(null)}>
|
||||
취소
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<DialogClose asChild>
|
||||
<Button disabled={!selectedNode}>확인</Button>
|
||||
</DialogClose>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import dayjs from "dayjs";
|
||||
import { usePathname, useRouter } from "next/navigation";
|
||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||
import {
|
||||
Button,
|
||||
Table,
|
||||
@@ -18,10 +19,11 @@ import { useAlertStore, useMutationWrapper } from "@/shared/lib";
|
||||
function UserDetail({ userUnqId }: { userUnqId: string }) {
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const { confirm } = useConfirm();
|
||||
const queryClient = useQueryClient();
|
||||
const alert = useAlertStore((state) => state.setMessage);
|
||||
|
||||
const { data } = useQuery({
|
||||
const { data, refetch } = useQuery({
|
||||
queryKey: [ENDPOINT.USER_SERVICE.USERS, userUnqId],
|
||||
queryFn: () => UserApi.findByUserUnqId(userUnqId),
|
||||
enabled: !!userUnqId,
|
||||
@@ -31,9 +33,7 @@ function UserDetail({ userUnqId }: { userUnqId: string }) {
|
||||
mutationFn: () => UserApi.lockUser(userUnqId),
|
||||
onSuccess: () => {
|
||||
alert("계정 잠금이 활성화 되었습니다.");
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: [ENDPOINT.USER_SERVICE.USERS, userUnqId],
|
||||
});
|
||||
refetch();
|
||||
},
|
||||
});
|
||||
|
||||
@@ -41,9 +41,7 @@ function UserDetail({ userUnqId }: { userUnqId: string }) {
|
||||
mutationFn: () => UserApi.unlockUser(userUnqId),
|
||||
onSuccess: () => {
|
||||
alert("계정 잠금이 해제되었습니다.");
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: [ENDPOINT.USER_SERVICE.USERS, userUnqId],
|
||||
});
|
||||
refetch();
|
||||
},
|
||||
});
|
||||
|
||||
@@ -51,12 +49,26 @@ function UserDetail({ userUnqId }: { userUnqId: string }) {
|
||||
mutationFn: () => UserApi.applyUser(userUnqId),
|
||||
onSuccess: () => {
|
||||
alert("사용자 승인이 완료되었습니다.");
|
||||
refetch();
|
||||
},
|
||||
});
|
||||
|
||||
const { mutateAsync: deleteUser } = useMutationWrapper({
|
||||
mutationFn: () => UserApi.deleteUser(userUnqId),
|
||||
onSuccess: () => {
|
||||
alert("회원이 삭제되었습니다.", router.back);
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: [ENDPOINT.USER_SERVICE.USERS, userUnqId],
|
||||
queryKey: [ENDPOINT.USER_SERVICE.USERS],
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const handleDelete = async () => {
|
||||
if (await confirm("삭제하시겠습니까?")) {
|
||||
await deleteUser();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="card card-border !mt-6">
|
||||
<div className="card-header">
|
||||
@@ -164,7 +176,7 @@ function UserDetail({ userUnqId }: { userUnqId: string }) {
|
||||
<Button size="lg" onClick={() => router.push(`${pathname}/modify`)}>
|
||||
수정
|
||||
</Button>
|
||||
<Button size="lg" color="red">
|
||||
<Button size="lg" color="red" onClick={handleDelete}>
|
||||
삭제
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user