diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-07-21 07:54:26 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-07-21 07:54:26 +0000 |
| commit | 14f61e24947fb92dd71ec0a7196a6e815f8e66da (patch) | |
| tree | 317c501d64662d05914330628f867467fba78132 /lib/tech-vendors/table/update-vendor-sheet.tsx | |
| parent | 194bd4bd7e6144d5c09c5e3f5476d254234dce72 (diff) | |
(최겸)기술영업 RFQ 담당자 초대, 요구사항 반영
Diffstat (limited to 'lib/tech-vendors/table/update-vendor-sheet.tsx')
| -rw-r--r-- | lib/tech-vendors/table/update-vendor-sheet.tsx | 1035 |
1 files changed, 623 insertions, 412 deletions
diff --git a/lib/tech-vendors/table/update-vendor-sheet.tsx b/lib/tech-vendors/table/update-vendor-sheet.tsx index 1d05b0c4..8498df51 100644 --- a/lib/tech-vendors/table/update-vendor-sheet.tsx +++ b/lib/tech-vendors/table/update-vendor-sheet.tsx @@ -1,413 +1,624 @@ -"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, - Building, -} 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 { useSession } from "next-auth/react" // Import useSession - -import { TechVendor, techVendors } from "@/db/schema/techVendors" -import { updateTechVendorSchema, type UpdateTechVendorSchema } from "../validations" -import { modifyTechVendor } from "../service" - -interface UpdateVendorSheetProps - extends React.ComponentPropsWithRef<typeof Sheet> { - 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 "PENDING_REVIEW": - 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<UpdateTechVendorSchema>({ - resolver: zodResolver(updateTechVendorSchema), - defaultValues: { - // 업체 기본 정보 - vendorName: vendor?.vendorName ?? "", - vendorCode: vendor?.vendorCode ?? "", - address: vendor?.address ?? "", - country: vendor?.country ?? "", - 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", - }, - }) - - 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 ?? "", - techVendorType: vendor?.techVendorType ? vendor.techVendorType.split(',').map(s => s.trim()).filter(Boolean) as ("조선" | "해양TOP" | "해양HULL")[] : [], - status: vendor?.status ?? "ACTIVE", - - }); - } - }, [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 ( - <Sheet {...props}> - <SheetContent className="flex flex-col gap-6 sm:max-w-lg overflow-y-auto"> - <SheetHeader className="text-left"> - <SheetTitle>업체 정보 수정</SheetTitle> - <SheetDescription> - 업체 세부 정보를 수정하고 변경 사항을 저장하세요 - </SheetDescription> - </SheetHeader> - <Form {...form}> - <form onSubmit={form.handleSubmit(onSubmit)} className="flex flex-col gap-6"> - {/* 업체 기본 정보 섹션 */} - <div className="space-y-4"> - <div className="flex items-center"> - <Building className="mr-2 h-5 w-5 text-muted-foreground" /> - <h3 className="text-sm font-medium">업체 기본 정보</h3> - </div> - <FormDescription> - 업체가 제공한 기본 정보입니다. 필요시 수정하세요. - </FormDescription> - <div className="grid grid-cols-1 gap-4 md:grid-cols-2"> - {/* vendorName */} - <FormField - control={form.control} - name="vendorName" - render={({ field }) => ( - <FormItem> - <FormLabel>업체명</FormLabel> - <FormControl> - <Input placeholder="업체명 입력" {...field} /> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - - {/* vendorCode */} - <FormField - control={form.control} - name="vendorCode" - render={({ field }) => ( - <FormItem> - <FormLabel>업체 코드</FormLabel> - <FormControl> - <Input placeholder="예: ABC123" {...field} /> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - - {/* address */} - <FormField - control={form.control} - name="address" - render={({ field }) => ( - <FormItem className="md:col-span-2"> - <FormLabel>주소</FormLabel> - <FormControl> - <Input placeholder="주소 입력" {...field} /> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - - {/* country */} - <FormField - control={form.control} - name="country" - render={({ field }) => ( - <FormItem> - <FormLabel>국가</FormLabel> - <FormControl> - <Input placeholder="예: 대한민국" {...field} /> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - - {/* phone */} - <FormField - control={form.control} - name="phone" - render={({ field }) => ( - <FormItem> - <FormLabel>전화번호</FormLabel> - <FormControl> - <Input placeholder="예: 010-1234-5678" {...field} /> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - - {/* email */} - <FormField - control={form.control} - name="email" - render={({ field }) => ( - <FormItem> - <FormLabel>이메일</FormLabel> - <FormControl> - <Input placeholder="예: info@company.com" {...field} /> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - - {/* website */} - <FormField - control={form.control} - name="website" - render={({ field }) => ( - <FormItem> - <FormLabel>웹사이트</FormLabel> - <FormControl> - <Input placeholder="예: https://www.company.com" {...field} /> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - - {/* techVendorType */} - <FormField - control={form.control} - name="techVendorType" - render={({ field }) => ( - <FormItem className="md:col-span-2"> - <FormLabel>벤더 타입 *</FormLabel> - <div className="space-y-2"> - {["조선", "해양TOP", "해양HULL"].map((type) => ( - <div key={type} className="flex items-center space-x-2"> - <input - type="checkbox" - id={`update-${type}`} - checked={field.value?.includes(type as "조선" | "해양TOP" | "해양HULL")} - onChange={(e) => { - 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" - /> - <label htmlFor={`update-${type}`} className="text-sm font-medium cursor-pointer"> - {type} - </label> - </div> - ))} - </div> - <FormMessage /> - </FormItem> - )} - /> - - {/* status with icons */} - <FormField - control={form.control} - name="status" - render={({ field }) => { - // 현재 선택된 상태의 구성 정보 가져오기 - const selectedConfig = getStatusConfig(field.value ?? "ACTIVE"); - const SelectedIcon = selectedConfig?.Icon || CircleIcon; - - return ( - <FormItem> - <FormLabel>업체승인상태</FormLabel> - <FormControl> - <Select - value={field.value || ""} - onValueChange={field.onChange} - > - <SelectTrigger className="w-full"> - <SelectValue> - {field.value && ( - <div className="flex items-center"> - <SelectedIcon className={`mr-2 h-4 w-4 ${selectedConfig.className}`} /> - <span>{selectedConfig.label}</span> - </div> - )} - </SelectValue> - </SelectTrigger> - <SelectContent> - <SelectGroup> - {techVendors.status.enumValues.map((status) => { - const config = getStatusConfig(status); - const StatusIcon = config.Icon; - return ( - <SelectItem key={status} value={status}> - <div className="flex items-center"> - <StatusIcon className={`mr-2 h-4 w-4 ${config.className}`} /> - <span>{config.label}</span> - </div> - </SelectItem> - ); - })} - </SelectGroup> - </SelectContent> - </Select> - </FormControl> - <FormMessage /> - </FormItem> - ); - }} - /> - - - - - </div> - </div> - - <SheetFooter className="gap-2 pt-2 sm:space-x-0"> - <SheetClose asChild> - <Button type="button" variant="outline"> - 취소 - </Button> - </SheetClose> - <Button disabled={isPending}> - {isPending && ( - <Loader className="mr-2 h-4 w-4 animate-spin" aria-hidden="true" /> - )} - 저장 - </Button> - </SheetFooter> - </form> - </Form> - </SheetContent> - </Sheet> - ) +"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<typeof Sheet> {
+ 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<UpdateTechVendorSchema>({
+ 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 (
+ <Sheet {...props}>
+ <SheetContent className="flex flex-col gap-6 sm:max-w-xl overflow-y-auto">
+ <SheetHeader className="text-left">
+ <SheetTitle>업체 정보 수정</SheetTitle>
+ <SheetDescription>
+ 업체 세부 정보를 수정하고 변경 사항을 저장하세요
+ </SheetDescription>
+ </SheetHeader>
+
+ <Form {...form}>
+ <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
+
+ {/* 업체 기본 정보 섹션 */}
+ <Card>
+ <CardHeader className="pb-3">
+ <CardTitle className="text-base">
+ 업체 기본 정보
+ </CardTitle>
+ <CardDescription>
+ 업체의 기본 정보를 관리합니다
+ </CardDescription>
+ </CardHeader>
+ <CardContent className="space-y-4">
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
+ {/* 업체명 */}
+ <FormField
+ control={form.control}
+ name="vendorName"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel>업체명</FormLabel>
+ <FormControl>
+ <Input placeholder="업체명 입력" {...field} />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+
+ {/* 업체 코드 */}
+ <FormField
+ control={form.control}
+ name="vendorCode"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel>업체 코드</FormLabel>
+ <FormControl>
+ <Input placeholder="예: ABC123" {...field} />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+
+ {/* 이메일 */}
+ <FormField
+ control={form.control}
+ name="email"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel>이메일</FormLabel>
+ <FormControl>
+ <Input placeholder="예: info@company.com" {...field} />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+
+ {/* 전화번호 */}
+ <FormField
+ control={form.control}
+ name="phone"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel>전화번호</FormLabel>
+ <FormControl>
+ <Input placeholder="예: 010-1234-5678" {...field} />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+
+ {/* 웹사이트 */}
+ <FormField
+ control={form.control}
+ name="website"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel>웹사이트</FormLabel>
+ <FormControl>
+ <Input placeholder="예: https://www.company.com" {...field} />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+ </div>
+
+ {/* 주소 */}
+ <FormField
+ control={form.control}
+ name="address"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel>주소</FormLabel>
+ <FormControl>
+ <Input placeholder="주소 입력" {...field} />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
+ {/* 국가 */}
+ <FormField
+ control={form.control}
+ name="country"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel>국가</FormLabel>
+ <FormControl>
+ <Input placeholder="예: 대한민국" {...field} />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+
+ {/* 국가(영문) */}
+ <FormField
+ control={form.control}
+ name="countryEng"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel>국가(영문)</FormLabel>
+ <FormControl>
+ <Input placeholder="예: South Korea" {...field} />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+
+ {/* 제조국가 */}
+ <FormField
+ control={form.control}
+ name="countryFab"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel>제조국가</FormLabel>
+ <FormControl>
+ <Input placeholder="제조국가 입력" {...field} />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+ </div>
+
+ {/* 벤더 타입 */}
+ <FormField
+ control={form.control}
+ name="techVendorType"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel>벤더 타입 *</FormLabel>
+ <div className="flex gap-6">
+ {["조선", "해양TOP", "해양HULL"].map((type) => (
+ <div key={type} className="flex items-center space-x-2">
+ <input
+ type="checkbox"
+ id={`update-${type}`}
+ checked={field.value?.includes(type as "조선" | "해양TOP" | "해양HULL")}
+ onChange={(e) => {
+ 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"
+ />
+ <label htmlFor={`update-${type}`} className="text-sm font-medium cursor-pointer">
+ {type}
+ </label>
+ </div>
+ ))}
+ </div>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+ </CardContent>
+ </Card>
+
+ {/* 승인 상태 섹션 */}
+ <Card>
+ <CardHeader className="pb-3">
+ <CardTitle className="text-base">
+ 승인 상태
+ </CardTitle>
+ <CardDescription>
+ 업체의 승인 상태를 관리합니다
+ </CardDescription>
+ </CardHeader>
+ <CardContent>
+ <FormField
+ control={form.control}
+ name="status"
+ render={({ field }) => {
+ const selectedConfig = getStatusConfig(field.value ?? "ACTIVE");
+ const SelectedIcon = selectedConfig?.Icon || CircleIcon;
+
+ return (
+ <FormItem>
+ <FormLabel>업체 승인 상태</FormLabel>
+ <FormControl>
+ <Select
+ value={field.value || ""}
+ onValueChange={field.onChange}
+ >
+ <SelectTrigger className="w-full">
+ <SelectValue>
+ {field.value && (
+ <div className="flex items-center">
+ <SelectedIcon className={`mr-2 h-4 w-4 ${selectedConfig.className}`} />
+ <span>{selectedConfig.label}</span>
+ </div>
+ )}
+ </SelectValue>
+ </SelectTrigger>
+ <SelectContent>
+ <SelectGroup>
+ {techVendors.status.enumValues.map((status) => {
+ const config = getStatusConfig(status);
+ const StatusIcon = config.Icon;
+ return (
+ <SelectItem key={status} value={status}>
+ <div className="flex items-center">
+ <StatusIcon className={`mr-2 h-4 w-4 ${config.className}`} />
+ <span>{config.label}</span>
+ </div>
+ </SelectItem>
+ );
+ })}
+ </SelectGroup>
+ </SelectContent>
+ </Select>
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ );
+ }}
+ />
+ </CardContent>
+ </Card>
+
+ {/* 에이전트 정보 섹션 */}
+ <Card>
+ <CardHeader className="pb-3">
+ <CardTitle className="text-base">
+ 에이전트 정보
+ </CardTitle>
+ <CardDescription>
+ 해당 업체의 에이전트 정보를 관리합니다
+ </CardDescription>
+ </CardHeader>
+ <CardContent>
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
+ {/* 에이전트명 */}
+ <FormField
+ control={form.control}
+ name="agentName"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel>에이전트명</FormLabel>
+ <FormControl>
+ <Input placeholder="에이전트명 입력" {...field} />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+
+ {/* 에이전트 전화번호 */}
+ <FormField
+ control={form.control}
+ name="agentPhone"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel>에이전트 전화번호</FormLabel>
+ <FormControl>
+ <Input placeholder="에이전트 전화번호 입력" {...field} />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+
+ {/* 에이전트 이메일 */}
+ <FormField
+ control={form.control}
+ name="agentEmail"
+ render={({ field }) => (
+ <FormItem className="md:col-span-2">
+ <FormLabel>에이전트 이메일</FormLabel>
+ <FormControl>
+ <Input type="email" placeholder="에이전트 이메일 입력" {...field} />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+ </div>
+ </CardContent>
+ </Card>
+
+ {/* 대표자 정보 섹션 */}
+ <Card>
+ <CardHeader className="pb-3">
+ <CardTitle className="text-base">
+ 대표자 정보
+ </CardTitle>
+ <CardDescription>
+ 업체 대표자의 정보를 관리합니다
+ </CardDescription>
+ </CardHeader>
+ <CardContent>
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
+ {/* 대표자명 */}
+ <FormField
+ control={form.control}
+ name="representativeName"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel>대표자명</FormLabel>
+ <FormControl>
+ <Input placeholder="대표자명 입력" {...field} />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+
+ {/* 대표자 생년월일 */}
+ <FormField
+ control={form.control}
+ name="representativeBirth"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel>대표자 생년월일</FormLabel>
+ <FormControl>
+ <Input placeholder="YYYY-MM-DD" {...field} />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+
+ {/* 대표자 전화번호 */}
+ <FormField
+ control={form.control}
+ name="representativePhone"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel>대표자 전화번호</FormLabel>
+ <FormControl>
+ <Input placeholder="대표자 전화번호 입력" {...field} />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+
+ {/* 대표자 이메일 */}
+ <FormField
+ control={form.control}
+ name="representativeEmail"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel>대표자 이메일</FormLabel>
+ <FormControl>
+ <Input type="email" placeholder="대표자 이메일 입력" {...field} />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+ </div>
+ </CardContent>
+ </Card>
+
+ <SheetFooter className="gap-2 pt-2 sm:space-x-0">
+ <SheetClose asChild>
+ <Button type="button" variant="outline">
+ 취소
+ </Button>
+ </SheetClose>
+ <Button disabled={isPending}>
+ {isPending && (
+ <Loader className="mr-2 h-4 w-4 animate-spin" aria-hidden="true" />
+ )}
+ 저장
+ </Button>
+ </SheetFooter>
+ </form>
+ </Form>
+ </SheetContent>
+ </Sheet>
+ )
}
\ No newline at end of file |
