"use client" import * as React from "react" import { zodResolver } from "@hookform/resolvers/zod" import { useForm } from "react-hook-form" import { Loader, Activity, AlertCircle, AlertTriangle, ClipboardList, FilePenLine, XCircle, ClipboardCheck, FileCheck2, FileX2, BadgeCheck, CheckCircle2, Circle as CircleIcon, User, Building, AlignLeft, Calendar } from "lucide-react" import { toast } from "sonner" import { Button } from "@/components/ui/button" import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage, FormDescription } from "@/components/ui/form" import { Input } from "@/components/ui/input" import { Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, } from "@/components/ui/sheet" import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select" import { Separator } from "@/components/ui/separator" import { useSession } from "next-auth/react" // Import useSession import { VendorWithType, vendors } from "@/db/schema/vendors" import { updateVendorSchema, type UpdateVendorSchema } from "../validations" import { modifyVendor } from "../service" interface UpdateVendorSheetProps extends React.ComponentPropsWithRef { vendor: VendorWithType | null } type StatusType = (typeof vendors.status.enumValues)[number]; type StatusConfig = { Icon: React.ElementType; className: string; label: string; }; // 상태 표시 유틸리티 함수 const getStatusConfig = (status: StatusType): StatusConfig => { switch(status) { case "PENDING_REVIEW": return { Icon: ClipboardList, className: "text-yellow-600", label: "가입 신청 중" }; case "IN_REVIEW": return { Icon: FilePenLine, className: "text-blue-600", label: "심사 중" }; case "REJECTED": return { Icon: XCircle, className: "text-red-600", label: "심사 거부됨" }; case "IN_PQ": return { Icon: ClipboardCheck, className: "text-purple-600", label: "PQ 진행 중" }; case "PQ_SUBMITTED": return { Icon: FileCheck2, className: "text-indigo-600", label: "PQ 제출" }; case "PQ_FAILED": return { Icon: FileX2, className: "text-red-600", label: "PQ 실패" }; case "PQ_APPROVED": return { Icon: BadgeCheck, className: "text-green-600", label: "PQ 통과" }; case "APPROVED": return { Icon: CheckCircle2, className: "text-green-600", label: "승인됨" }; case "READY_TO_SEND": return { Icon: CheckCircle2, className: "text-emerald-600", label: "MDG 송부대기" }; case "ACTIVE": return { Icon: Activity, className: "text-emerald-600", label: "활성 상태" }; case "INACTIVE": return { Icon: AlertCircle, className: "text-gray-600", label: "비활성 상태" }; case "BLACKLISTED": return { Icon: AlertTriangle, className: "text-slate-800", label: "거래 금지" }; default: return { Icon: CircleIcon, className: "text-gray-600", label: status }; } }; // 신용평가기관 목록 const creditAgencies = [ { value: "NICE", label: "NICE평가정보" }, { value: "KIS", label: "KIS (한국신용평가)" }, { value: "KED", label: "KED (한국기업데이터)" }, { value: "SCI", label: "SCI평가정보" }, ] // 신용등급 스케일 const creditRatingScaleMap: Record = { NICE: ["AAA", "AA", "A", "BBB", "BB", "B", "C", "D"], KIS: ["AAA", "AA+", "AA", "A+", "A", "BBB+", "BBB", "BB", "B", "C"], KED: ["AAA", "AA", "A", "BBB", "BB", "B", "CCC", "CC", "C", "D"], SCI: ["AAA", "AA+", "AA", "AA-", "A+", "A", "A-", "BBB+", "BBB-", "B"], } // 현금흐름등급 스케일 const cashFlowRatingScaleMap: Record = { NICE: ["우수", "양호", "보통", "미흡", "불량"], KIS: ["A+", "A", "B+", "B", "C", "D"], KED: ["1등급", "2등급", "3등급", "4등급", "5등급"], SCI: ["Level 1", "Level 2", "Level 3", "Level 4"], } // 폼 컴포넌트 export function UpdateVendorSheet({ vendor, ...props }: UpdateVendorSheetProps) { const [isPending, startTransition] = React.useTransition() const [selectedAgency, setSelectedAgency] = React.useState(vendor?.creditAgency || "NICE") // 폼 정의 - UpdateVendorSchema 타입을 직접 사용 const form = useForm({ resolver: zodResolver(updateVendorSchema), defaultValues: { // 업체 기본 정보 vendorName: vendor?.vendorName ?? "", vendorCode: vendor?.vendorCode ?? "", address: vendor?.address ?? "", country: vendor?.country ?? "", phone: vendor?.phone ?? "", email: vendor?.email ?? "", website: vendor?.website ?? "", creditRating: vendor?.creditRating ?? "", cashFlowRating: vendor?.cashFlowRating ?? "", status: vendor?.status ?? "ACTIVE", vendorTypeId: vendor?.vendorTypeId ?? undefined, // 구매담당자 정보 (기본값은 비어있음) buyerName: "", buyerDepartment: "", contractStartDate: undefined, contractEndDate: undefined, internalNotes: "", // evaluationScore: "", }, }) React.useEffect(() => { if (vendor) { form.reset({ vendorName: vendor?.vendorName ?? "", vendorCode: vendor?.vendorCode ?? "", address: vendor?.address ?? "", country: vendor?.country ?? "", phone: vendor?.phone ?? "", email: vendor?.email ?? "", website: vendor?.website ?? "", creditRating: vendor?.creditRating ?? "", cashFlowRating: vendor?.cashFlowRating ?? "", status: vendor?.status ?? "ACTIVE", vendorTypeId: vendor?.vendorTypeId ?? undefined, // 구매담당자 필드는 유지 buyerName: form.getValues("buyerName"), buyerDepartment: form.getValues("buyerDepartment"), contractStartDate: form.getValues("contractStartDate"), contractEndDate: form.getValues("contractEndDate"), internalNotes: form.getValues("internalNotes"), // evaluationScore: form.getValues("evaluationScore"), }); } }, [vendor, form]); // 신용평가기관 변경 시 등급 필드를 초기화하는 효과 React.useEffect(() => { // 선택된 평가기관에 따라 현재 선택된 등급이 유효한지 확인 const currentCreditRating = form.getValues("creditRating"); const currentCashFlowRating = form.getValues("cashFlowRating"); // 선택된 기관에 따른 유효한 등급 목록 const validCreditRatings = creditRatingScaleMap[selectedAgency] || []; const validCashFlowRatings = cashFlowRatingScaleMap[selectedAgency] || []; // 현재 등급이 유효하지 않으면 초기화 if (currentCreditRating && !validCreditRatings.includes(currentCreditRating)) { form.setValue("creditRating", ""); } if (currentCashFlowRating && !validCashFlowRatings.includes(currentCashFlowRating)) { form.setValue("cashFlowRating", ""); } // 신용평가기관 필드 업데이트 if(selectedAgency){ form.setValue("creditAgency", selectedAgency as "NICE" | "KIS" | "KED" | "SCI"); } }, [selectedAgency, form]); // 제출 핸들러 async function onSubmit(data: UpdateVendorSchema) { if (!vendor) return const { data: session } = useSession() if (!session?.user?.id) { toast.error("사용자 인증 정보를 찾을 수 없습니다.") return } startTransition(async () => { try { // Add status change comment if status has changed const oldStatus = vendor.status ?? "ACTIVE" // Default to ACTIVE if undefined const newStatus = data.status ?? "ACTIVE" // Default to ACTIVE if undefined const statusComment = oldStatus !== newStatus ? `상태 변경: ${getStatusConfig(oldStatus).label} → ${getStatusConfig(newStatus).label}` : "" // Empty string instead of undefined // 업체 정보 업데이트 - userId와 상태 변경 코멘트 추가 const { error } = await modifyVendor({ id: String(vendor.id), userId: Number(session.user.id), // Add user ID from session comment: statusComment, // Add comment for status changes ...data // 모든 데이터 전달 - 서비스 함수에서 필요한 필드만 처리 }) if (error) throw new Error(error) toast.success("업체 정보가 업데이트되었습니다!") form.reset() props.onOpenChange?.(false) } catch (err: any) { toast.error(String(err)) } }) } return ( 업체 정보 수정 업체 세부 정보를 수정하고 변경 사항을 저장하세요
{/* 업체 기본 정보 섹션 */}

업체 기본 정보

업체가 제공한 기본 정보입니다. 필요시 수정하세요.
{/* vendorName */} ( 업체명 )} /> {/* vendorCode */} ( 업체 코드 )} /> {/* address */} ( 주소 )} /> {/* country */} ( 국가 )} /> {/* phone */} ( 전화번호 )} /> {/* email */} ( 이메일 )} /> {/* website */} ( 웹사이트 )} /> {/* status with icons */} { // 현재 선택된 상태의 구성 정보 가져오기 const selectedConfig = getStatusConfig(field.value ?? "ACTIVE"); const SelectedIcon = selectedConfig?.Icon || CircleIcon; return ( 업체승인상태 ); }} /> {/* 신용평가기관 선택 */} ( 신용평가기관 )} /> {/* 평가년도 - 나중에 추가 가능 */} {/* 신용등급 - 선택된 기관에 따라 옵션 변경 */} ( 신용등급 )} /> {/* 현금흐름등급 - 선택된 기관에 따라 옵션 변경 */} ( 현금흐름등급 )} />
{/* 구분선 */} {/* 구매담당자 입력 섹션 */}

구매담당자 정보

구매담당자가 관리하는 추가 정보입니다. 이 정보는 내부용으로만 사용됩니다.
{/* 여기에 구매담당자 필드 추가 */} ( 담당자 이름 )} /> ( 담당 부서 )} /> ( 내부 메모 )} />
) }