"use client" import { useState, useEffect, useCallback, useRef } from "react" import { useSearchParams, useRouter } from "next/navigation" import { Button } from "@/components/ui/button" import { PanelLeft, PanelLeftClose, PanelLeftOpen } from "lucide-react" // shadcn/ui components import { ResizablePanelGroup, ResizablePanel, ResizableHandle, } from "@/components/ui/resizable" import { cn } from "@/lib/utils" import { ProcurementRfqsView } from "@/db/schema" import { RFQListTable } from "@/lib/procurement-rfqs/table/rfq-table" import { getPORfqs } from "@/lib/procurement-rfqs/services" import { RFQFilterSheet } from "./rfq-filter-sheet" import { DataTableSkeleton } from "@/components/data-table/data-table-skeleton" import { RfqDetailTables } from "./detail-table/rfq-detail-table" interface RfqContainerProps { // 초기 데이터 (필수) initialData: Awaited> // 서버 액션으로 데이터를 가져오는 함수 fetchData: (params: any) => Promise>> } export default function RFQContainer({ initialData, fetchData }: RfqContainerProps) { const router = useRouter() const searchParams = useSearchParams() // Whether the filter panel is open (now a side panel instead of sheet) const [isFilterPanelOpen, setIsFilterPanelOpen] = useState(false) // 데이터 상태 관리 - 초기 데이터로 시작 const [data, setData] = useState>>(initialData) const [isLoading, setIsLoading] = useState(false) // 선택된 문서를 이 state로 관리 const [selectedRfq, setSelectedRfq] = useState(null) // 패널 collapse const [isTopCollapsed, setIsTopCollapsed] = useState(false) // 이전 URL 파라미터를 저장하기 위한 ref const prevParamsRef = useRef(searchParams.toString()) // 현재 URL 파라미터로부터 필터 데이터 구성 const getFilterParams = useCallback(() => { return { page: searchParams.get('page') || '1', perPage: searchParams.get('perPage') || '10', sort: searchParams.get('sort') || JSON.stringify([{ id: "updatedAt", desc: true }]), basicFilters: searchParams.get('basicFilters') || null, basicJoinOperator: searchParams.get('basicJoinOperator') || 'and', filters: searchParams.get('filters') || null, joinOperator: searchParams.get('joinOperator') || 'and', search: searchParams.get('search') || '', } }, [searchParams]) // 데이터 로드 함수 const loadData = useCallback(async () => { try { setIsLoading(true) const filterParams = getFilterParams() console.log("데이터 로드 시작:", filterParams) // 서버 액션으로 데이터 가져오는 함수 const newData = await fetchData(filterParams) console.log("데이터 로드 완료:", newData.data.length, "건") setData(newData) } catch (error) { console.error("데이터 로드 오류:", error) } finally { setIsLoading(false) } }, [fetchData, getFilterParams]) const refreshData = useCallback(() => { // 현재 파라미터로 데이터 다시 로드 loadData(); }, [loadData]); // URL 파라미터 변경 감지 useEffect(() => { const currentParams = searchParams.toString() // 파라미터가 변경되었을 때만 데이터 로드 if (currentParams !== prevParamsRef.current) { console.log("URL 파라미터 변경 감지:", { previous: prevParamsRef.current, current: currentParams, }) prevParamsRef.current = currentParams loadData() } }, [searchParams, loadData]) // 문서 선택 핸들러 const handleSelectRfq = (rfq: ProcurementRfqsView | null) => { setSelectedRfq(rfq) } // 조회 버튼 클릭 핸들러 - RFQFilterSheet에 전달 // 페이지 리라우팅을 통해 처리하므로 별도 로직 불필요 const handleSearch = () => { // Close the panel after search setIsFilterPanelOpen(false) } const [panelHeight, setPanelHeight] = useState(400) // Get active filter count for UI display const getActiveFilterCount = () => { try { const basicFilters = searchParams.get('basicFilters') return basicFilters ? JSON.parse(basicFilters).length : 0 } catch (e) { console.error("Error parsing filters:", e) return 0 } } // Filter panel width in pixels const FILTER_PANEL_WIDTH = 400; // Table refresh key - 패널 상태가 변경되면 테이블을 강제로 재렌더링 const [tableRefreshKey, setTableRefreshKey] = useState(0); useEffect(() => { // 패널 상태가 변경될 때 테이블 강제 재렌더링 setTableRefreshKey(prev => prev + 1); }, [isFilterPanelOpen]); return (
{/* Fixed Filter Panel - 가장 왼쪽부터 시작, 전체 높이 맞춤 */}
{/* Filter Content - 제목 포함하여 내부에서 처리 */}
setIsFilterPanelOpen(false)} onSearch={handleSearch} isLoading={isLoading} />
{/* Main Content Panel - 패널이 열릴 때 오른쪽으로 이동 */}
{/* Filter Toggle Button - 메인 콘텐츠 상단에 위치 */}
{/* 추가적인 헤더 정보나 버튼들을 여기에 배치할 수 있음 */}
{data && !isLoading && ( 총 {data.total || 0}건 )}
{/* Main Content Area */}
{isLoading ? ( // 로딩 중 상태 ) : ( // 데이터 로드 완료 상태 setIsTopCollapsed(true)} onExpand={() => setIsTopCollapsed(false)} onResize={(size) => { setPanelHeight(size) }} className={cn("overflow-y-auto overflow-x-hidden border-b", isTopCollapsed && "transition-all")} >
)}
) }