"use client" import * as React from "react" import { zodResolver } from "@hookform/resolvers/zod" import { useForm } from "react-hook-form" import { Loader, Activity, AlertCircle, AlertTriangle, Circle as CircleIcon } from "lucide-react" import { toast } from "sonner" import { Button } from "@/components/ui/button" import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } 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 { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { useSession } from "next-auth/react" import { TechVendor, techVendors } from "@/db/schema/techVendors" import { updateTechVendorSchema, type UpdateTechVendorSchema } from "../validations" import { modifyTechVendor } from "../service" interface UpdateVendorSheetProps extends React.ComponentPropsWithRef { vendor: TechVendor | null } type StatusType = (typeof techVendors.status.enumValues)[number]; type StatusConfig = { Icon: React.ElementType; className: string; label: string; }; // 상태 표시 유틸리티 함수 const getStatusConfig = (status: StatusType): StatusConfig => { switch(status) { 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: "거래 금지" }; case "QUOTE_COMPARISON": return { Icon: AlertTriangle, className: "text-slate-800", label: "비교 견적" }; case "PENDING_INVITE": return { Icon: AlertTriangle, className: "text-slate-800", label: "초대 대기" }; case "INVITED": return { Icon: AlertTriangle, className: "text-slate-800", label: "초대 완료" }; default: return { Icon: CircleIcon, className: "text-gray-600", label: status }; } }; // 폼 컴포넌트 export function UpdateVendorSheet({ vendor, ...props }: UpdateVendorSheetProps) { const [isPending, startTransition] = React.useTransition() const { data: session } = useSession() // 폼 정의 - UpdateVendorSchema 타입을 직접 사용 const form = useForm({ resolver: zodResolver(updateTechVendorSchema), defaultValues: { // 업체 기본 정보 vendorName: vendor?.vendorName ?? "", vendorCode: vendor?.vendorCode ?? "", address: vendor?.address ?? "", country: vendor?.country ?? "", countryEng: vendor?.countryEng ?? "", countryFab: vendor?.countryFab ?? "", phone: vendor?.phone ?? "", email: vendor?.email ?? "", website: vendor?.website ?? "", techVendorType: vendor?.techVendorType ? vendor.techVendorType.split(',').map(s => s.trim()).filter(Boolean) as ("조선" | "해양TOP" | "해양HULL")[] : [], status: vendor?.status ?? "ACTIVE", // 에이전트 정보 agentName: vendor?.agentName ?? "", agentEmail: vendor?.agentEmail ?? "", agentPhone: vendor?.agentPhone ?? "", // 대표자 정보 representativeName: vendor?.representativeName ?? "", representativeEmail: vendor?.representativeEmail ?? "", representativePhone: vendor?.representativePhone ?? "", representativeBirth: vendor?.representativeBirth ?? "", }, }) React.useEffect(() => { if (vendor) { form.reset({ vendorName: vendor?.vendorName ?? "", vendorCode: vendor?.vendorCode ?? "", address: vendor?.address ?? "", country: vendor?.country ?? "", countryEng: vendor?.countryEng ?? "", countryFab: vendor?.countryFab ?? "", phone: vendor?.phone ?? "", email: vendor?.email ?? "", website: vendor?.website ?? "", techVendorType: vendor?.techVendorType ? vendor.techVendorType.split(',').map(s => s.trim()).filter(Boolean) as ("조선" | "해양TOP" | "해양HULL")[] : [], status: vendor?.status ?? "ACTIVE", // 에이전트 정보 agentName: vendor?.agentName ?? "", agentEmail: vendor?.agentEmail ?? "", agentPhone: vendor?.agentPhone ?? "", // 대표자 정보 representativeName: vendor?.representativeName ?? "", representativeEmail: vendor?.representativeEmail ?? "", representativePhone: vendor?.representativePhone ?? "", representativeBirth: vendor?.representativeBirth ?? "", }); } }, [vendor, form]); // 제출 핸들러 async function onSubmit(data: UpdateTechVendorSchema) { if (!vendor) return 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 modifyTechVendor({ id: String(vendor.id), userId: Number(session.user.id), // Add user ID from session comment: statusComment, // Add comment for status changes ...data, // 모든 데이터 전달 - 서비스 함수에서 필요한 필드만 처리 techVendorType: Array.isArray(data.techVendorType) ? data.techVendorType.join(',') : undefined, }) if (error) throw new Error(error) toast.success("업체 정보가 업데이트되었습니다!") form.reset() props.onOpenChange?.(false) } catch (err: unknown) { toast.error(String(err)) } }) } return ( 업체 정보 수정 업체 세부 정보를 수정하고 변경 사항을 저장하세요
{/* 업체 기본 정보 섹션 */} 업체 기본 정보 업체의 기본 정보를 관리합니다
{/* 업체명 */} ( 업체명 )} /> {/* 업체 코드 */} ( 업체 코드 )} /> {/* 이메일 */} ( 이메일 )} /> {/* 전화번호 */} ( 전화번호 )} /> {/* 웹사이트 */} ( 웹사이트 )} />
{/* 주소 */} ( 주소 )} />
{/* 국가 */} ( 국가 )} /> {/* 국가(영문) */} ( 국가(영문) )} /> {/* 제조국가 */} ( 제조국가 )} />
{/* 벤더 타입 */} ( 벤더 타입 *
{["조선", "해양TOP", "해양HULL"].map((type) => (
{ const currentValue = Array.isArray(field.value) ? field.value : []; if (e.target.checked) { field.onChange([...currentValue, type]); } else { field.onChange(currentValue.filter((v: string) => v !== type)); } }} className="w-4 h-4" />
))}
)} />
{/* 승인 상태 섹션 */} 승인 상태 업체의 승인 상태를 관리합니다 { const selectedConfig = getStatusConfig(field.value ?? "ACTIVE"); const SelectedIcon = selectedConfig?.Icon || CircleIcon; return ( 업체 승인 상태 ); }} /> {/* 에이전트 정보 섹션 */} 에이전트 정보 해당 업체의 에이전트 정보를 관리합니다
{/* 에이전트명 */} ( 에이전트명 )} /> {/* 에이전트 전화번호 */} ( 에이전트 전화번호 )} /> {/* 에이전트 이메일 */} ( 에이전트 이메일 )} />
{/* 대표자 정보 섹션 */} 대표자 정보 업체 대표자의 정보를 관리합니다
{/* 대표자명 */} ( 대표자명 )} /> {/* 대표자 생년월일 */} ( 대표자 생년월일 )} /> {/* 대표자 전화번호 */} ( 대표자 전화번호 )} /> {/* 대표자 이메일 */} ( 대표자 이메일 )} />
) }