diff --git a/apps/cs/src/pages/code/ui/lwpocode-dialog.tsx b/apps/cs/src/pages/code/ui/lwpocode-dialog.tsx index 1eb9562ec..d21f5b60a 100644 --- a/apps/cs/src/pages/code/ui/lwpocode-dialog.tsx +++ b/apps/cs/src/pages/code/ui/lwpocode-dialog.tsx @@ -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="정렬순서를 입력해주세요" /> diff --git a/apps/cs/src/pages/code/ui/lwpocode-section.tsx b/apps/cs/src/pages/code/ui/lwpocode-section.tsx index 3e6aaf1ca..9692c842d 100644 --- a/apps/cs/src/pages/code/ui/lwpocode-section.tsx +++ b/apps/cs/src/pages/code/ui/lwpocode-section.tsx @@ -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) { 코드갱신 diff --git a/apps/cs/src/pages/groups/model/groups-table-columns.tsx b/apps/cs/src/pages/groups/model/groups-table-columns.tsx index 864bfafd2..18ad4e78a 100644 --- a/apps/cs/src/pages/groups/model/groups-table-columns.tsx +++ b/apps/cs/src/pages/groups/model/groups-table-columns.tsx @@ -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 { - onDelete?: (groupId: string , row?: TData) => void; - } -} - -export const columns: ColumnDef[] = [ +export const createColumns = ({ + onDelete, +}: { + onDelete: (groupId: string) => void; +}): ColumnDef[] => [ { accessorKey: "groupId", header: "그룹코드", @@ -28,12 +24,10 @@ export const columns: ColumnDef[] = [ { 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 ( diff --git a/apps/cs/src/pages/groups/ui/groups-section.tsx b/apps/cs/src/pages/groups/ui/groups-section.tsx index c316283b7..9c7f5b6ca 100644 --- a/apps/cs/src/pages/groups/ui/groups-section.tsx +++ b/apps/cs/src/pages/groups/ui/groups-section.tsx @@ -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, diff --git a/apps/cs/src/pages/menu/lib/utils.ts b/apps/cs/src/pages/menu/lib/utils.ts index 0e219047d..a5cb921a6 100644 --- a/apps/cs/src/pages/menu/lib/utils.ts +++ b/apps/cs/src/pages/menu/lib/utils.ts @@ -153,6 +153,7 @@ export const filterUserOrganizationTreeDataByKeyword = ( ): NodeModel[] => { 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); diff --git a/apps/cs/src/pages/menu/ui/organization-search-dialog.tsx b/apps/cs/src/pages/menu/ui/organization-search-dialog.tsx index 19e3fcf87..eb942fe11 100644 --- a/apps/cs/src/pages/menu/ui/organization-search-dialog.tsx +++ b/apps/cs/src/pages/menu/ui/organization-search-dialog.tsx @@ -12,7 +12,9 @@ import { import { Button, Dialog, + DialogClose, DialogContent, + DialogFooter, DialogHeader, DialogTitle, DialogTrigger, @@ -52,10 +54,22 @@ function OrganizationSearchDialog({ }); const handleSelectNode = (node: NodeModel) => { + if (node.data && "ognzSn" in node.data) return; setSelectedNode(node); handleUserSelect(node.data as TreeUser); }; + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + e.stopPropagation(); + setTree(filterUserOrganizationTreeDataByKeyword(treeData ?? [], keyword)); + }; + + const handleReset = () => { + setKeyword(""); + setTree(treeData ?? []); + }; + useEffect(() => { setTree(treeData ?? []); }, [treeData]); @@ -73,21 +87,25 @@ function OrganizationSearchDialog({ 담당자 조회
-
- setKeyword(e.target.value)} - /> - +
+
+ setKeyword(e.target.value)} + /> + + +
@@ -116,6 +134,16 @@ function OrganizationSearchDialog({
+ + + + + + + + ); diff --git a/apps/cs/src/pages/users/ui/user-detail.tsx b/apps/cs/src/pages/users/ui/user-detail.tsx index 60c1f34b8..fbfa016c2 100644 --- a/apps/cs/src/pages/users/ui/user-detail.tsx +++ b/apps/cs/src/pages/users/ui/user-detail.tsx @@ -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 (
@@ -164,7 +176,7 @@ function UserDetail({ userUnqId }: { userUnqId: string }) { -