"use client"; import { useEffect, useTransition, useState, useRef } from "react"; import { useRouter } from "next/navigation"; import { z } from "zod"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { Search, X } from "lucide-react"; import { customAlphabet } from "nanoid"; import { Button } from "@/components/ui/button"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage, } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { Badge } from "@/components/ui/badge"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { DatePicker } from "@/components/ui/date-picker"; import { cn } from "@/lib/utils"; import { RFQ_STATUS_OPTIONS, SERIES_OPTIONS } from "@/lib/rfq-last/validations"; const generateId = customAlphabet("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 6); const rfqFilterSchema = z.object({ rfqCode: z.string().optional(), status: z.string().optional(), series: z.string().optional(), projectCode: z.string().optional(), projectName: z.string().optional(), itemCode: z.string().optional(), itemName: z.string().optional(), packageNo: z.string().optional(), picName: z.string().optional(), vendorCountMin: z.string().optional(), vendorCountMax: z.string().optional(), dueDateFrom: z.date().optional(), dueDateTo: z.date().optional(), rfqSendDateFrom: z.date().optional(), rfqSendDateTo: z.date().optional(), // 일반견적 필드 rfqType: z.string().optional(), rfqTitle: z.string().optional(), // ITB 필드 projectCompany: z.string().optional(), projectSite: z.string().optional(), smCode: z.string().optional(), // RFQ 필드 prNumber: z.string().optional(), }); export type RfqFilterFormValues = z.infer; interface RfqFilterSheetProps { isOpen: boolean; onClose: () => void; isLoading?: boolean; onFiltersApply: (filters: any[], joinOperator: "and" | "or") => void; rfqCategory?: "all" | "general" | "itb" | "rfq"; } export function RfqFilterSheet({ isOpen, onClose, isLoading = false, onFiltersApply, rfqCategory = "all", }: RfqFilterSheetProps) { const router = useRouter(); const [isPending, startTransition] = useTransition(); const [joinOperator, setJoinOperator] = useState<"and" | "or">("and"); const form = useForm({ resolver: zodResolver(rfqFilterSchema), defaultValues: { rfqCode: "", status: "", series: "", projectCode: "", projectName: "", itemCode: "", itemName: "", packageNo: "", picName: "", vendorCountMin: "", vendorCountMax: "", dueDateFrom: undefined, dueDateTo: undefined, rfqSendDateFrom: undefined, rfqSendDateTo: undefined, rfqType: "", rfqTitle: "", projectCompany: "", projectSite: "", smCode: "", prNumber: "", }, }); async function onSubmit(data: RfqFilterFormValues) { startTransition(() => { try { const newFilters: any[] = []; // 기본 필드 if (data.rfqCode?.trim()) { newFilters.push({ id: "rfqCode", value: data.rfqCode.trim(), type: "text", operator: "iLike", rowId: generateId() }); } if (data.status?.trim()) { newFilters.push({ id: "status", value: data.status.trim(), type: "select", operator: "eq", rowId: generateId() }); } if (data.series?.trim()) { newFilters.push({ id: "series", value: data.series.trim(), type: "select", operator: "eq", rowId: generateId() }); } if (data.projectCode?.trim()) { newFilters.push({ id: "projectCode", value: data.projectCode.trim(), type: "text", operator: "iLike", rowId: generateId() }); } if (data.projectName?.trim()) { newFilters.push({ id: "projectName", value: data.projectName.trim(), type: "text", operator: "iLike", rowId: generateId() }); } if (data.itemCode?.trim()) { newFilters.push({ id: "itemCode", value: data.itemCode.trim(), type: "text", operator: "iLike", rowId: generateId() }); } if (data.itemName?.trim()) { newFilters.push({ id: "itemName", value: data.itemName.trim(), type: "text", operator: "iLike", rowId: generateId() }); } if (data.packageNo?.trim()) { newFilters.push({ id: "packageNo", value: data.packageNo.trim(), type: "text", operator: "iLike", rowId: generateId() }); } if (data.picName?.trim()) { newFilters.push({ id: "picUserName", value: data.picName.trim(), type: "text", operator: "iLike", rowId: generateId() }); } // 벤더 수 범위 if (data.vendorCountMin?.trim()) { newFilters.push({ id: "vendorCount", value: parseInt(data.vendorCountMin.trim()), type: "number", operator: "gte", rowId: generateId() }); } if (data.vendorCountMax?.trim()) { newFilters.push({ id: "vendorCount", value: parseInt(data.vendorCountMax.trim()), type: "number", operator: "lte", rowId: generateId() }); } // 날짜 필터 if (data.dueDateFrom) { newFilters.push({ id: "dueDate", value: data.dueDateFrom.toISOString(), type: "date", operator: "gte", rowId: generateId() }); } if (data.dueDateTo) { newFilters.push({ id: "dueDate", value: data.dueDateTo.toISOString(), type: "date", operator: "lte", rowId: generateId() }); } if (data.rfqSendDateFrom) { newFilters.push({ id: "rfqSendDate", value: data.rfqSendDateFrom.toISOString(), type: "date", operator: "gte", rowId: generateId() }); } if (data.rfqSendDateTo) { newFilters.push({ id: "rfqSendDate", value: data.rfqSendDateTo.toISOString(), type: "date", operator: "lte", rowId: generateId() }); } // 일반견적 필드 if ((rfqCategory === "general" || rfqCategory === "all") && data.rfqType?.trim()) { newFilters.push({ id: "rfqType", value: data.rfqType.trim(), type: "text", operator: "iLike", rowId: generateId() }); } if ((rfqCategory === "general" || rfqCategory === "all") && data.rfqTitle?.trim()) { newFilters.push({ id: "rfqTitle", value: data.rfqTitle.trim(), type: "text", operator: "iLike", rowId: generateId() }); } // ITB 필드 if ((rfqCategory === "itb" || rfqCategory === "all") && data.projectCompany?.trim()) { newFilters.push({ id: "projectCompany", value: data.projectCompany.trim(), type: "text", operator: "iLike", rowId: generateId() }); } if ((rfqCategory === "itb" || rfqCategory === "all") && data.projectSite?.trim()) { newFilters.push({ id: "projectSite", value: data.projectSite.trim(), type: "text", operator: "iLike", rowId: generateId() }); } if ((rfqCategory === "itb" || rfqCategory === "all") && data.smCode?.trim()) { newFilters.push({ id: "smCode", value: data.smCode.trim(), type: "text", operator: "iLike", rowId: generateId() }); } // RFQ 필드 if ((rfqCategory === "rfq" || rfqCategory === "all") && data.prNumber?.trim()) { newFilters.push({ id: "prNumber", value: data.prNumber.trim(), type: "text", operator: "iLike", rowId: generateId() }); } console.log("=== 생성된 필터들 ===", newFilters); console.log("=== 조인 연산자 ===", joinOperator); onFiltersApply(newFilters, joinOperator); onClose(); console.log("=== 필터 적용 완료 ==="); } catch (error) { console.error("RFQ 필터 적용 오류:", error); } }); } function handleReset() { form.reset(); setJoinOperator("and"); const currentUrl = new URL(window.location.href); const newSearchParams = new URLSearchParams(currentUrl.search); newSearchParams.set("filters", JSON.stringify([])); newSearchParams.set("joinOperator", "and"); newSearchParams.set("page", "1"); newSearchParams.delete("search"); router.replace(`${currentUrl.pathname}?${newSearchParams.toString()}`); onFiltersApply([], "and"); console.log("=== 필터 완전 초기화 완료 ==="); } if (!isOpen) return null; return (
{/* Header */}

RFQ 검색 필터

{/* Join operator selector */}
{/* Form */}
{/* RFQ 코드 */} ( 견적 No.
{field.value && ( )}
)} /> {/* 견적상태 */} ( 견적상태 )} /> {/* 시리즈 (RFQ 카테고리일 때만) */} {(rfqCategory === "rfq" || rfqCategory === "all") && ( ( 시리즈 )} /> )} {/* 프로젝트 정보 */} ( 프로젝트
{field.value && ( )}
)} /> {/* 일반견적 필드 */} {(rfqCategory === "general" || rfqCategory === "all") && ( <> ( 견적 종류
{field.value && ( )}
)} /> ( 견적 제목
{field.value && ( )}
)} /> )} {/* ITB 필드 */} {/* {(rfqCategory === "itb" || rfqCategory === "all") && ( <> ( 프로젝트 회사
{field.value && ( )}
)} /> )} */} {/* RFQ 필드 */} {(rfqCategory === "rfq" || rfqCategory === "all") && ( ( PR 번호
{field.value && ( )}
)} /> )} {/* 날짜 범위 필터 */}
마감일 범위
( field.onChange(date)} placeholder="시작일" /> )} /> ( field.onChange(date)} placeholder="종료일" /> )} />
{/* Footer buttons */}
); }