diff options
| author | joonhoekim <26rote@gmail.com> | 2025-12-01 19:52:06 +0900 |
|---|---|---|
| committer | joonhoekim <26rote@gmail.com> | 2025-12-01 19:52:06 +0900 |
| commit | 44b74ff4170090673b6eeacd8c528e0abf47b7aa (patch) | |
| tree | 3f3824b4e2cb24536c1677188b4cae5b8909d3da /lib/b-rfq/summary-table/summary-rfq-filter-sheet.tsx | |
| parent | 4953e770929b82ef77da074f77071ebd0f428529 (diff) | |
(김준회) deprecated code 정리
Diffstat (limited to 'lib/b-rfq/summary-table/summary-rfq-filter-sheet.tsx')
| -rw-r--r-- | lib/b-rfq/summary-table/summary-rfq-filter-sheet.tsx | 617 |
1 files changed, 0 insertions, 617 deletions
diff --git a/lib/b-rfq/summary-table/summary-rfq-filter-sheet.tsx b/lib/b-rfq/summary-table/summary-rfq-filter-sheet.tsx deleted file mode 100644 index ff3bc132..00000000 --- a/lib/b-rfq/summary-table/summary-rfq-filter-sheet.tsx +++ /dev/null @@ -1,617 +0,0 @@ -"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" -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 { cn } from "@/lib/utils" -import { getFiltersStateParser } from "@/lib/parsers" - -// nanoid 생성기 -const generateId = customAlphabet("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 6) - -// RFQ 필터 스키마 정의 -const rfqFilterSchema = z.object({ - rfqCode: z.string().optional(), - projectCode: z.string().optional(), - picName: z.string().optional(), - packageNo: z.string().optional(), - packageName: z.string().optional(), - status: z.string().optional(), -}) - -// RFQ 상태 옵션 정의 -const rfqStatusOptions = [ - { value: "DRAFT", label: "초안" }, - { value: "Doc. Received", label: "문서접수" }, - { value: "PIC Assigned", label: "담당자배정" }, - { value: "Doc. Confirmed", label: "문서확인" }, - { value: "Init. RFQ Sent", label: "초기RFQ발송" }, - { value: "Init. RFQ Answered", label: "초기RFQ회신" }, - { value: "TBE started", label: "TBE시작" }, - { value: "TBE finished", label: "TBE완료" }, - { value: "Final RFQ Sent", label: "최종RFQ발송" }, - { value: "Quotation Received", label: "견적접수" }, - { value: "Vendor Selected", label: "업체선정" }, -] - -type RFQFilterFormValues = z.infer<typeof rfqFilterSchema> - -interface RFQFilterSheetProps { - isOpen: boolean; - onClose: () => void; - onSearch?: () => void; - isLoading?: boolean; -} - -export function RFQFilterSheet({ - isOpen, - onClose, - onSearch, - isLoading = false -}: RFQFilterSheetProps) { - const router = useRouter() - const params = useParams(); - const lng = params ? (params.lng as string) : 'ko'; - - const [isPending, startTransition] = useTransition() - - // 초기화 상태 추가 - 폼 초기화 중에는 상태 변경을 방지 - const [isInitializing, setIsInitializing] = useState(false) - // 마지막으로 적용된 필터를 추적하기 위한 ref - const lastAppliedFilters = useRef<string>("") - - // nuqs로 URL 상태 관리 - const [filters, setFilters] = useQueryState( - "basicFilters", - getFiltersStateParser().withDefault([]) - ) - - // joinOperator 설정 - const [joinOperator, setJoinOperator] = useQueryState( - "basicJoinOperator", - parseAsStringEnum(["and", "or"]).withDefault("and") - ) - - // 현재 URL의 페이지 파라미터도 가져옴 - const [page, setPage] = useQueryState("page", { defaultValue: "1" }) - - // 폼 상태 초기화 - const form = useForm<RFQFilterFormValues>({ - resolver: zodResolver(rfqFilterSchema), - defaultValues: { - rfqCode: "", - projectCode: "", - picName: "", - packageNo: "", - packageName: "", - status: "", - }, - }) - - // 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; - } - }); - - // 폼 값이 변경된 경우에만 reset으로 한 번에 업데이트 - if (formUpdated) { - form.reset(formValues); - lastAppliedFilters.current = currentFiltersString; - } - - setIsInitializing(false); - } - }, [filters, isOpen]) - - // 현재 적용된 필터 카운트 - const getActiveFilterCount = () => { - return filters?.length || 0 - } - - // 폼 제출 핸들러 - async function onSubmit(data: RFQFilterFormValues) { - // 초기화 중이면 제출 방지 - if (isInitializing) return; - - startTransition(async () => { - try { - // 필터 배열 생성 - const newFilters = [] - - if (data.rfqCode?.trim()) { - newFilters.push({ - id: "rfqCode", - value: data.rfqCode.trim(), - type: "text", - operator: "iLike", - rowId: generateId() - }) - } - - if (data.projectCode?.trim()) { - newFilters.push({ - id: "projectCode", - value: data.projectCode.trim(), - type: "text", - operator: "iLike", - rowId: generateId() - }) - } - - if (data.picName?.trim()) { - newFilters.push({ - id: "picName", - value: data.picName.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.packageName?.trim()) { - newFilters.push({ - id: "packageName", - value: data.packageName.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() - }) - } - - // 수동으로 URL 업데이트 (nuqs 대신) - const currentUrl = new URL(window.location.href); - const params = new URLSearchParams(currentUrl.search); - - // 기존 필터 관련 파라미터 제거 - params.delete('basicFilters'); - params.delete('rfqBasicFilters'); - params.delete('basicJoinOperator'); - params.delete('rfqBasicJoinOperator'); - params.delete('page'); - - // 새로운 필터 추가 - if (newFilters.length > 0) { - params.set('basicFilters', JSON.stringify(newFilters)); - params.set('basicJoinOperator', joinOperator); - } - - // 페이지를 1로 설정 - params.set('page', '1'); - - const newUrl = `${currentUrl.pathname}?${params.toString()}`; - console.log("New RFQ Filter URL:", newUrl); - - // 페이지 완전 새로고침으로 서버 렌더링 강제 - window.location.href = newUrl; - - // 마지막 적용된 필터 업데이트 - lastAppliedFilters.current = JSON.stringify(newFilters); - - // 필터 업데이트 후 조회 핸들러 호출 (제공된 경우) - if (onSearch) { - console.log("Calling RFQ onSearch..."); - onSearch(); - } - - console.log("=== RFQ Filter Submit Complete ==="); - } catch (error) { - console.error("RFQ 필터 적용 오류:", error); - } - }) - } - - // 필터 초기화 핸들러 - async function handleReset() { - try { - setIsInitializing(true); - - form.reset({ - rfqCode: "", - projectCode: "", - picName: "", - packageNo: "", - packageName: "", - status: "", - }); - - console.log("=== RFQ Filter Reset Debug ==="); - console.log("Current URL before reset:", window.location.href); - - // 수동으로 URL 초기화 - const currentUrl = new URL(window.location.href); - const params = new URLSearchParams(currentUrl.search); - - // 필터 관련 파라미터 제거 - params.delete('basicFilters'); - params.delete('rfqBasicFilters'); - params.delete('basicJoinOperator'); - params.delete('rfqBasicJoinOperator'); - params.set('page', '1'); - - const newUrl = `${currentUrl.pathname}?${params.toString()}`; - console.log("Reset URL:", newUrl); - - // 페이지 완전 새로고침 - window.location.href = newUrl; - - // 마지막 적용된 필터 초기화 - lastAppliedFilters.current = ""; - - console.log("RFQ 필터 초기화 완료"); - setIsInitializing(false); - } catch (error) { - console.error("RFQ 필터 초기화 오류:", error); - setIsInitializing(false); - } - } - - // Don't render if not open (for side panel use) - 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">RFQ 검색 필터</h3> - <div className="flex items-center gap-2"> - {getActiveFilterCount() > 0 && ( - <Badge variant="secondary" className="px-2 py-1"> - {getActiveFilterCount()}개 필터 적용됨 - </Badge> - )} - </div> - </div> - - {/* Join Operator Selection */} - <div className="px-6 shrink-0"> - <label className="text-sm font-medium">조건 결합 방식</label> - <Select - value={joinOperator} - onValueChange={(value: "and" | "or") => setJoinOperator(value)} - disabled={isInitializing} - > - <SelectTrigger className="h-8 w-[180px] mt-2 bg-white"> - <SelectValue placeholder="조건 결합 방식" /> - </SelectTrigger> - <SelectContent> - <SelectItem value="and">모든 조건 충족 (AND)</SelectItem> - <SelectItem value="or">하나라도 충족 (OR)</SelectItem> - </SelectContent> - </Select> - </div> - - <Form {...form}> - <form onSubmit={form.handleSubmit(onSubmit)} className="flex flex-col h-full min-h-0"> - {/* Scrollable content area */} - <div className="flex-1 min-h-0 overflow-y-auto px-6 pb-4"> - <div className="space-y-4 pt-2"> - - {/* RFQ 코드 */} - <FormField - control={form.control} - name="rfqCode" - render={({ field }) => ( - <FormItem> - <FormLabel>RFQ 코드</FormLabel> - <FormControl> - <div className="relative"> - <Input - placeholder="RFQ 코드 입력" - {...field} - className={cn(field.value && "pr-8", "bg-white")} - disabled={isInitializing} - /> - {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("rfqCode", ""); - }} - disabled={isInitializing} - > - <X className="size-3.5" /> - <span className="sr-only">Clear</span> - </Button> - )} - </div> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - - {/* 프로젝트 코드 */} - <FormField - control={form.control} - name="projectCode" - render={({ field }) => ( - <FormItem> - <FormLabel>프로젝트 코드</FormLabel> - <FormControl> - <div className="relative"> - <Input - placeholder="프로젝트 코드 입력" - {...field} - className={cn(field.value && "pr-8", "bg-white")} - disabled={isInitializing} - /> - {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("projectCode", ""); - }} - disabled={isInitializing} - > - <X className="size-3.5" /> - <span className="sr-only">Clear</span> - </Button> - )} - </div> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - - {/* 담당자명 */} - <FormField - control={form.control} - name="picName" - render={({ field }) => ( - <FormItem> - <FormLabel>담당자명</FormLabel> - <FormControl> - <div className="relative"> - <Input - placeholder="담당자명 입력" - {...field} - className={cn(field.value && "pr-8", "bg-white")} - disabled={isInitializing} - /> - {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("picName", ""); - }} - disabled={isInitializing} - > - <X className="size-3.5" /> - <span className="sr-only">Clear</span> - </Button> - )} - </div> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - - {/* 패키지 번호 */} - <FormField - control={form.control} - name="packageNo" - render={({ field }) => ( - <FormItem> - <FormLabel>패키지 번호</FormLabel> - <FormControl> - <div className="relative"> - <Input - placeholder="패키지 번호 입력" - {...field} - className={cn(field.value && "pr-8", "bg-white")} - disabled={isInitializing} - /> - {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("packageNo", ""); - }} - disabled={isInitializing} - > - <X className="size-3.5" /> - <span className="sr-only">Clear</span> - </Button> - )} - </div> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - - {/* 패키지명 */} - <FormField - control={form.control} - name="packageName" - render={({ field }) => ( - <FormItem> - <FormLabel>패키지명</FormLabel> - <FormControl> - <div className="relative"> - <Input - placeholder="패키지명 입력" - {...field} - className={cn(field.value && "pr-8", "bg-white")} - disabled={isInitializing} - /> - {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("packageName", ""); - }} - disabled={isInitializing} - > - <X className="size-3.5" /> - <span className="sr-only">Clear</span> - </Button> - )} - </div> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - - {/* RFQ 상태 */} - <FormField - control={form.control} - name="status" - render={({ field }) => ( - <FormItem> - <FormLabel>RFQ 상태</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="RFQ 상태 선택" /> - {field.value && ( - <Button - type="button" - variant="ghost" - size="icon" - className="h-4 w-4 -mr-2" - onClick={(e) => { - e.stopPropagation(); - form.setValue("status", ""); - }} - disabled={isInitializing} - > - <X className="size-3" /> - <span className="sr-only">Clear</span> - </Button> - )} - </div> - </SelectTrigger> - </FormControl> - <SelectContent> - {rfqStatusOptions.map(option => ( - <SelectItem key={option.value} value={option.value}> - {option.label} - </SelectItem> - ))} - </SelectContent> - </Select> - <FormMessage /> - </FormItem> - )} - /> - </div> - </div> - - {/* Fixed buttons at bottom */} - <div className="p-4 shrink-0"> - <div className="flex gap-2 justify-end"> - <Button - type="button" - variant="outline" - onClick={handleReset} - disabled={isPending || getActiveFilterCount() === 0 || isInitializing} - className="px-4" - > - 초기화 - </Button> - <Button - type="submit" - variant="samsung" - disabled={isPending || isLoading || isInitializing} - className="px-4" - > - <Search className="size-4 mr-2" /> - {isPending || isLoading ? "조회 중..." : "조회"} - </Button> - </div> - </div> - </form> - </Form> - </div> - ) -}
\ No newline at end of file |
