summaryrefslogtreecommitdiff
path: root/lib/evaluation/table/evaluation-filter-sheet.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/evaluation/table/evaluation-filter-sheet.tsx')
-rw-r--r--lib/evaluation/table/evaluation-filter-sheet.tsx616
1 files changed, 203 insertions, 413 deletions
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
+ );
+}