From 225ebc0983a7d5e1612f989b007a1847a897220d Mon Sep 17 00:00:00 2001 From: bicochan Date: Thu, 10 Jul 2025 14:39:24 +0900 Subject: [PATCH 1/5] =?UTF-8?q?[apps/cs]=20fix:=20=EB=B9=8C=EB=93=9C=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../groups/model/groups-table-columns.tsx | 12 +++++++----- .../cs/src/pages/groups/ui/groups-section.tsx | 19 ++++++++++--------- 2 files changed, 17 insertions(+), 14 deletions(-) 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 0f417a304..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,7 +4,11 @@ import { type GroupListResponseDto } from "@/entities/group"; import { MenuAuthorityDialog } from "../ui/menu-authority-dialog"; import { GroupsDialog } from "../ui/groups-dialog"; -export const columns: ColumnDef[] = [ +export const createColumns = ({ + onDelete, +}: { + onDelete: (groupId: string) => void; +}): ColumnDef[] => [ { accessorKey: "groupId", header: "그룹코드", @@ -20,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 2130a94c0..8acc7f019 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 } from "@common/components"; import { GroupApi } 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"; @@ -30,8 +34,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({ @@ -51,22 +55,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, From 29bc717b2caec3a80b7ccf64b62d41e385477322 Mon Sep 17 00:00:00 2001 From: bicochan Date: Thu, 10 Jul 2025 16:50:19 +0900 Subject: [PATCH 2/5] =?UTF-8?q?[apps/cs]=20feat:=20=ED=9A=8C=EC=9B=90=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?(CS=5FUT05010109)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/cs/src/pages/users/ui/user-detail.tsx | 30 +++++++++++++++------- 1 file changed, 21 insertions(+), 9 deletions(-) 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 }) { -
From e5b8bf2685056ee8ac01650890a495fe5411db71 Mon Sep 17 00:00:00 2001 From: bicochan Date: Thu, 10 Jul 2025 17:08:19 +0900 Subject: [PATCH 3/5] =?UTF-8?q?[apps/cs]=20fix:=20=ED=95=98=EC=9C=84?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EB=93=B1=EB=A1=9D=20=ED=8F=BC=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=20=ED=95=B4=EA=B2=B0=20(CS=5FUT08010104)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/cs/src/pages/code/ui/lwpocode-dialog.tsx | 10 ++++++++-- apps/cs/src/pages/code/ui/lwpocode-section.tsx | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/cs/src/pages/code/ui/lwpocode-dialog.tsx b/apps/cs/src/pages/code/ui/lwpocode-dialog.tsx index c11c57332..d6c6bb685 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, @@ -50,8 +50,8 @@ const LwpoCodeManagementDialog = memo( ...props }: ManagementLwpoCodeDialogProps) => { const isRegistration = !lwpoCd; - const { confirm } = useConfirm(); + const queryClient = useQueryClient(); const alert = useAlertStore((state) => state.setMessage); const { data: detailData } = useQuery({ @@ -70,6 +70,9 @@ const LwpoCodeManagementDialog = memo( mutationFn: (data: LwpoCodeFormData) => LwpoCodeApi.createLwpoCode(data), onSuccess: () => { alert("등록되었습니다.", () => onOpenChange?.(false)); + queryClient.invalidateQueries({ + queryKey: [ENDPOINT.CMS_SERVICE.LWPO_CODE, upCd], + }); }, }); @@ -251,6 +254,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 c6025b338..15773c5f4 100644 --- a/apps/cs/src/pages/code/ui/lwpocode-section.tsx +++ b/apps/cs/src/pages/code/ui/lwpocode-section.tsx @@ -116,6 +116,7 @@ function LwpoCodeSection({ upCd }: LwpoCodeSectionProps) { 코드갱신 From e74d554992dd00c9af0292b2b55fc7f5c812fca5 Mon Sep 17 00:00:00 2001 From: bicochan Date: Fri, 11 Jul 2025 11:49:48 +0900 Subject: [PATCH 4/5] =?UTF-8?q?fix:=20eslint=20=EC=97=90=EB=9F=AC=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/cs/src/pages/code/ui/lwpocode-section.tsx | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/apps/cs/src/pages/code/ui/lwpocode-section.tsx b/apps/cs/src/pages/code/ui/lwpocode-section.tsx index ac3d8218c..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: () => { @@ -125,8 +124,7 @@ function LwpoCodeSection({ upCd }: LwpoCodeSectionProps) { From ab606ad65d266dfe2cc89645d4de82991e9fe8c7 Mon Sep 17 00:00:00 2001 From: bicochan Date: Fri, 11 Jul 2025 17:39:17 +0900 Subject: [PATCH 5/5] =?UTF-8?q?[apps/cs]=20fix:=20=EB=8B=B4=EB=8B=B9?= =?UTF-8?q?=EC=9E=90=20=EC=A1=B0=ED=9A=8C=20=EB=8B=A4=EC=9D=B4=EC=96=BC?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=20=EA=B8=B0=EB=8A=A5=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?(CS=5FUT01020108)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/cs/src/pages/menu/lib/utils.ts | 1 + .../menu/ui/organization-search-dialog.tsx | 58 ++++++++++++++----- 2 files changed, 44 insertions(+), 15 deletions(-) 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({
+ + + + + + + + );