From eb1ed7f7e807a4a550285064e96169621e011a42 Mon Sep 17 00:00:00 2001 From: joonhoekim <26rote@gmail.com> Date: Thu, 6 Nov 2025 18:09:26 +0900 Subject: (김준회) 결재 preview dialog 공통컴포넌트 UI 수정, 렌더링 사이클 오류 수정(useEffect 의존성변수에 의한 무한로딩) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/approval/approval-preview-dialog.tsx | 205 +++++++++++----------------- lib/vendors/table/approve-vendor-dialog.tsx | 4 +- 2 files changed, 83 insertions(+), 126 deletions(-) diff --git a/lib/approval/approval-preview-dialog.tsx b/lib/approval/approval-preview-dialog.tsx index bc5a4f65..a91e146c 100644 --- a/lib/approval/approval-preview-dialog.tsx +++ b/lib/approval/approval-preview-dialog.tsx @@ -1,7 +1,7 @@ "use client"; import * as React from "react"; -import { Loader2, Eye, Send, X } from "lucide-react"; +import { Loader2, Send, X } from "lucide-react"; import { toast } from "sonner"; import { Button } from "@/components/ui/button"; @@ -23,19 +23,18 @@ import { } from "@/components/ui/drawer"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; -import { Textarea } from "@/components/ui/textarea"; import { ScrollArea } from "@/components/ui/scroll-area"; -import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { useMediaQuery } from "@/hooks/use-media-query"; -import { ApprovalLineSelector } from "@/components/knox/approval/ApprovalLineSelector"; +import { + ApprovalLineSelector, + type ApprovalLineItem +} from "@/components/knox/approval/ApprovalLineSelector"; import { getApprovalTemplateByName, replaceTemplateVariables } from "./template-utils"; -import type { ApprovalLine } from "@/components/knox/approval/types"; - /** * 결재 미리보기 다이얼로그 Props */ @@ -50,8 +49,6 @@ export interface ApprovalPreviewDialogProps { variables: Record; /** 결재 제목 */ title: string; - /** 결재 설명 (선택사항) */ - description?: string; /** 현재 사용자 정보 */ currentUser: { id: number; @@ -66,12 +63,9 @@ export interface ApprovalPreviewDialogProps { onConfirm: (data: { approvers: string[]; title: string; - description?: string; }) => Promise; /** 제목 수정 가능 여부 (기본: true) */ allowTitleEdit?: boolean; - /** 설명 수정 가능 여부 (기본: true) */ - allowDescriptionEdit?: boolean; } /** @@ -104,12 +98,10 @@ export function ApprovalPreviewDialog({ templateName, variables, title: initialTitle, - description: initialDescription, currentUser, defaultApprovers = [], onConfirm, allowTitleEdit = true, - allowDescriptionEdit = true, }: ApprovalPreviewDialogProps) { const isDesktop = useMediaQuery("(min-width: 768px)"); @@ -119,8 +111,7 @@ export function ApprovalPreviewDialog({ // 폼 상태 const [title, setTitle] = React.useState(initialTitle); - const [description, setDescription] = React.useState(initialDescription || ""); - const [approvalLines, setApprovalLines] = React.useState([]); + const [approvalLines, setApprovalLines] = React.useState([]); const [previewHtml, setPreviewHtml] = React.useState(""); // 템플릿 로딩 및 미리보기 생성 @@ -154,14 +145,24 @@ export function ApprovalPreviewDialog({ } loadTemplatePreview(); - }, [open, templateName, variables]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [open, templateName]); // variables 제거 - 다이얼로그가 열릴 때만 로드 - // 초기 결재선 설정 + // 다이얼로그 상태 초기화/리셋 React.useEffect(() => { - if (!open) return; + if (!open) { + // 다이얼로그가 닫힐 때 상태 초기화 + setTitle(initialTitle); + setApprovalLines([]); + setPreviewHtml(""); + return; + } + + // 다이얼로그가 열릴 때 초기화 + setTitle(initialTitle); // 상신자 추가 - const submitter: ApprovalLine = { + const submitter: ApprovalLineItem = { id: `submitter-${currentUser.id}`, epId: currentUser.epId, userId: currentUser.id.toString(), @@ -174,7 +175,7 @@ export function ApprovalPreviewDialog({ }; // 기본 결재자들 추가 (있는 경우) - const defaultLines: ApprovalLine[] = defaultApprovers.map((epId, index) => ({ + const defaultLines: ApprovalLineItem[] = defaultApprovers.map((epId, index) => ({ id: `approver-${index}`, epId: epId, userId: "", // EP ID로만 식별 @@ -186,10 +187,11 @@ export function ApprovalPreviewDialog({ })); setApprovalLines([submitter, ...defaultLines]); - }, [open, currentUser, defaultApprovers]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [open]); // open 상태만 감지 - 다이얼로그 열림/닫힘 시에만 초기화 // 결재선 변경 핸들러 - const handleApprovalLinesChange = (lines: ApprovalLine[]) => { + const handleApprovalLinesChange = (lines: ApprovalLineItem[]) => { setApprovalLines(lines); }; @@ -223,7 +225,6 @@ export function ApprovalPreviewDialog({ await onConfirm({ approvers: approverEpIds, title: title.trim(), - description: description.trim() || undefined, }); // 성공 시 다이얼로그 닫기 @@ -244,99 +245,55 @@ export function ApprovalPreviewDialog({ // 폼 내용 const FormContent = () => (
- {/* 탭: 미리보기 / 결재선 설정 */} - - - - - 미리보기 - - - - 결재선 설정 - - - - {/* 미리보기 탭 */} - - {/* 제목 입력 */} -
- - setTitle(e.target.value)} - placeholder="결재 제목을 입력하세요" - disabled={!allowTitleEdit || isSubmitting} - /> -
+ {/* 결재선 설정 */} +
+
+ +

+ 결재자를 검색하여 추가하고, 결재 순서를 설정하세요. +

+
- {/* 설명 입력 */} -
- -