diff options
| author | joonhoekim <26rote@gmail.com> | 2025-12-01 19:52:06 +0900 |
|---|---|---|
| committer | joonhoekim <26rote@gmail.com> | 2025-12-01 19:52:06 +0900 |
| commit | 44b74ff4170090673b6eeacd8c528e0abf47b7aa (patch) | |
| tree | 3f3824b4e2cb24536c1677188b4cae5b8909d3da /lib/legal-review/status/request-review-dialog.tsx | |
| parent | 4953e770929b82ef77da074f77071ebd0f428529 (diff) | |
(김준회) deprecated code 정리
Diffstat (limited to 'lib/legal-review/status/request-review-dialog.tsx')
| -rw-r--r-- | lib/legal-review/status/request-review-dialog.tsx | 983 |
1 files changed, 0 insertions, 983 deletions
diff --git a/lib/legal-review/status/request-review-dialog.tsx b/lib/legal-review/status/request-review-dialog.tsx deleted file mode 100644 index d99fc0e3..00000000 --- a/lib/legal-review/status/request-review-dialog.tsx +++ /dev/null @@ -1,983 +0,0 @@ -"use client" - -import * as React from "react" -import { useForm } from "react-hook-form" -import { zodResolver } from "@hookform/resolvers/zod" -import * as z from "zod" -import { Loader2, Send, FileText, Clock, Upload, X, Building, User, Calendar } from "lucide-react" -import { toast } from "sonner" - -import { Button } from "@/components/ui/button" -import { - Dialog, - DialogContent, - DialogDescription, - DialogHeader, - DialogTitle, -} from "@/components/ui/dialog" -import { - Form, - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage, -} from "@/components/ui/form" -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select" -import { Input } from "@/components/ui/input" -import { Textarea } from "@/components/ui/textarea" -import { Badge } from "@/components/ui/badge" -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" -import { Switch } from "@/components/ui/switch" -import TiptapEditor from "@/components/qna/tiptap-editor" -import { canRequestReview, requestReview } from "../service" -import { LegalWorksDetailView } from "@/db/schema" - -type LegalWorkData = LegalWorksDetailView - -interface RequestReviewDialogProps { - open: boolean - onOpenChange: (open: boolean) => void - work: LegalWorkData | null - onSuccess?: () => void -} - -// 검토요청 폼 스키마 -const requestReviewSchema = z.object({ - // 기본 검토 설정 - dueDate: z.string().min(1, "검토 완료 희망일을 선택해주세요"), - assignee: z.string().optional(), - notificationMethod: z.enum(["email", "internal", "both"]).default("both"), - - // 법무업무 상세 정보 - reviewDepartment: z.enum(["준법문의", "법무검토"]), - inquiryType: z.enum(["국내계약", "국내자문", "해외계약", "해외자문"]).optional(), - - // 공통 필드 - title: z.string().min(1, "제목을 선택해주세요"), - requestContent: z.string().min(1, "요청내용을 입력해주세요"), - - // 준법문의 전용 필드 - isPublic: z.boolean().default(false), - - // 법무검토 전용 필드들 - contractProjectName: z.string().optional(), - contractType: z.string().optional(), - contractCounterparty: z.string().optional(), - counterpartyType: z.enum(["법인", "개인"]).optional(), - contractPeriod: z.string().optional(), - contractAmount: z.string().optional(), - factualRelation: z.string().optional(), - projectNumber: z.string().optional(), - shipownerOrderer: z.string().optional(), - projectType: z.string().optional(), - governingLaw: z.string().optional(), -}).refine((data) => { - // 법무검토 선택시 문의종류 필수 - if (data.reviewDepartment === "법무검토" && !data.inquiryType) { - return false; - } - return true; -}, { - message: "법무검토 선택시 문의종류를 선택해주세요", - path: ["inquiryType"] -}); - -type RequestReviewFormValues = z.infer<typeof requestReviewSchema> - -export function RequestReviewDialog({ - open, - onOpenChange, - work, - onSuccess -}: RequestReviewDialogProps) { - const [isSubmitting, setIsSubmitting] = React.useState(false) - const [attachments, setAttachments] = React.useState<File[]>([]) - const [editorContent, setEditorContent] = React.useState("") - const [canRequest, setCanRequest] = React.useState(true) - const [requestCheckMessage, setRequestCheckMessage] = React.useState("") - const [isCustomTitle, setIsCustomTitle] = React.useState(false) - - // work의 category에 따라 기본 reviewDepartment 결정 - const getDefaultReviewDepartment = () => { - return work?.category === "CP" ? "준법문의" : "법무검토" - } - - const form = useForm<RequestReviewFormValues>({ - resolver: zodResolver(requestReviewSchema), - defaultValues: { - dueDate: "", - assignee: "", - notificationMethod: "both", - reviewDepartment: getDefaultReviewDepartment(), - title: getDefaultReviewDepartment() === "준법문의" ? "CP검토" : "GTC검토", - requestContent: "", - isPublic: false, - }, - }) - - // work 변경시 검토요청 가능 여부 확인 - React.useEffect(() => { - if (work && open) { - canRequestReview(work.id).then((result) => { - setCanRequest(result.canRequest) - setRequestCheckMessage(result.reason || "") - }) - - const defaultDepartment = work.category === "CP" ? "준법문의" : "법무검토" - form.setValue("reviewDepartment", defaultDepartment) - } - }, [work, open, form]) - - // 검토부문 감시 - const reviewDepartment = form.watch("reviewDepartment") - const inquiryType = form.watch("inquiryType") - const titleValue = form.watch("title") - - // 조건부 필드 활성화 로직 - const isContractTypeActive = inquiryType && ["국내계약", "해외계약", "해외자문"].includes(inquiryType) - const isDomesticContractFieldsActive = inquiryType === "국내계약" - const isFactualRelationActive = inquiryType && ["국내자문", "해외자문"].includes(inquiryType) - const isOverseasFieldsActive = inquiryType && ["해외계약", "해외자문"].includes(inquiryType) - - // 제목 "기타" 선택 여부 확인 - // const isTitleOther = titleValue === "기타" - - // 검토부문 변경시 관련 필드 초기화 - React.useEffect(() => { - if (reviewDepartment === "준법문의") { - setIsCustomTitle(false) - form.setValue("inquiryType", undefined) - // 제목 초기화 (기타 상태였거나 값이 없으면 기본값으로) - const currentTitle = form.getValues("title") - if (!currentTitle || currentTitle === "GTC검토") { - form.setValue("title", "CP검토") - } - // 법무검토 전용 필드들 초기화 - form.setValue("contractProjectName", "") - form.setValue("contractType", "") - form.setValue("contractCounterparty", "") - form.setValue("counterpartyType", undefined) - form.setValue("contractPeriod", "") - form.setValue("contractAmount", "") - form.setValue("factualRelation", "") - form.setValue("projectNumber", "") - form.setValue("shipownerOrderer", "") - form.setValue("projectType", "") - form.setValue("governingLaw", "") - } else { - setIsCustomTitle(false) - // 제목 초기화 (기타 상태였거나 값이 없으면 기본값으로) - const currentTitle = form.getValues("title") - if (!currentTitle || currentTitle === "CP검토") { - form.setValue("title", "GTC검토") - } - form.setValue("isPublic", false) - } - }, [reviewDepartment, form]) - - // 문의종류 변경시 관련 필드 초기화 - React.useEffect(() => { - if (inquiryType) { - // 계약서 종류 초기화 (옵션이 달라지므로) - form.setValue("contractType", "") - - // 조건에 맞지 않는 필드들 초기화 - if (!isDomesticContractFieldsActive) { - form.setValue("contractCounterparty", "") - form.setValue("counterpartyType", undefined) - form.setValue("contractPeriod", "") - form.setValue("contractAmount", "") - } - - if (!isFactualRelationActive) { - form.setValue("factualRelation", "") - } - - if (!isOverseasFieldsActive) { - form.setValue("projectNumber", "") - form.setValue("shipownerOrderer", "") - form.setValue("projectType", "") - form.setValue("governingLaw", "") - } - } - }, [inquiryType, isDomesticContractFieldsActive, isFactualRelationActive, isOverseasFieldsActive, form]) - - // 에디터 내용이 변경될 때 폼에 반영 - React.useEffect(() => { - form.setValue("requestContent", editorContent) - }, [editorContent, form]) - - // 첨부파일 처리 - const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => { - const files = Array.from(event.target.files || []) - setAttachments(prev => [...prev, ...files]) - } - - const removeAttachment = (index: number) => { - setAttachments(prev => prev.filter((_, i) => i !== index)) - } - - // 폼 제출 - async function onSubmit(data: RequestReviewFormValues) { - if (!work) return - - console.log("Request review data:", data) - console.log("Work to review:", work) - console.log("Attachments:", attachments) - setIsSubmitting(true) - - try { - const result = await requestReview(work.id, data, attachments) - - if (result.success) { - toast.success(result.data?.message || `법무업무 #${work.id}에 대한 검토요청이 완료되었습니다.`) - onOpenChange(false) - handleReset() - onSuccess?.() - } else { - toast.error(result.error || "검토요청 중 오류가 발생했습니다.") - } - } catch (error) { - console.error("Error requesting review:", error) - toast.error("검토요청 중 오류가 발생했습니다.") - } finally { - setIsSubmitting(false) - } - } - - // 폼 리셋 함수 - const handleReset = () => { - const defaultDepartment = getDefaultReviewDepartment() - setIsCustomTitle(false) // 추가 - - form.reset({ - dueDate: "", - assignee: "", - notificationMethod: "both", - reviewDepartment: defaultDepartment, - title: defaultDepartment === "준법문의" ? "CP검토" : "GTC검토", - requestContent: "", - isPublic: false, - }) - setAttachments([]) - setEditorContent("") - } - - // 다이얼로그 닫기 핸들러 - const handleOpenChange = (open: boolean) => { - onOpenChange(open) - if (!open) { - handleReset() - } - } - - // 제목 옵션 (검토부문에 따라 다름) - const getTitleOptions = () => { - if (reviewDepartment === "준법문의") { - return [ - { value: "CP검토", label: "CP검토" }, - { value: "기타", label: "기타 (직접입력)" } - ] - } else { - return [ - { value: "GTC검토", label: "GTC검토" }, - { value: "기타", label: "기타 (직접입력)" } - ] - } - } - - // 계약서 종류 옵션 (문의종류에 따라 다름) - const getContractTypeOptions = () => { - if (inquiryType === "국내계약") { - return [ - { value: "공사도급계약", label: "공사도급계약" }, - { value: "제작납품계약", label: "제작납품계약" }, - { value: "자재매매계약", label: "자재매매계약" }, - { value: "용역위탁계약", label: "용역위탁계약" }, - { value: "기술사용 및 개발계약", label: "기술사용 및 개발계약" }, - { value: "운송 및 자재관리 계약", label: "운송 및 자재관리 계약" }, - { value: "자문 등 위임계약", label: "자문 등 위임계약" }, - { value: "양해각서", label: "양해각서" }, - { value: "양수도 계약", label: "양수도 계약" }, - { value: "합의서", label: "합의서" }, - { value: "공동도급(운영)협약서", label: "공동도급(운영)협약서" }, - { value: "협정서", label: "협정서" }, - { value: "약정서", label: "약정서" }, - { value: "협의서", label: "협의서" }, - { value: "기타", label: "기타" }, - { value: "비밀유지계약서", label: "비밀유지계약서" }, - { value: "분양계약서", label: "분양계약서" }, - ] - } else { - // 해외계약/해외자문 - return [ - { value: "Shipbuilding Contract", label: "Shipbuilding Contract" }, - { value: "Offshore Contract (EPCI, FEED)", label: "Offshore Contract (EPCI, FEED)" }, - { value: "Supplementary / Addendum", label: "Supplementary / Addendum" }, - { value: "Subcontract / GTC / PTC / PO", label: "Subcontract / GTC / PTC / PO" }, - { value: "Novation / Assignment", label: "Novation / Assignment" }, - { value: "NDA (Confidential, Secrecy)", label: "NDA (Confidential, Secrecy)" }, - { value: "Warranty", label: "Warranty" }, - { value: "Waiver and Release", label: "Waiver and Release" }, - { value: "Bond (PG, RG, Advanced Payment)", label: "Bond (PG, RG, Advanced Payment)" }, - { value: "MOU / LOI / LOA", label: "MOU / LOI / LOA" }, - { value: "Power of Attorney (POA)", label: "Power of Attorney (POA)" }, - { value: "Commission Agreement", label: "Commission Agreement" }, - { value: "Consortium Agreement", label: "Consortium Agreement" }, - { value: "JV / JDP Agreement", label: "JV / JDP Agreement" }, - { value: "Engineering Service Contract", label: "Engineering Service Contract" }, - { value: "Consultancy Service Agreement", label: "Consultancy Service Agreement" }, - { value: "Purchase / Lease Agreement", label: "Purchase / Lease Agreement" }, - { value: "Financial / Loan / Covenant", label: "Financial / Loan / Covenant" }, - { value: "Other Contract / Agreement", label: "Other Contract / Agreement" }, - ] - } - } - - // 프로젝트 종류 옵션 - const getProjectTypeOptions = () => { - return [ - { value: "BARGE VESSEL", label: "BARGE VESSEL" }, - { value: "BULK CARRIER", label: "BULK CARRIER" }, - { value: "CHEMICAL CARRIER", label: "CHEMICAL CARRIER" }, - { value: "FULL CONTAINER", label: "FULL CONTAINER" }, - { value: "CRUDE OIL TANKER", label: "CRUDE OIL TANKER" }, - { value: "CRUISE SHIP", label: "CRUISE SHIP" }, - { value: "DRILL SHIP", label: "DRILL SHIP" }, - { value: "FIELD DEVELOPMENT SHIP", label: "FIELD DEVELOPMENT SHIP" }, - { value: "FLOATING PRODUCTION STORAGE OFFLOADING", label: "FLOATING PRODUCTION STORAGE OFFLOADING" }, - { value: "CAR-FERRY & PASSENGER VESSEL", label: "CAR-FERRY & PASSENGER VESSEL" }, - { value: "FLOATING STORAGE OFFLOADING", label: "FLOATING STORAGE OFFLOADING" }, - { value: "HEAVY DECK CARGO", label: "HEAVY DECK CARGO" }, - { value: "PRODUCT OIL TANKER", label: "PRODUCT OIL TANKER" }, - { value: "HIGH SPEED LINER", label: "HIGH SPEED LINER" }, - { value: "JACK-UP", label: "JACK-UP" }, - { value: "LIQUEFIED NATURAL GAS CARRIER", label: "LIQUEFIED NATURAL GAS CARRIER" }, - { value: "LIQUEFIED PETROLEUM GAS CARRIER", label: "LIQUEFIED PETROLEUM GAS CARRIER" }, - { value: "MULTIPURPOSE CARGO CARRIER", label: "MULTIPURPOSE CARGO CARRIER" }, - { value: "ORE-BULK-OIL CARRIER", label: "ORE-BULK-OIL CARRIER" }, - { value: "OIL TANKER", label: "OIL TANKER" }, - { value: "OTHER VESSEL", label: "OTHER VESSEL" }, - { value: "PURE CAR CARRIER", label: "PURE CAR CARRIER" }, - { value: "PRODUCT CARRIER", label: "PRODUCT CARRIER" }, - { value: "PLATFORM", label: "PLATFORM" }, - { value: "PUSHER", label: "PUSHER" }, - { value: "REEFER TRANSPORT VESSEL", label: "REEFER TRANSPORT VESSEL" }, - { value: "ROLL-ON ROLL-OFF VESSEL", label: "ROLL-ON ROLL-OFF VESSEL" }, - { value: "SEMI RIG", label: "SEMI RIG" }, - { value: "SUPPLY ANCHOR HANDLING VESSEL", label: "SUPPLY ANCHOR HANDLING VESSEL" }, - { value: "SHUTTLE TANKER", label: "SHUTTLE TANKER" }, - { value: "SUPPLY VESSEL", label: "SUPPLY VESSEL" }, - { value: "TOPSIDE", label: "TOPSIDE" }, - { value: "TUG SUPPLY VESSEL", label: "TUG SUPPLY VESSEL" }, - { value: "VERY LARGE CRUDE OIL CARRIER", label: "VERY LARGE CRUDE OIL CARRIER" }, - { value: "WELL INTERVENTION SHIP", label: "WELL INTERVENTION SHIP" }, - { value: "WIND TURBINE INSTALLATION VESSEL", label: "WIND TURBINE INSTALLATION VESSEL" }, - { value: "기타", label: "기타" }, - ] - } - - if (!work) { - return null - } - - // 검토요청 불가능한 경우 안내 메시지 - if (!canRequest) { - return ( - <Dialog open={open} onOpenChange={onOpenChange}> - <DialogContent className="max-w-md"> - <DialogHeader> - <DialogTitle className="flex items-center gap-2 text-amber-600"> - <FileText className="h-5 w-5" /> - 검토요청 불가 - </DialogTitle> - <DialogDescription className="pt-4"> - {requestCheckMessage} - </DialogDescription> - </DialogHeader> - <div className="flex justify-end pt-4"> - <Button onClick={() => onOpenChange(false)}>확인</Button> - </div> - </DialogContent> - </Dialog> - ) - } - - return ( - <Dialog open={open} onOpenChange={handleOpenChange}> - <DialogContent className="max-w-4xl h-[90vh] p-0 flex flex-col"> - {/* 고정 헤더 */} - <div className="flex-shrink-0 p-6 border-b"> - <DialogHeader> - <DialogTitle className="flex items-center gap-2"> - <Send className="h-5 w-5" /> - 검토요청 발송 - </DialogTitle> - <DialogDescription> - 법무업무 #{work.id}에 대한 상세한 검토를 요청합니다. - </DialogDescription> - </DialogHeader> - </div> - - <Form {...form}> - <form - onSubmit={form.handleSubmit(onSubmit)} - className="flex flex-col flex-1 min-h-0" - > - {/* 스크롤 가능한 콘텐츠 영역 */} - <div className="flex-1 overflow-y-auto p-6"> - <div className="space-y-6"> - {/* 선택된 업무 정보 */} - <Card className="bg-blue-50 border-blue-200"> - <CardHeader> - <CardTitle className="text-lg flex items-center gap-2"> - <FileText className="h-5 w-5" /> - 검토 대상 업무 - </CardTitle> - </CardHeader> - <CardContent> - <div className="grid grid-cols-2 gap-4 text-sm"> - <div className="space-y-2"> - <div className="flex items-center gap-2"> - <span className="font-medium">업무 ID:</span> - <Badge variant="outline">#{work.id}</Badge> - </div> - <div className="flex items-center gap-2"> - <span className="font-medium">구분:</span> - <Badge variant={work.category === "CP" ? "default" : "secondary"}> - {work.category} - </Badge> - {work.isUrgent && ( - <Badge variant="destructive" className="text-xs"> - 긴급 - </Badge> - )} - </div> - <div className="flex items-center gap-2"> - <Building className="h-4 w-4" /> - <span className="font-medium">벤더:</span> - <span>{work.vendorCode} - {work.vendorName}</span> - </div> - </div> - <div className="space-y-2"> - <div className="flex items-center gap-2"> - <User className="h-4 w-4" /> - <span className="font-medium">요청자:</span> - <span>{work.reviewer || "미지정"}</span> - </div> - <div className="flex items-center gap-2"> - <Calendar className="h-4 w-4" /> - <span className="font-medium">답변요청일:</span> - <span>{work.requestDate || "미설정"}</span> - </div> - <div className="flex items-center gap-2"> - <span className="font-medium">상태:</span> - <Badge variant="outline">{work.status}</Badge> - </div> - </div> - </div> - </CardContent> - </Card> - - {/* 기본 설정 */} - <Card> - <CardHeader> - <CardTitle className="text-lg">기본 설정</CardTitle> - </CardHeader> - <CardContent className="space-y-4"> - {/* 검토 완료 희망일 */} - <FormField - control={form.control} - name="dueDate" - render={({ field }) => ( - <FormItem> - <FormLabel className="flex items-center gap-2"> - <Clock className="h-4 w-4" /> - 검토 완료 희망일 - </FormLabel> - <FormControl> - <Input type="date" {...field} /> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - </CardContent> - </Card> - - {/* 법무업무 상세 정보 */} - <Card> - <CardHeader> - <CardTitle className="text-lg">법무업무 상세 정보</CardTitle> - </CardHeader> - <CardContent className="space-y-4"> - {/* 검토부문 */} - <FormField - control={form.control} - name="reviewDepartment" - render={({ field }) => ( - <FormItem> - <FormLabel>검토부문</FormLabel> - <Select onValueChange={field.onChange} value={field.value}> - <FormControl> - <SelectTrigger> - <SelectValue placeholder="검토부문 선택" /> - </SelectTrigger> - </FormControl> - <SelectContent> - <SelectItem value="준법문의">준법문의</SelectItem> - <SelectItem value="법무검토">법무검토</SelectItem> - </SelectContent> - </Select> - <FormMessage /> - </FormItem> - )} - /> - - {/* 문의종류 (법무검토 선택시만) */} - {reviewDepartment === "법무검토" && ( - <FormField - control={form.control} - name="inquiryType" - render={({ field }) => ( - <FormItem> - <FormLabel>문의종류</FormLabel> - <Select onValueChange={field.onChange} value={field.value}> - <FormControl> - <SelectTrigger> - <SelectValue placeholder="문의종류 선택" /> - </SelectTrigger> - </FormControl> - <SelectContent> - <SelectItem value="국내계약">국내계약</SelectItem> - <SelectItem value="국내자문">국내자문</SelectItem> - <SelectItem value="해외계약">해외계약</SelectItem> - <SelectItem value="해외자문">해외자문</SelectItem> - </SelectContent> - </Select> - <FormMessage /> - </FormItem> - )} - /> - )} - - {/* 제목 - 조건부 렌더링 */} - <FormField - control={form.control} - name="title" - render={({ field }) => ( - <FormItem> - <FormLabel>제목</FormLabel> - {!isCustomTitle ? ( - // Select 모드 - <Select - onValueChange={(value) => { - if (value === "기타") { - setIsCustomTitle(true) - field.onChange("") // 빈 값으로 초기화 - } else { - field.onChange(value) - } - }} - value={field.value} - > - <FormControl> - <SelectTrigger> - <SelectValue placeholder="제목 선택" /> - </SelectTrigger> - </FormControl> - <SelectContent> - {getTitleOptions().map((option) => ( - <SelectItem key={option.value} value={option.value}> - {option.label} - </SelectItem> - ))} - </SelectContent> - </Select> - ) : ( - // Input 모드 (기타 선택시) - <div className="space-y-2"> - <div className="flex items-center gap-2"> - <Badge variant="outline" className="text-xs">기타</Badge> - <Button - type="button" - variant="ghost" - size="sm" - onClick={() => { - const defaultTitle = reviewDepartment === "준법문의" ? "CP검토" : "GTC검토" - form.setValue("title", defaultTitle) - setIsCustomTitle(false) // 상태 초기화 - }} - className="h-6 text-xs" - > - 선택 모드로 돌아가기 - </Button> - </div> - <FormControl> - <Input - placeholder="제목을 직접 입력하세요" - value={field.value} - onChange={(e) => field.onChange(e.target.value)} - autoFocus - /> - </FormControl> - </div> - )} - <FormMessage /> - </FormItem> - )} -/> - - {/* 준법문의 전용 필드들 */} - {reviewDepartment === "준법문의" && ( - <FormField - control={form.control} - name="isPublic" - render={({ field }) => ( - <FormItem className="flex flex-row items-center justify-between rounded-lg border p-4"> - <div className="space-y-0.5"> - <FormLabel className="text-base">공개여부</FormLabel> - <div className="text-sm text-muted-foreground"> - 준법문의 공개 설정 - </div> - </div> - <FormControl> - <Switch - checked={field.value} - onCheckedChange={field.onChange} - /> - </FormControl> - </FormItem> - )} - /> - )} - - {/* 법무검토 전용 필드들 */} - {reviewDepartment === "법무검토" && ( - <div className="space-y-4"> - {/* 계약명/프로젝트명 */} - <FormField - control={form.control} - name="contractProjectName" - render={({ field }) => ( - <FormItem> - <FormLabel>계약명/프로젝트명</FormLabel> - <FormControl> - <Input placeholder="계약명 또는 프로젝트명 입력" {...field} /> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - - {/* 계약서 종류 - 조건부 활성화 */} - {isContractTypeActive && ( - <FormField - control={form.control} - name="contractType" - render={({ field }) => ( - <FormItem> - <FormLabel>계약서 종류</FormLabel> - <Select onValueChange={field.onChange} value={field.value}> - <FormControl> - <SelectTrigger> - <SelectValue placeholder="계약서 종류 선택" /> - </SelectTrigger> - </FormControl> - <SelectContent> - {getContractTypeOptions().map((option) => ( - <SelectItem key={option.value} value={option.value}> - {option.label} - </SelectItem> - ))} - </SelectContent> - </Select> - <FormMessage /> - </FormItem> - )} - /> - )} - - {/* 국내계약 전용 필드들 */} - {isDomesticContractFieldsActive && ( - <div className="grid grid-cols-2 gap-4"> - {/* 계약상대방 */} - <FormField - control={form.control} - name="contractCounterparty" - render={({ field }) => ( - <FormItem> - <FormLabel>계약상대방</FormLabel> - <FormControl> - <Input placeholder="계약상대방 입력" {...field} /> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - - {/* 계약상대방 구분 */} - <FormField - control={form.control} - name="counterpartyType" - render={({ field }) => ( - <FormItem> - <FormLabel>계약상대방 구분</FormLabel> - <Select onValueChange={field.onChange} value={field.value}> - <FormControl> - <SelectTrigger> - <SelectValue placeholder="구분 선택" /> - </SelectTrigger> - </FormControl> - <SelectContent> - <SelectItem value="법인">법인</SelectItem> - <SelectItem value="개인">개인</SelectItem> - </SelectContent> - </Select> - <FormMessage /> - </FormItem> - )} - /> - - {/* 계약기간 */} - <FormField - control={form.control} - name="contractPeriod" - render={({ field }) => ( - <FormItem> - <FormLabel>계약기간</FormLabel> - <FormControl> - <Input placeholder="계약기간 입력" {...field} /> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - - {/* 계약금액 */} - <FormField - control={form.control} - name="contractAmount" - render={({ field }) => ( - <FormItem> - <FormLabel>계약금액</FormLabel> - <FormControl> - <Input placeholder="계약금액 입력" {...field} /> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - </div> - )} - - {/* 사실관계 - 조건부 활성화 */} - {isFactualRelationActive && ( - <FormField - control={form.control} - name="factualRelation" - render={({ field }) => ( - <FormItem> - <FormLabel>사실관계</FormLabel> - <FormControl> - <Textarea - placeholder="사실관계를 상세히 입력해주세요" - className="min-h-[80px]" - {...field} - /> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - )} - - {/* 해외 관련 필드들 - 조건부 활성화 */} - {isOverseasFieldsActive && ( - <div className="grid grid-cols-2 gap-4"> - {/* 프로젝트번호 */} - <FormField - control={form.control} - name="projectNumber" - render={({ field }) => ( - <FormItem> - <FormLabel>프로젝트번호</FormLabel> - <FormControl> - <Input placeholder="프로젝트번호 입력" {...field} /> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - - {/* 선주/발주처 */} - <FormField - control={form.control} - name="shipownerOrderer" - render={({ field }) => ( - <FormItem> - <FormLabel>선주/발주처</FormLabel> - <FormControl> - <Input placeholder="선주/발주처 입력" {...field} /> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - - {/* 프로젝트종류 */} - <FormField - control={form.control} - name="projectType" - render={({ field }) => ( - <FormItem> - <FormLabel>프로젝트종류</FormLabel> - <Select onValueChange={field.onChange} value={field.value}> - <FormControl> - <SelectTrigger> - <SelectValue placeholder="프로젝트종류 선택" /> - </SelectTrigger> - </FormControl> - <SelectContent> - {getProjectTypeOptions().map((option) => ( - <SelectItem key={option.value} value={option.value}> - {option.label} - </SelectItem> - ))} - </SelectContent> - </Select> - <FormMessage /> - </FormItem> - )} - /> - - {/* 준거법 */} - <FormField - control={form.control} - name="governingLaw" - render={({ field }) => ( - <FormItem> - <FormLabel>준거법</FormLabel> - <FormControl> - <Input placeholder="준거법 입력" {...field} /> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - </div> - )} - </div> - )} - - {/* 요청내용 - TiptapEditor로 교체 */} - <FormField - control={form.control} - name="requestContent" - render={({ field }) => ( - <FormItem> - <FormLabel>요청내용</FormLabel> - <FormControl> - <div className="min-h-[250px]"> - <TiptapEditor - content={editorContent} - setContent={setEditorContent} - disabled={isSubmitting} - height="250px" - /> - </div> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - - {/* 첨부파일 */} - <div className="space-y-2"> - <FormLabel>첨부파일</FormLabel> - <div className="border-2 border-dashed border-muted-foreground/25 rounded-lg p-4"> - <input - type="file" - multiple - onChange={handleFileChange} - className="hidden" - id="file-upload" - /> - <label - htmlFor="file-upload" - className="flex flex-col items-center justify-center cursor-pointer" - > - <Upload className="h-8 w-8 text-muted-foreground mb-2" /> - <span className="text-sm text-muted-foreground"> - 파일을 선택하거나 여기로 드래그하세요 - </span> - </label> - </div> - - {/* 선택된 파일 목록 */} - {attachments.length > 0 && ( - <div className="space-y-2"> - {attachments.map((file, index) => ( - <div key={index} className="flex items-center justify-between bg-muted/50 p-2 rounded"> - <span className="text-sm truncate">{file.name}</span> - <Button - type="button" - variant="ghost" - size="sm" - onClick={() => removeAttachment(index)} - > - <X className="h-4 w-4" /> - </Button> - </div> - ))} - </div> - )} - </div> - </CardContent> - </Card> - </div> - </div> - - {/* 고정 버튼 영역 */} - <div className="flex-shrink-0 border-t p-6"> - <div className="flex justify-end gap-3"> - <Button - type="button" - variant="outline" - onClick={() => handleOpenChange(false)} - disabled={isSubmitting} - > - 취소 - </Button> - <Button - type="submit" - disabled={isSubmitting} - className="bg-blue-600 hover:bg-blue-700" - > - {isSubmitting ? ( - <> - <Loader2 className="mr-2 h-4 w-4 animate-spin" /> - 발송 중... - </> - ) : ( - <> - <Send className="mr-2 h-4 w-4" /> - 검토요청 발송 - </> - )} - </Button> - </div> - </div> - </form> - </Form> - </DialogContent> - </Dialog> - ) -}
\ No newline at end of file |
