From de2ac5a2860bc25180971e7a11f852d9d44675b7 Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
Date: Wed, 6 Aug 2025 04:23:40 +0000
Subject: (대표님) 정기평가, 법적검토, 정책, 가입관련 처리 및 관련 컴포넌트
 추가, 메뉴 변경
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 components/qna/tiptap-editor.tsx | 98 ++++++++++++++++++++++++++++------------
 1 file changed, 69 insertions(+), 29 deletions(-)

(limited to 'components/qna/tiptap-editor.tsx')

diff --git a/components/qna/tiptap-editor.tsx b/components/qna/tiptap-editor.tsx
index 5d0a84e9..b1cebf5a 100644
--- a/components/qna/tiptap-editor.tsx
+++ b/components/qna/tiptap-editor.tsx
@@ -1,4 +1,5 @@
 import { useEditor, EditorContent } from '@tiptap/react'
+import { useEffect } from 'react' // useEffect 추가
 import StarterKit from '@tiptap/starter-kit'
 import Underline from '@tiptap/extension-underline'
 import { Image as TiptapImage } from '@tiptap/extension-image'
@@ -26,6 +27,18 @@ interface TiptapEditorProps {
   height?: string; // 높이 prop 추가
 }
 
+// 이미지 크기 가져오기 헬퍼 함수
+function getImageDimensions(url: string): Promise<{ width: number; height: number }> {
+  return new Promise((resolve, reject) => {
+    const img = new Image()
+    img.onload = () => {
+      resolve({ width: img.width, height: img.height })
+    }
+    img.onerror = reject
+    img.src = url
+  })
+}
+
 export default function TiptapEditor({ content, setContent, disabled, height = "300px" }: TiptapEditorProps) {
   const editor = useEditor({
     extensions: [
@@ -135,6 +148,21 @@ export default function TiptapEditor({ content, setContent, disabled, height = "
     },
   })
 
+  // ✅ 핵심 추가: content prop이 변경될 때 에디터 내용 동기화
+  useEffect(() => {
+    if (editor && content !== editor.getHTML()) {
+      console.log('Updating editor content:', content) // 디버깅용
+      editor.commands.setContent(content, false) // false: focus 유지하지 않음
+    }
+  }, [content, editor])
+
+  // ✅ editable 상태 변경 처리
+  useEffect(() => {
+    if (editor) {
+      editor.setEditable(!disabled)
+    }
+  }, [disabled, editor])
+
   async function uploadImageToServer(file: File): Promise<string> {
     const formData = new FormData();
     formData.append('file', file);
@@ -153,39 +181,51 @@ export default function TiptapEditor({ content, setContent, disabled, height = "
     return url;
   }
 
-// Base64 → 서버 업로드 방식으로 교체
-const handleImageUpload = async (file: File) => {
-  try {
-    if (file.size > 3 * 1024 * 1024) {
-      alert('이미지 크기는 3 MB 이하만 지원됩니다.');
-      return;
-    }
-    if (!file.type.startsWith('image/')) {
-      alert('이미지 파일만 업로드 가능합니다.');
-      return;
-    }
+  // Base64 → 서버 업로드 방식으로 교체
+  const handleImageUpload = async (file: File) => {
+    try {
+      if (file.size > 3 * 1024 * 1024) {
+        alert('이미지 크기는 3 MB 이하만 지원됩니다.');
+        return;
+      }
+      if (!file.type.startsWith('image/')) {
+        alert('이미지 파일만 업로드 가능합니다.');
+        return;
+      }
 
-    const url = await uploadImageToServer(file);   // ← 업로드 & URL 획득
+      const url = await uploadImageToServer(file);   // ← 업로드 & URL 획득
 
-    // 이미지 크기(너비)에 따라 style 조정
-    const { width, height } = await getImageDimensions(url);
-    const maxWidth = 600;
-    const newW = width > maxWidth ? maxWidth : width;
-    const newH = width > maxWidth ? (height * maxWidth) / width : height;
+      // 이미지 크기(너비)에 따라 style 조정
+      const { width, height } = await getImageDimensions(url);
+      const maxWidth = 600;
+      const newW = width > maxWidth ? maxWidth : width;
+      const newH = width > maxWidth ? (height * maxWidth) / width : height;
+
+      editor
+        ?.chain()
+        .focus()
+        .setImage({
+          src: url,
+          style: `width:${newW}px;height:${newH}px;max-width:100%;`,
+        })
+        .run();
+    } catch (e) {
+      console.error(e);
+      alert('이미지 업로드에 실패했습니다.');
+    }
+  };
 
-    editor
-      ?.chain()
-      .focus()
-      .setImage({
-        src: url,
-        style: `width:${newW}px;height:${newH}px;max-width:100%;`,
-      })
-      .run();
-  } catch (e) {
-    console.error(e);
-    alert('이미지 업로드에 실패했습니다.');
+  // ✅ 에디터가 준비되지 않았을 때 로딩 표시
+  if (!editor) {
+    return (
+      <div 
+        className="border rounded-md bg-background flex items-center justify-center"
+        style={{ height }}
+      >
+        <div className="text-muted-foreground text-sm">에디터를 로딩 중...</div>
+      </div>
+    )
   }
-};
 
   // 높이 계산 (100%인 경우 flex 사용, 아니면 구체적 높이)
   const containerStyle = height === "100%" 
-- 
cgit v1.2.3

