summaryrefslogtreecommitdiff
path: root/components/approval/ApprovalPreviewDialog.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'components/approval/ApprovalPreviewDialog.tsx')
-rw-r--r--components/approval/ApprovalPreviewDialog.tsx213
1 files changed, 0 insertions, 213 deletions
diff --git a/components/approval/ApprovalPreviewDialog.tsx b/components/approval/ApprovalPreviewDialog.tsx
deleted file mode 100644
index 7b5ff615..00000000
--- a/components/approval/ApprovalPreviewDialog.tsx
+++ /dev/null
@@ -1,213 +0,0 @@
-"use client";
-
-import * as React from "react";
-import { Button } from "@/components/ui/button";
-import {
- Dialog,
- DialogContent,
- DialogDescription,
- DialogFooter,
- DialogHeader,
- DialogTitle,
-} from "@/components/ui/dialog";
-import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
-import { Loader2, FileText, AlertCircle } from "lucide-react";
-import { toast } from "sonner";
-import { Separator } from "@/components/ui/separator";
-
-import ApprovalLineSelector, {
- type ApprovalLineItem,
-} from "@/components/knox/approval/ApprovalLineSelector";
-import { getApprovalTemplateByName, replaceTemplateVariables } from "@/lib/approval/template-utils";
-import { debugLog, debugError, debugSuccess } from "@/lib/debug-utils";
-
-interface ApprovalPreviewDialogProps {
- open: boolean;
- onOpenChange: (open: boolean) => void;
- templateName: string;
- variables: Record<string, string>;
- title: string;
- description?: string;
- currentUser: { id: number; epId: string | null; name?: string | null; email?: string };
- onSubmit: (approvers: ApprovalLineItem[]) => Promise<void>;
-}
-
-export function ApprovalPreviewDialog({
- open,
- onOpenChange,
- templateName,
- variables,
- title,
- description,
- currentUser,
- onSubmit,
-}: ApprovalPreviewDialogProps) {
- const [approvalLines, setApprovalLines] = React.useState<ApprovalLineItem[]>([]);
- const [isSubmitting, setIsSubmitting] = React.useState(false);
- const [templateContent, setTemplateContent] = React.useState<string>("");
- const [isLoadingTemplate, setIsLoadingTemplate] = React.useState(false);
- const [templateError, setTemplateError] = React.useState<string | null>(null);
-
- // 상신자 초기화
- React.useEffect(() => {
- if (open && currentUser.epId) {
- const drafterLine: ApprovalLineItem = {
- id: `drafter-${Date.now()}`,
- epId: currentUser.epId,
- userId: currentUser.id.toString(),
- emailAddress: currentUser.email,
- name: currentUser.name || undefined,
- role: "0", // 기안
- seq: "0",
- opinion: "",
- };
- setApprovalLines([drafterLine]);
- }
- }, [open, currentUser]);
-
- // 템플릿 로드 및 변수 치환
- React.useEffect(() => {
- if (!open) return;
-
- const loadTemplate = async () => {
- setIsLoadingTemplate(true);
- setTemplateError(null);
-
- try {
- const template = await getApprovalTemplateByName(templateName);
-
- if (!template) {
- setTemplateError(`템플릿 "${templateName}"을 찾을 수 없습니다.`);
- setTemplateContent(`<p class="text-gray-500">${description || "결재 요청"}</p>`);
- } else {
- // 변수 치환
- const replaced = await replaceTemplateVariables(template.content, variables);
- setTemplateContent(replaced);
- }
- } catch (error) {
- console.error("Template load error:", error);
- setTemplateError("템플릿을 불러오는 중 오류가 발생했습니다.");
- setTemplateContent(`<p class="text-gray-500">${description || "결재 요청"}</p>`);
- } finally {
- setIsLoadingTemplate(false);
- }
- };
-
- loadTemplate();
- }, [open, templateName, variables, description]);
-
- const handleSubmit = async () => {
- debugLog('[ApprovalPreviewDialog] 결재 제출 시작', {
- templateName,
- approvalLineCount: approvalLines.length,
- });
-
- // 결재자가 있는지 확인 (상신자 제외)
- const approvers = approvalLines.filter((line) => line.seq !== "0");
- if (approvers.length === 0) {
- debugError('[ApprovalPreviewDialog] 결재자가 없음');
- toast.error("결재자를 최소 1명 이상 추가해주세요.");
- return;
- }
-
- setIsSubmitting(true);
- try {
- debugLog('[ApprovalPreviewDialog] onSubmit 호출', {
- approversCount: approvers.length,
- });
-
- await onSubmit(approvalLines);
-
- debugSuccess('[ApprovalPreviewDialog] 결재 요청 성공');
- toast.success("결재가 성공적으로 요청되었습니다.");
- onOpenChange(false);
- } catch (error) {
- debugError('[ApprovalPreviewDialog] 결재 요청 실패', error);
- const errorMessage = error instanceof Error ? error.message : "결재 요청에 실패했습니다.";
- toast.error(errorMessage);
- // 에러 발생 시 dialog를 닫지 않음
- } finally {
- setIsSubmitting(false);
- }
- };
-
- return (
- <Dialog open={open} onOpenChange={onOpenChange}>
- <DialogContent className="max-w-5xl max-h-[90vh] overflow-y-auto">
- <DialogHeader>
- <DialogTitle className="flex items-center gap-2">
- <FileText className="w-5 h-5" />
- {title}
- </DialogTitle>
- {description && <DialogDescription>{description}</DialogDescription>}
- </DialogHeader>
-
- <div className="space-y-6">
-
- {/* 결재선 선택 */}
- <div>
- <ApprovalLineSelector
- value={approvalLines}
- onChange={setApprovalLines}
- placeholder="결재자를 검색하세요..."
- maxSelections={10}
- />
- </div>
-
- <Separator />
-
- {/* 템플릿 미리보기 */}
- <Card>
- <CardHeader>
- <CardTitle>결재 내용 미리보기</CardTitle>
- <CardDescription>
- 템플릿: <span className="font-mono text-sm">{templateName}</span>
- </CardDescription>
- </CardHeader>
- <CardContent>
- {isLoadingTemplate ? (
- <div className="flex items-center justify-center py-8">
- <Loader2 className="w-6 h-6 animate-spin text-gray-400" />
- <span className="ml-2 text-gray-500">템플릿을 불러오는 중...</span>
- </div>
- ) : templateError ? (
- <div className="p-4 bg-yellow-50 border border-yellow-200 rounded-lg">
- <div className="flex items-center gap-2 text-yellow-700">
- <AlertCircle className="w-4 h-4" />
- <span className="font-medium">경고</span>
- </div>
- <p className="text-sm text-yellow-600 mt-1">{templateError}</p>
- <p className="text-xs text-yellow-500 mt-2">
- 기본 내용으로 대체되었습니다. 결재는 정상적으로 진행됩니다.
- </p>
- </div>
- ) : null}
-
- <div
- className="border rounded-lg p-4 min-h-[200px] [&_table]:w-full [&_table]:border-collapse [&_table]:border [&_table]:border-border [&_th]:border [&_th]:border-border [&_th]:bg-muted/50 [&_th]:px-3 [&_th]:py-2 [&_th]:text-left [&_th]:font-semibold [&_td]:border [&_td]:border-border [&_td]:px-3 [&_td]:py-2 [&_tr:hover]:bg-muted/30"
- dangerouslySetInnerHTML={{ __html: templateContent }}
- />
- </CardContent>
- </Card>
-
- </div>
-
- <DialogFooter className="gap-2">
- <Button
- type="button"
- variant="outline"
- onClick={() => onOpenChange(false)}
- disabled={isSubmitting}
- >
- 취소
- </Button>
- <Button type="button" onClick={handleSubmit} disabled={isSubmitting || isLoadingTemplate}>
- {isSubmitting && <Loader2 className="mr-2 w-4 h-4 animate-spin" />}
- 결재 요청
- </Button>
- </DialogFooter>
- </DialogContent>
- </Dialog>
- );
-}
-