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/polices/policy-editor.tsx | 262 +++++++++++++++++++++++++++++++++++
 1 file changed, 262 insertions(+)
 create mode 100644 components/polices/policy-editor.tsx

(limited to 'components/polices/policy-editor.tsx')

diff --git a/components/polices/policy-editor.tsx b/components/polices/policy-editor.tsx
new file mode 100644
index 00000000..d58831e0
--- /dev/null
+++ b/components/polices/policy-editor.tsx
@@ -0,0 +1,262 @@
+'use client'
+
+import { useState, useEffect } from 'react'
+import { Button } from '@/components/ui/button'
+import { Input } from '@/components/ui/input'
+import { Label } from '@/components/ui/label'
+import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
+import { Alert, AlertDescription } from '@/components/ui/alert'
+import { Separator } from '@/components/ui/separator'
+import { Save, Eye, X, Info, AlertTriangle } from 'lucide-react'
+import TiptapEditor from '../qna/tiptap-editor'
+
+interface PolicyEditorProps {
+  policyType: string
+  currentPolicy?: any
+  onSave: (policyType: string, version: string, content: string) => void
+  onCancel: () => void
+  onPreview: (policyType: string, content: string, version: string) => void
+  isLoading?: boolean
+}
+
+export function PolicyEditor({ 
+  policyType, 
+  currentPolicy, 
+  onSave, 
+  onCancel, 
+  onPreview,
+  isLoading = false 
+}: PolicyEditorProps) {
+  const [version, setVersion] = useState('')
+  const [content, setContent] = useState('')
+  const [validationErrors, setValidationErrors] = useState<string[]>([])
+
+  console.log(content)
+
+  const policyLabels = {
+    privacy_policy: '개인정보 처리방침',
+    terms_of_service: '이용약관'
+  }
+
+  // 현재 정책 기반으로 다음 버전 생성
+  useEffect(() => {
+    if (currentPolicy) {
+      const currentVersion = currentPolicy.version
+      const versionParts = currentVersion.split('.')
+      const majorVersion = parseInt(versionParts[0]) || 1
+      const minorVersion = parseInt(versionParts[1]) || 0
+      
+      // 마이너 버전 업
+      const nextVersion = `${majorVersion}.${minorVersion + 1}`
+      setVersion(nextVersion)
+      setContent(currentPolicy.content || '')
+    } else {
+      setVersion('1.0')
+      setContent(getDefaultPolicyContent(policyType))
+    }
+  }, [currentPolicy, policyType])
+
+  const getDefaultPolicyContent = (type: string) => {
+    if (type === 'privacy_policy') {
+      return `<h1>개인정보 처리방침</h1>
+
+<h2>제1조 (목적)</h2>
+<p>본 개인정보 처리방침은 eVCP(이하 "회사")가 개인정보 보호법 등 관련 법령에 따라 정보주체의 개인정보를 보호하고 이와 관련된 고충을 신속하고 원활하게 처리할 수 있도록 하기 위하여 다음과 같은 처리방침을 수립·공개합니다.</p>
+
+<h2>제2조 (개인정보의 수집 및 이용목적)</h2>
+<p>회사는 다음의 목적을 위하여 개인정보를 처리합니다:</p>
+<ul>
+  <li>회원 가입 및 관리</li>
+  <li>서비스 제공 및 계약 이행</li>
+  <li>고객 상담 및 불만 처리</li>
+</ul>
+
+<h2>제3조 (개인정보의 수집항목)</h2>
+<p><strong>필수항목:</strong></p>
+<ul>
+  <li>이메일 주소</li>
+  <li>전화번호</li>
+  <li>회사명</li>
+</ul>
+
+<h2>제4조 (개인정보의 보유 및 이용기간)</h2>
+<p>회사는 법령에 따른 개인정보 보유·이용기간 또는 정보주체로부터 개인정보를 수집 시에 동의받은 개인정보 보유·이용기간 내에서 개인정보를 처리·보유합니다.</p>
+
+<h2>제5조 (정보주체의 권리)</h2>
+<p>정보주체는 회사에 대해 언제든지 다음 각 호의 개인정보 보호 관련 권리를 행사할 수 있습니다:</p>
+<ul>
+  <li>개인정보 처리현황 통지요구</li>
+  <li>개인정보 열람요구</li>
+  <li>개인정보 정정·삭제요구</li>
+  <li>개인정보 처리정지요구</li>
+</ul>`
+    } else {
+      return `<h1>이용약관</h1>
+
+<h2>제1조 (목적)</h2>
+<p>본 약관은 eVCP(이하 "회사")가 제공하는 서비스의 이용조건 및 절차, 회사와 회원 간의 권리, 의무 및 책임사항을 규정함을 목적으로 합니다.</p>
+
+<h2>제2조 (정의)</h2>
+<ul>
+  <li><strong>"서비스"</strong>란 회사가 제공하는 모든 서비스를 의미합니다.</li>
+  <li><strong>"회원"</strong>이란 본 약관에 동의하고 회사와 서비스 이용계약을 체결한 자를 의미합니다.</li>
+  <li><strong>"업체"</strong>란 회사의 파트너로 등록된 법인 또는 개인사업자를 의미합니다.</li>
+</ul>
+
+<h2>제3조 (약관의 효력 및 변경)</h2>
+<p>본 약관은 서비스를 이용하고자 하는 모든 회원에 대하여 그 효력을 발생합니다.</p>
+
+<h2>제4조 (회원가입)</h2>
+<p>회원가입은 신청자가 본 약관의 내용에 대하여 동의를 한 다음 회원가입신청을 하고 회사가 이러한 신청에 대하여 승낙함으로써 체결됩니다.</p>
+
+<h2>제5조 (서비스의 제공)</h2>
+<p>회사는 회원에게 다음과 같은 서비스를 제공합니다:</p>
+<ul>
+  <li>업체 등록 및 관리 서비스</li>
+  <li>문서 관리 서비스</li>
+  <li>견적 제출 서비스</li>
+</ul>`
+    }
+  }
+
+  const validateForm = () => {
+    const errors: string[] = []
+
+    if (!version.trim()) {
+      errors.push('버전을 입력해주세요.')
+    } else if (!/^\d+\.\d+$/.test(version.trim())) {
+      errors.push('버전은 "1.0" 형식으로 입력해주세요.')
+    }
+
+    if (!content.trim()) {
+      errors.push('정책 내용을 입력해주세요.')
+    } else if (content.trim().length < 100) {
+      errors.push('정책 내용이 너무 짧습니다. (최소 100자)')
+    }
+
+    // 버전 중복 체크 (현재 정책이 있는 경우)
+    if (currentPolicy && version === currentPolicy.version) {
+      errors.push('이미 존재하는 버전입니다. 다른 버전을 입력해주세요.')
+    }
+
+    setValidationErrors(errors)
+    return errors.length === 0
+  }
+
+  const handleSave = () => {
+    if (validateForm()) {
+      onSave(policyType, version.trim(), content)
+    }
+  }
+
+  const handlePreview = () => {
+    if (validateForm()) {
+      onPreview(policyType, content, version.trim())
+    }
+  }
+
+  return (
+    <Card>
+      <CardHeader>
+        <CardTitle>
+          {currentPolicy ? '정책 편집' : '새 정책 생성'} - {policyLabels[policyType]}
+        </CardTitle>
+        <CardDescription>
+          {currentPolicy 
+            ? `현재 버전 v${currentPolicy.version}을 기반으로 새 버전을 생성합니다.`
+            : `${policyLabels[policyType]}의 첫 번째 버전을 생성합니다.`
+          }
+        </CardDescription>
+      </CardHeader>
+      <CardContent className="space-y-6">
+        {/* 경고 메시지 */}
+        <Alert>
+          <Info className="h-4 w-4" />
+          <AlertDescription>
+            새 버전을 저장하면 즉시 활성화되어 모든 사용자에게 적용됩니다. 
+            저장하기 전에 미리보기로 내용을 확인해주세요.
+          </AlertDescription>
+        </Alert>
+
+        {/* 유효성 검사 오류 */}
+        {validationErrors.length > 0 && (
+          <Alert variant="destructive">
+            <AlertTriangle className="h-4 w-4" />
+            <AlertDescription>
+              <ul className="list-disc list-inside space-y-1">
+                {validationErrors.map((error, index) => (
+                  <li key={index}>{error}</li>
+                ))}
+              </ul>
+            </AlertDescription>
+          </Alert>
+        )}
+
+        {/* 버전 입력 */}
+        <div className="space-y-2">
+          <Label htmlFor="version">버전</Label>
+          <Input
+            id="version"
+            placeholder="예: 1.1"
+            value={version}
+            onChange={(e) => setVersion(e.target.value)}
+            disabled={isLoading}
+            className="w-32"
+          />
+          <p className="text-xs text-muted-foreground">
+            형식: 주.부 (예: 1.0, 1.1, 2.0)
+          </p>
+        </div>
+
+        <Separator />
+
+        {/* 정책 내용 편집기 */}
+        <div className="space-y-2">
+          <Label>정책 내용</Label>
+          <div className="border rounded-md">
+            <TiptapEditor
+              content={content}
+              setContent={setContent}
+              disabled={isLoading}
+              height="500px"
+            />
+          </div>
+          <p className="text-xs text-muted-foreground">
+            리치 텍스트 편집기를 사용하여 정책 내용을 작성하세요. 
+            이미지, 표, 목록 등을 추가할 수 있습니다.
+          </p>
+        </div>
+
+        {/* 액션 버튼들 */}
+        <div className="flex justify-between pt-4">
+          <Button
+            variant="outline"
+            onClick={onCancel}
+            disabled={isLoading}
+          >
+            <X className="h-4 w-4 mr-2" />
+            취소
+          </Button>
+
+          <div className="flex gap-2">
+            <Button
+              variant="outline"
+              onClick={handlePreview}
+              disabled={isLoading || !content.trim() || !version.trim()}
+            >
+              <Eye className="h-4 w-4 mr-2" />
+              미리보기
+            </Button>
+            <Button
+              onClick={handleSave}
+              disabled={isLoading || !content.trim() || !version.trim()}
+            >
+              <Save className="h-4 w-4 mr-2" />
+              {isLoading ? '저장 중...' : '저장'}
+            </Button>
+          </div>
+        </div>
+      </CardContent>
+    </Card>
+  )
+}
\ No newline at end of file
-- 
cgit v1.2.3

