From 1dc24d48e52f2e490f5603ceb02842586ecae533 Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
Date: Thu, 24 Jul 2025 11:06:32 +0000
Subject: (대표님) 정기평가 피드백 반영, 설계 피드백 반영, (최겸) 기술영업
 피드백 반영
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 lib/evaluation/table/evaluation-filter-sheet.tsx | 616 ++++++++---------------
 1 file changed, 203 insertions(+), 413 deletions(-)

(limited to 'lib/evaluation/table/evaluation-filter-sheet.tsx')

diff --git a/lib/evaluation/table/evaluation-filter-sheet.tsx b/lib/evaluation/table/evaluation-filter-sheet.tsx
index 7f4de6a6..8f435e36 100644
--- a/lib/evaluation/table/evaluation-filter-sheet.tsx
+++ b/lib/evaluation/table/evaluation-filter-sheet.tsx
@@ -1,19 +1,15 @@
-// ================================================================
-// 2. PERIODIC EVALUATIONS FILTER SHEET
-// ================================================================
-
-"use client"
-
-import { useEffect, useTransition, useState, useRef } from "react"
-import { useRouter, useParams } 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 { parseAsStringEnum, useQueryState } from "nuqs"
-
-import { Button } from "@/components/ui/button"
+"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 { parseAsStringEnum, useQueryState } from "nuqs";
+
+import { Button } from "@/components/ui/button";
 import {
   Form,
   FormControl,
@@ -21,50 +17,28 @@ import {
   FormItem,
   FormLabel,
   FormMessage,
-} from "@/components/ui/form"
-import { Input } from "@/components/ui/input"
-import { Badge } from "@/components/ui/badge"
+} 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 { cn } from "@/lib/utils"
-import { getFiltersStateParser } from "@/lib/parsers"
+} from "@/components/ui/select";
+import { cn } from "@/lib/utils";
+import { getFiltersStateParser } from "@/lib/parsers";
+import { EVALUATION_TARGET_FILTER_OPTIONS } from "@/lib/evaluation-target-list/validation";
 
-// nanoid 생성기
-const generateId = customAlphabet("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 6)
+/*****************************************************************************************
+ * UTILS & CONSTANTS
+ *****************************************************************************************/
 
-// 정기평가 필터 스키마 정의
-const periodicEvaluationFilterSchema = z.object({
-  evaluationYear: z.string().optional(),
-  evaluationPeriod: z.string().optional(),
-  division: z.string().optional(),
-  status: z.string().optional(),
-  domesticForeign: z.string().optional(),
-  materialType: z.string().optional(),
-  vendorCode: z.string().optional(),
-  vendorName: z.string().optional(),
-  documentsSubmitted: z.string().optional(),
-  evaluationGrade: z.string().optional(),
-  finalGrade: z.string().optional(),
-  minTotalScore: z.string().optional(),
-  maxTotalScore: z.string().optional(),
-})
+// nanoid generator (6‑chars [0-9a-zA-Z])
+const generateId = customAlphabet("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 6);
 
-// 옵션 정의
-const evaluationPeriodOptions = [
-  { value: "상반기", label: "상반기" },
-  { value: "하반기", label: "하반기" },
-  { value: "연간", label: "연간" },
-]
-
-const divisionOptions = [
-  { value: "PLANT", label: "해양" },
-  { value: "SHIP", label: "조선" },
-]
+// ── SELECT OPTIONS ──────────────────────────────────────────────────────────────────────
 
 const statusOptions = [
   { value: "PENDING", label: "대상확정" },
@@ -73,70 +47,76 @@ const statusOptions = [
   { value: "IN_REVIEW", label: "평가중" },
   { value: "REVIEW_COMPLETED", label: "평가완료" },
   { value: "FINALIZED", label: "결과확정" },
-]
-
-const domesticForeignOptions = [
-  { value: "DOMESTIC", label: "내자" },
-  { value: "FOREIGN", label: "외자" },
-]
+];
 
-const materialTypeOptions = [
-  { value: "EQUIPMENT", label: "기자재" },
-  { value: "BULK", label: "벌크" },
-  { value: "EQUIPMENT_BULK", label: "기자재/벌크" },
-]
 
 const documentsSubmittedOptions = [
   { value: "true", label: "제출완료" },
   { value: "false", label: "미제출" },
-]
+];
 
 const gradeOptions = [
   { value: "A", label: "A등급" },
   { value: "B", label: "B등급" },
   { value: "C", label: "C등급" },
   { value: "D", label: "D등급" },
-]
+];
 
-type PeriodicEvaluationFilterFormValues = z.infer<typeof periodicEvaluationFilterSchema>
+/*****************************************************************************************
+ * ZOD SCHEMA & TYPES
+ *****************************************************************************************/
+const periodicEvaluationFilterSchema = z.object({
+  evaluationYear: z.string().optional(),
+  division: z.string().optional(),
+  status: z.string().optional(),
+  domesticForeign: z.string().optional(),
+  materialType: z.string().optional(),
+  vendorCode: z.string().optional(),
+  vendorName: z.string().optional(),
+  documentsSubmitted: z.string().optional(),
+  evaluationGrade: z.string().optional(),
+  finalGrade: z.string().optional(),
+  minTotalScore: z.string().optional(),
+  maxTotalScore: z.string().optional(),
+});
 
+export type PeriodicEvaluationFilterFormValues = z.infer<
+  typeof periodicEvaluationFilterSchema
+>;
+
+/*****************************************************************************************
+ * COMPONENT
+ *****************************************************************************************/
 interface PeriodicEvaluationFilterSheetProps {
+  /** Slide‑over visibility */
   isOpen: boolean;
+  /** Close panel handler */
   onClose: () => void;
-  onSearch?: () => void;
+  /** Show skeleton / spinner while outer data grid fetches */
   isLoading?: boolean;
+  /** Optional: fire immediately after URL is patched so parent can refetch */
+  onFiltersApply: (filters: any[], joinOperator: "and" | "or") => void; // ✅ 필터 전달 콜백
 }
 
 export function PeriodicEvaluationFilterSheet({
   isOpen,
   onClose,
-  onSearch,
-  isLoading = false
+  isLoading = false,
+  onFiltersApply,
 }: PeriodicEvaluationFilterSheetProps) {
-  const router = useRouter()
-  const params = useParams();
-
-  const [isPending, startTransition] = useTransition()
-  const [isInitializing, setIsInitializing] = useState(false)
-  const lastAppliedFilters = useRef<string>("")
+  /** Router (needed only for pathname) */
+  const router = useRouter();
 
-  // nuqs로 URL 상태 관리
-  const [filters, setFilters] = useQueryState(
-    "basicFilters",
-    getFiltersStateParser().withDefault([])
-  )
+  /** Track pending state while we update URL */
+  const [isPending, startTransition] = useTransition();
+  const [joinOperator, setJoinOperator] = useState<"and" | "or">("and")
 
-  const [joinOperator, setJoinOperator] = useQueryState(
-    "basicJoinOperator",
-    parseAsStringEnum(["and", "or"]).withDefault("and")
-  )
 
-  // 폼 상태 초기화
+  /** React‑Hook‑Form */
   const form = useForm<PeriodicEvaluationFilterFormValues>({
     resolver: zodResolver(periodicEvaluationFilterSchema),
     defaultValues: {
       evaluationYear: new Date().getFullYear().toString(),
-      evaluationPeriod: "",
       division: "",
       status: "",
       domesticForeign: "",
@@ -149,273 +129,130 @@ export function PeriodicEvaluationFilterSheet({
       minTotalScore: "",
       maxTotalScore: "",
     },
-  })
-
-  // URL 필터에서 초기 폼 상태 설정
-  useEffect(() => {
-    const currentFiltersString = JSON.stringify(filters);
-
-    if (isOpen && filters && filters.length > 0 && currentFiltersString !== lastAppliedFilters.current) {
-      setIsInitializing(true);
-
-      const formValues = { ...form.getValues() };
-      let formUpdated = false;
-
-      filters.forEach(filter => {
-        if (filter.id in formValues) {
-          // @ts-ignore - 동적 필드 접근
-          formValues[filter.id] = filter.value;
-          formUpdated = true;
-        }
-      });
-
-      if (formUpdated) {
-        form.reset(formValues);
-        lastAppliedFilters.current = currentFiltersString;
-      }
-
-      setIsInitializing(false);
-    }
-  }, [filters, isOpen])
+  });
 
-  // 현재 적용된 필터 카운트
-  const getActiveFilterCount = () => {
-    return filters?.length || 0
-  }
 
-  // 폼 제출 핸들러
+  /*****************************************************************************************
+   * 3️⃣  Submit → build filter array → push to URL (and reset page=1)
+   *****************************************************************************************/
   async function onSubmit(data: PeriodicEvaluationFilterFormValues) {
-    if (isInitializing) return;
-
-    startTransition(async () => {
+    startTransition(() => {
       try {
-        const newFilters = []
+        const newFilters: any[] = [];
 
-        if (data.evaluationYear?.trim()) {
-          newFilters.push({
-            id: "evaluationYear",
-            value: parseInt(data.evaluationYear.trim()),
-            type: "number",
-            operator: "eq",
-            rowId: generateId()
-          })
-        }
+        const pushFilter = (
+          id: string,
+          value: any,
+          type: "text" | "select" | "number" | "boolean",
+          operator: "eq" | "iLike" | "gte" | "lte"
+        ) => {
+          newFilters.push({ id, value, type, operator, rowId: generateId() });
+        };
 
-        if (data.evaluationPeriod?.trim()) {
-          newFilters.push({
-            id: "evaluationPeriod",
-            value: data.evaluationPeriod.trim(),
-            type: "select",
-            operator: "eq",
-            rowId: generateId()
-          })
-        }
+        if (data.evaluationYear?.trim())
+          pushFilter("evaluationYear", Number(data.evaluationYear), "number", "eq");
 
-        if (data.division?.trim()) {
-          newFilters.push({
-            id: "division",
-            value: data.division.trim(),
-            type: "select",
-            operator: "eq",
-            rowId: generateId()
-          })
-        }
+        if (data.division?.trim())
+          pushFilter("division", data.division.trim(), "select", "eq");
 
-        if (data.status?.trim()) {
-          newFilters.push({
-            id: "status",
-            value: data.status.trim(),
-            type: "select",
-            operator: "eq",
-            rowId: generateId()
-          })
-        }
+        if (data.status?.trim())
+          pushFilter("status", data.status.trim(), "select", "eq");
 
-        if (data.domesticForeign?.trim()) {
-          newFilters.push({
-            id: "domesticForeign",
-            value: data.domesticForeign.trim(),
-            type: "select",
-            operator: "eq",
-            rowId: generateId()
-          })
-        }
+        if (data.domesticForeign?.trim())
+          pushFilter("domesticForeign", data.domesticForeign.trim(), "select", "eq");
 
-        if (data.materialType?.trim()) {
-          newFilters.push({
-            id: "materialType",
-            value: data.materialType.trim(),
-            type: "select",
-            operator: "eq",
-            rowId: generateId()
-          })
-        }
+        if (data.materialType?.trim())
+          pushFilter("materialType", data.materialType.trim(), "select", "eq");
 
-        if (data.vendorCode?.trim()) {
-          newFilters.push({
-            id: "vendorCode",
-            value: data.vendorCode.trim(),
-            type: "text",
-            operator: "iLike",
-            rowId: generateId()
-          })
-        }
+        if (data.vendorCode?.trim())
+          pushFilter("vendorCode", data.vendorCode.trim(), "text", "iLike");
 
-        if (data.vendorName?.trim()) {
-          newFilters.push({
-            id: "vendorName",
-            value: data.vendorName.trim(),
-            type: "text",
-            operator: "iLike",
-            rowId: generateId()
-          })
-        }
+        if (data.vendorName?.trim())
+          pushFilter("vendorName", data.vendorName.trim(), "text", "iLike");
 
-        if (data.documentsSubmitted?.trim()) {
-          newFilters.push({
-            id: "documentsSubmitted",
-            value: data.documentsSubmitted.trim() === "true",
-            type: "boolean",
-            operator: "eq",
-            rowId: generateId()
-          })
-        }
+        if (data.documentsSubmitted?.trim())
+          pushFilter(
+            "documentsSubmitted",
+            data.documentsSubmitted.trim() === "true",
+            "boolean",
+            "eq"
+          );
 
-        if (data.evaluationGrade?.trim()) {
-          newFilters.push({
-            id: "evaluationGrade",
-            value: data.evaluationGrade.trim(),
-            type: "select",
-            operator: "eq",
-            rowId: generateId()
-          })
-        }
+        if (data.evaluationGrade?.trim())
+          pushFilter("evaluationGrade", data.evaluationGrade.trim(), "select", "eq");
 
-        if (data.finalGrade?.trim()) {
-          newFilters.push({
-            id: "finalGrade",
-            value: data.finalGrade.trim(),
-            type: "select",
-            operator: "eq",
-            rowId: generateId()
-          })
-        }
+        if (data.finalGrade?.trim())
+          pushFilter("finalGrade", data.finalGrade.trim(), "select", "eq");
 
-        if (data.minTotalScore?.trim()) {
-          newFilters.push({
-            id: "totalScore",
-            value: parseFloat(data.minTotalScore.trim()),
-            type: "number",
-            operator: "gte",
-            rowId: generateId()
-          })
-        }
+        if (data.minTotalScore?.trim())
+          pushFilter("totalScore", Number(data.minTotalScore), "number", "gte");
 
-        if (data.maxTotalScore?.trim()) {
-          newFilters.push({
-            id: "totalScore",
-            value: parseFloat(data.maxTotalScore.trim()),
-            type: "number",
-            operator: "lte",
-            rowId: generateId()
-          })
-        }
+        if (data.maxTotalScore?.trim())
+          pushFilter("totalScore", Number(data.maxTotalScore), "number", "lte");
 
-        // URL 업데이트
-        const currentUrl = new URL(window.location.href);
-        const params = new URLSearchParams(currentUrl.search);
-        
-        params.delete('basicFilters');
-        params.delete('basicJoinOperator');
-        params.delete('page');
-        
-        if (newFilters.length > 0) {
-          params.set('basicFilters', JSON.stringify(newFilters));
-          params.set('basicJoinOperator', joinOperator);
-        }
-        
-        params.set('page', '1');
-        
-        const newUrl = `${currentUrl.pathname}?${params.toString()}`;
-        window.location.href = newUrl;
+        setJoinOperator(joinOperator);
 
-        lastAppliedFilters.current = JSON.stringify(newFilters);
 
-        if (onSearch) {
-          onSearch();
-        }
-      } catch (error) {
-        console.error("정기평가 필터 적용 오류:", error);
+        onFiltersApply(newFilters, joinOperator);
+      } catch (err) {
+        // eslint-disable-next-line no-console
+        console.error("정기평가 필터 적용 오류:", err);
       }
-    })
+    });
   }
 
-  // 필터 초기화 핸들러
+  /*****************************************************************************************
+   * 4️⃣  Reset → clear form & URL
+   *****************************************************************************************/
   async function handleReset() {
-    try {
-      setIsInitializing(true);
-
-      form.reset({
-        evaluationYear: new Date().getFullYear().toString(),
-        evaluationPeriod: "",
-        division: "",
-        status: "",
-        domesticForeign: "",
-        materialType: "",
-        vendorCode: "",
-        vendorName: "",
-        documentsSubmitted: "",
-        evaluationGrade: "",
-        finalGrade: "",
-        minTotalScore: "",
-        maxTotalScore: "",
-      });
-
-      const currentUrl = new URL(window.location.href);
-      const params = new URLSearchParams(currentUrl.search);
-
-      params.delete('basicFilters');
-      params.delete('basicJoinOperator');
-      params.set('page', '1');
+    form.reset({
+      evaluationYear: new Date().getFullYear().toString(),
+      division: "",
+      status: "",
+      domesticForeign: "",
+      materialType: "",
+      vendorCode: "",
+      vendorName: "",
+      documentsSubmitted: "",
+      evaluationGrade: "",
+      finalGrade: "",
+      minTotalScore: "",
+      maxTotalScore: "",
+    });
 
-      const newUrl = `${currentUrl.pathname}?${params.toString()}`;
-      window.location.href = newUrl;
+    onFiltersApply([], "and");
+    setJoinOperator("and");
 
-      lastAppliedFilters.current = "";
-      setIsInitializing(false);
-    } catch (error) {
-      console.error("정기평가 필터 초기화 오류:", error);
-      setIsInitializing(false);
-    }
   }
 
-  if (!isOpen) {
-    return null;
-  }
+  /*****************************************************************************************
+   * 5️⃣  RENDER
+   *****************************************************************************************/
+  if (!isOpen) return null;
 
   return (
-    <div className="flex flex-col h-full max-h-full bg-[#F5F7FB] px-6 sm:px-8" style={{backgroundColor:"#F5F7FB", paddingLeft:"2rem", paddingRight:"2rem"}}>
-      {/* Filter Panel Header */}
-      <div className="flex items-center justify-between px-6 min-h-[60px] shrink-0">
-        <h3 className="text-lg font-semibold whitespace-nowrap">정기평가 검색 필터</h3>
+    <div
+      className="flex h-full max-h-full flex-col px-6 sm:px-8"
+      style={{ backgroundColor: "#F5F7FB", paddingLeft: "2rem", paddingRight: "2rem" }}
+    >
+      {/* Header */}
+      <div className="flex shrink-0 min-h-[60px] items-center justify-between px-6">
+        <h3 className="whitespace-nowrap text-lg font-semibold">정기평가 검색 필터</h3>
         <div className="flex items-center gap-2">
-          {getActiveFilterCount() > 0 && (
-            <Badge variant="secondary" className="px-2 py-1">
-              {getActiveFilterCount()}개 필터 적용됨
-            </Badge>
-          )}
+          <Button variant="ghost" size="icon" onClick={onClose} className="h-8 w-8">
+            <X className="size-4" />
+          </Button>
         </div>
       </div>
 
-      {/* Join Operator Selection */}
-      <div className="px-6 shrink-0">
+      {/* Join‑operator selector */}
+      <div className="shrink-0 px-6">
         <label className="text-sm font-medium">조건 결합 방식</label>
         <Select
           value={joinOperator}
-          onValueChange={(value: "and" | "or") => setJoinOperator(value)}
-          disabled={isInitializing}
+          onValueChange={(v: "and" | "or") => setJoinOperator(v)}
         >
-          <SelectTrigger className="h-8 w-[180px] mt-2 bg-white">
+          <SelectTrigger className="mt-2 h-8 w-[180px] bg-white">
             <SelectValue placeholder="조건 결합 방식" />
           </SelectTrigger>
           <SelectContent>
@@ -425,12 +262,12 @@ export function PeriodicEvaluationFilterSheet({
         </Select>
       </div>
 
+      {/* Form */}
       <Form {...form}>
-        <form onSubmit={form.handleSubmit(onSubmit)} className="flex flex-col h-full min-h-0">
-          {/* Scrollable content area */}
+        <form onSubmit={form.handleSubmit(onSubmit)} className="flex min-h-0 flex-col h-full">
+          {/* Scrollable area */}
           <div className="flex-1 min-h-0 overflow-y-auto px-6 pb-4">
             <div className="space-y-4 pt-2">
-              
               {/* 평가년도 */}
               <FormField
                 control={form.control}
@@ -444,20 +281,20 @@ export function PeriodicEvaluationFilterSheet({
                           type="number"
                           placeholder="평가년도 입력"
                           {...field}
-                          className={cn(field.value && "pr-8", "bg-white")}
                           disabled={isInitializing}
+                          className={cn(field.value && "pr-8", "bg-white")}
                         />
                         {field.value && (
                           <Button
                             type="button"
                             variant="ghost"
                             size="icon"
-                            className="absolute right-0 top-0 h-full px-2"
                             onClick={(e) => {
                               e.stopPropagation();
                               form.setValue("evaluationYear", "");
                             }}
                             disabled={isInitializing}
+                            className="absolute right-0 top-0 h-full px-2"
                           >
                             <X className="size-3.5" />
                           </Button>
@@ -469,52 +306,6 @@ export function PeriodicEvaluationFilterSheet({
                 )}
               />
 
-              {/* 평가기간 */}
-              {/* <FormField
-                control={form.control}
-                name="evaluationPeriod"
-                render={({ field }) => (
-                  <FormItem>
-                    <FormLabel>평가기간</FormLabel>
-                    <Select
-                      value={field.value}
-                      onValueChange={field.onChange}
-                      disabled={isInitializing}
-                    >
-                      <FormControl>
-                        <SelectTrigger className={cn(field.value && "pr-8", "bg-white")}>
-                          <div className="flex justify-between w-full">
-                            <SelectValue placeholder="평가기간 선택" />
-                            {field.value && (
-                              <Button
-                                type="button"
-                                variant="ghost"
-                                size="icon"
-                                className="h-4 w-4 -mr-2"
-                                onClick={(e) => {
-                                  e.stopPropagation();
-                                  form.setValue("evaluationPeriod", "");
-                                }}
-                                disabled={isInitializing}
-                              >
-                                <X className="size-3" />
-                              </Button>
-                            )}
-                          </div>
-                        </SelectTrigger>
-                      </FormControl>
-                      <SelectContent>
-                        {evaluationPeriodOptions.map(option => (
-                          <SelectItem key={option.value} value={option.value}>
-                            {option.label}
-                          </SelectItem>
-                        ))}
-                      </SelectContent>
-                    </Select>
-                    <FormMessage />
-                  </FormItem>
-                )}
-              /> */}
 
               {/* 구분 */}
               <FormField
@@ -530,14 +321,14 @@ export function PeriodicEvaluationFilterSheet({
                     >
                       <FormControl>
                         <SelectTrigger className={cn(field.value && "pr-8", "bg-white")}>
-                          <div className="flex justify-between w-full">
+                          <div className="flex w-full justify-between">
                             <SelectValue placeholder="구분 선택" />
                             {field.value && (
                               <Button
                                 type="button"
                                 variant="ghost"
                                 size="icon"
-                                className="h-4 w-4 -mr-2"
+                                className="-mr-2 h-4 w-4"
                                 onClick={(e) => {
                                   e.stopPropagation();
                                   form.setValue("division", "");
@@ -551,9 +342,9 @@ export function PeriodicEvaluationFilterSheet({
                         </SelectTrigger>
                       </FormControl>
                       <SelectContent>
-                        {divisionOptions.map(option => (
-                          <SelectItem key={option.value} value={option.value}>
-                            {option.label}
+                        {EVALUATION_TARGET_FILTER_OPTIONS.DIVISIONS.map((opt) => (
+                          <SelectItem key={opt.value} value={opt.value}>
+                            {opt.label}
                           </SelectItem>
                         ))}
                       </SelectContent>
@@ -577,14 +368,14 @@ export function PeriodicEvaluationFilterSheet({
                     >
                       <FormControl>
                         <SelectTrigger className={cn(field.value && "pr-8", "bg-white")}>
-                          <div className="flex justify-between w-full">
+                          <div className="flex w-full justify-between">
                             <SelectValue placeholder="진행상태 선택" />
                             {field.value && (
                               <Button
                                 type="button"
                                 variant="ghost"
                                 size="icon"
-                                className="h-4 w-4 -mr-2"
+                                className="-mr-2 h-4 w-4"
                                 onClick={(e) => {
                                   e.stopPropagation();
                                   form.setValue("status", "");
@@ -598,9 +389,9 @@ export function PeriodicEvaluationFilterSheet({
                         </SelectTrigger>
                       </FormControl>
                       <SelectContent>
-                        {statusOptions.map(option => (
-                          <SelectItem key={option.value} value={option.value}>
-                            {option.label}
+                        {statusOptions.map((opt) => (
+                          <SelectItem key={opt.value} value={opt.value}>
+                            {opt.label}
                           </SelectItem>
                         ))}
                       </SelectContent>
@@ -624,14 +415,14 @@ export function PeriodicEvaluationFilterSheet({
                     >
                       <FormControl>
                         <SelectTrigger className={cn(field.value && "pr-8", "bg-white")}>
-                          <div className="flex justify-between w-full">
+                          <div className="flex w-full justify-between">
                             <SelectValue placeholder="내외자 구분 선택" />
                             {field.value && (
                               <Button
                                 type="button"
                                 variant="ghost"
                                 size="icon"
-                                className="h-4 w-4 -mr-2"
+                                className="-mr-2 h-4 w-4"
                                 onClick={(e) => {
                                   e.stopPropagation();
                                   form.setValue("domesticForeign", "");
@@ -645,9 +436,9 @@ export function PeriodicEvaluationFilterSheet({
                         </SelectTrigger>
                       </FormControl>
                       <SelectContent>
-                        {domesticForeignOptions.map(option => (
-                          <SelectItem key={option.value} value={option.value}>
-                            {option.label}
+                        {EVALUATION_TARGET_FILTER_OPTIONS.DOMESTIC_FOREIGN.map((opt) => (
+                          <SelectItem key={opt.value} value={opt.value}>
+                            {opt.label}
                           </SelectItem>
                         ))}
                       </SelectContent>
@@ -671,14 +462,14 @@ export function PeriodicEvaluationFilterSheet({
                     >
                       <FormControl>
                         <SelectTrigger className={cn(field.value && "pr-8", "bg-white")}>
-                          <div className="flex justify-between w-full">
+                          <div className="flex w-full justify-between">
                             <SelectValue placeholder="자재구분 선택" />
                             {field.value && (
                               <Button
                                 type="button"
                                 variant="ghost"
                                 size="icon"
-                                className="h-4 w-4 -mr-2"
+                                className="-mr-2 h-4 w-4"
                                 onClick={(e) => {
                                   e.stopPropagation();
                                   form.setValue("materialType", "");
@@ -692,9 +483,9 @@ export function PeriodicEvaluationFilterSheet({
                         </SelectTrigger>
                       </FormControl>
                       <SelectContent>
-                        {materialTypeOptions.map(option => (
-                          <SelectItem key={option.value} value={option.value}>
-                            {option.label}
+                        {EVALUATION_TARGET_FILTER_OPTIONS.MATERIAL_TYPES.map((opt) => (
+                          <SelectItem key={opt.value} value={opt.value}>
+                            {opt.label}
                           </SelectItem>
                         ))}
                       </SelectContent>
@@ -716,8 +507,8 @@ export function PeriodicEvaluationFilterSheet({
                         <Input
                           placeholder="벤더 코드 입력"
                           {...field}
-                          className={cn(field.value && "pr-8", "bg-white")}
                           disabled={isInitializing}
+                          className={cn(field.value && "pr-8", "bg-white")}
                         />
                         {field.value && (
                           <Button
@@ -753,8 +544,8 @@ export function PeriodicEvaluationFilterSheet({
                         <Input
                           placeholder="벤더명 입력"
                           {...field}
-                          className={cn(field.value && "pr-8", "bg-white")}
                           disabled={isInitializing}
+                          className={cn(field.value && "pr-8", "bg-white")}
                         />
                         {field.value && (
                           <Button
@@ -792,14 +583,14 @@ export function PeriodicEvaluationFilterSheet({
                     >
                       <FormControl>
                         <SelectTrigger className={cn(field.value && "pr-8", "bg-white")}>
-                          <div className="flex justify-between w-full">
+                          <div className="flex w-full justify-between">
                             <SelectValue placeholder="문서제출여부 선택" />
                             {field.value && (
                               <Button
                                 type="button"
                                 variant="ghost"
                                 size="icon"
-                                className="h-4 w-4 -mr-2"
+                                className="-mr-2 h-4 w-4"
                                 onClick={(e) => {
                                   e.stopPropagation();
                                   form.setValue("documentsSubmitted", "");
@@ -813,9 +604,9 @@ export function PeriodicEvaluationFilterSheet({
                         </SelectTrigger>
                       </FormControl>
                       <SelectContent>
-                        {documentsSubmittedOptions.map(option => (
-                          <SelectItem key={option.value} value={option.value}>
-                            {option.label}
+                        {documentsSubmittedOptions.map((opt) => (
+                          <SelectItem key={opt.value} value={opt.value}>
+                            {opt.label}
                           </SelectItem>
                         ))}
                       </SelectContent>
@@ -839,14 +630,14 @@ export function PeriodicEvaluationFilterSheet({
                     >
                       <FormControl>
                         <SelectTrigger className={cn(field.value && "pr-8", "bg-white")}>
-                          <div className="flex justify-between w-full">
+                          <div className="flex w-full justify-between">
                             <SelectValue placeholder="평가등급 선택" />
                             {field.value && (
                               <Button
                                 type="button"
                                 variant="ghost"
                                 size="icon"
-                                className="h-4 w-4 -mr-2"
+                                className="-mr-2 h-4 w-4"
                                 onClick={(e) => {
                                   e.stopPropagation();
                                   form.setValue("evaluationGrade", "");
@@ -860,9 +651,9 @@ export function PeriodicEvaluationFilterSheet({
                         </SelectTrigger>
                       </FormControl>
                       <SelectContent>
-                        {gradeOptions.map(option => (
-                          <SelectItem key={option.value} value={option.value}>
-                            {option.label}
+                        {gradeOptions.map((opt) => (
+                          <SelectItem key={opt.value} value={opt.value}>
+                            {opt.label}
                           </SelectItem>
                         ))}
                       </SelectContent>
@@ -886,14 +677,14 @@ export function PeriodicEvaluationFilterSheet({
                     >
                       <FormControl>
                         <SelectTrigger className={cn(field.value && "pr-8", "bg-white")}>
-                          <div className="flex justify-between w-full">
+                          <div className="flex w-full justify-between">
                             <SelectValue placeholder="최종등급 선택" />
                             {field.value && (
                               <Button
                                 type="button"
                                 variant="ghost"
                                 size="icon"
-                                className="h-4 w-4 -mr-2"
+                                className="-mr-2 h-4 w-4"
                                 onClick={(e) => {
                                   e.stopPropagation();
                                   form.setValue("finalGrade", "");
@@ -907,9 +698,9 @@ export function PeriodicEvaluationFilterSheet({
                         </SelectTrigger>
                       </FormControl>
                       <SelectContent>
-                        {gradeOptions.map(option => (
-                          <SelectItem key={option.value} value={option.value}>
-                            {option.label}
+                        {gradeOptions.map((opt) => (
+                          <SelectItem key={opt.value} value={opt.value}>
+                            {opt.label}
                           </SelectItem>
                         ))}
                       </SelectContent>
@@ -934,8 +725,8 @@ export function PeriodicEvaluationFilterSheet({
                             step="0.1"
                             placeholder="최소"
                             {...field}
-                            className={cn(field.value && "pr-8", "bg-white")}
                             disabled={isInitializing}
+                            className={cn(field.value && "pr-8", "bg-white")}
                           />
                           {field.value && (
                             <Button
@@ -972,8 +763,8 @@ export function PeriodicEvaluationFilterSheet({
                             step="0.1"
                             placeholder="최대"
                             {...field}
-                            className={cn(field.value && "pr-8", "bg-white")}
                             disabled={isInitializing}
+                            className={cn(field.value && "pr-8", "bg-white")}
                           />
                           {field.value && (
                             <Button
@@ -997,18 +788,17 @@ export function PeriodicEvaluationFilterSheet({
                   )}
                 />
               </div>
-
             </div>
           </div>
 
-          {/* Fixed buttons at bottom */}
-          <div className="p-4 shrink-0">
-            <div className="flex gap-2 justify-end">
+          {/* Footer buttons */}
+          <div className="shrink-0 p-4">
+            <div className="flex justify-end gap-2">
               <Button
                 type="button"
                 variant="outline"
                 onClick={handleReset}
-                disabled={isPending || getActiveFilterCount() === 0 || isInitializing}
+                disabled={isPending }
                 className="px-4"
               >
                 초기화
@@ -1016,10 +806,10 @@ export function PeriodicEvaluationFilterSheet({
               <Button
                 type="submit"
                 variant="samsung"
-                disabled={isPending || isLoading || isInitializing}
+                disabled={isPending || isLoading }
                 className="px-4"
               >
-                <Search className="size-4 mr-2" />
+                <Search className="mr-2 size-4" />
                 {isPending || isLoading ? "조회 중..." : "조회"}
               </Button>
             </div>
@@ -1027,5 +817,5 @@ export function PeriodicEvaluationFilterSheet({
         </form>
       </Form>
     </div>
-  )
-}
\ No newline at end of file
+  );
+}
-- 
cgit v1.2.3

