From 20800b214145ee6056f94ca18fa1054f145eb977 Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
Date: Wed, 28 May 2025 00:32:31 +0000
Subject: (대표님) lib 파트 커밋
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 lib/pq/pq-review-table-new/pq-container.tsx | 151 ++++++++++++++++++++++++++++
 1 file changed, 151 insertions(+)
 create mode 100644 lib/pq/pq-review-table-new/pq-container.tsx

(limited to 'lib/pq/pq-review-table-new/pq-container.tsx')

diff --git a/lib/pq/pq-review-table-new/pq-container.tsx b/lib/pq/pq-review-table-new/pq-container.tsx
new file mode 100644
index 00000000..ebe46809
--- /dev/null
+++ b/lib/pq/pq-review-table-new/pq-container.tsx
@@ -0,0 +1,151 @@
+"use client"
+
+import { useState, useEffect, useCallback, useRef } from "react"
+import { useSearchParams } from "next/navigation"
+import { Button } from "@/components/ui/button"
+import { PanelLeftClose, PanelLeftOpen } from "lucide-react"
+
+import { cn } from "@/lib/utils"
+import { getPQSubmissions } from "../service"
+import { PQSubmissionsTable } from "./vendors-table"
+import { PQFilterSheet } from "./pq-filter-sheet"
+
+interface PQContainerProps {
+  // Promise.all로 감싼 promises를 받음
+  promises: Promise<[Awaited<ReturnType<typeof getPQSubmissions>>]>
+  // 컨테이너 클래스명 (옵션)
+  className?: string
+}
+
+export default function PQContainer({
+  promises,
+  className
+}: PQContainerProps) {
+  const searchParams = useSearchParams()
+
+  // Whether the filter panel is open
+  const [isFilterPanelOpen, setIsFilterPanelOpen] = useState(false)
+
+  // Container wrapper의 위치를 측정하기 위한 ref
+  const containerRef = useRef<HTMLDivElement>(null)
+  const [containerTop, setContainerTop] = useState(0)
+
+  // Container 위치 측정 함수 - top만 측정
+  const updateContainerBounds = useCallback(() => {
+    if (containerRef.current) {
+      const rect = containerRef.current.getBoundingClientRect()
+      setContainerTop(rect.top)
+    }
+  }, [])
+
+  // 컴포넌트 마운트 시와 윈도우 리사이즈 시 위치 업데이트
+  useEffect(() => {
+    updateContainerBounds()
+    
+    const handleResize = () => {
+      updateContainerBounds()
+    }
+    
+    window.addEventListener('resize', handleResize)
+    window.addEventListener('scroll', updateContainerBounds)
+    
+    return () => {
+      window.removeEventListener('resize', handleResize)
+      window.removeEventListener('scroll', updateContainerBounds)
+    }
+  }, [updateContainerBounds])
+
+  // 조회 버튼 클릭 핸들러 - PQFilterSheet에 전달
+  const handleSearch = () => {
+    // Close the panel after search
+    setIsFilterPanelOpen(false)
+  }
+
+  // Get active filter count for UI display (서버 사이드 필터만 계산)
+  const getActiveFilterCount = () => {
+    try {
+      // 새로운 이름 우선, 기존 이름도 지원
+      const basicFilters = searchParams.get('basicFilters') || searchParams.get('pqBasicFilters')
+      return basicFilters ? JSON.parse(basicFilters).length : 0
+    } catch (e) {
+      return 0
+    }
+  }
+
+  // Filter panel width
+  const FILTER_PANEL_WIDTH = 400;
+
+  return (
+    <>
+      {/* Filter Panel - fixed positioning으로 화면 최대 좌측에서 시작 */}
+      <div 
+        className={cn(
+          "fixed left-0 bg-background border-r z-50 flex flex-col transition-all duration-300 ease-in-out overflow-hidden",
+          isFilterPanelOpen ? "border-r shadow-lg" : "border-r-0"
+        )}
+        style={{ 
+          width: isFilterPanelOpen ? `${FILTER_PANEL_WIDTH}px` : '0px',
+          top: `${containerTop}px`,
+          height: `calc(100vh - ${containerTop}px)`
+        }}
+      >
+        {/* Filter Content */}
+        <div className="h-full">
+          <PQFilterSheet 
+            isOpen={isFilterPanelOpen} 
+            onClose={() => setIsFilterPanelOpen(false)}
+            onSearch={handleSearch}
+            isLoading={false} // 로딩 상태 제거
+          />
+        </div>
+      </div>
+
+      {/* Main Content Container */}
+      <div 
+        ref={containerRef}
+        className={cn("relative w-full overflow-hidden", className)}
+      >
+        <div className="flex w-full h-full">
+          {/* Main Content - 너비 조정으로 필터 패널 공간 확보 */}
+          <div 
+            className="flex flex-col min-w-0 overflow-hidden transition-all duration-300 ease-in-out"
+            style={{
+              width: isFilterPanelOpen ? `calc(100% - ${FILTER_PANEL_WIDTH}px)` : '100%',
+              marginLeft: isFilterPanelOpen ? `${FILTER_PANEL_WIDTH}px` : '0px'
+            }}
+          >
+            {/* Header Bar */}
+            <div className="flex items-center justify-between p-4 bg-background shrink-0">
+              <div className="flex items-center gap-3">
+                <Button 
+                  variant="outline" 
+                  size="sm" 
+                  type='button'
+                  onClick={() => setIsFilterPanelOpen(!isFilterPanelOpen)}
+                  className="flex items-center shadow-sm"
+                >
+                  {
+                    isFilterPanelOpen ? <PanelLeftClose className="size-4"/> : <PanelLeftOpen className="size-4"/>
+                  }
+                  {getActiveFilterCount() > 0 && (
+                    <span className="ml-2 bg-primary text-primary-foreground rounded-full px-2 py-0.5 text-xs">
+                      {getActiveFilterCount()}
+                    </span>
+                  )}
+                </Button>
+              </div>
+            </div>
+
+            {/* Table Content Area */}
+            <div className="flex-1 overflow-hidden" style={{ height: 'calc(100vh - 380px)' }}>
+              <div className="h-full w-full">
+                {/* Promise를 직접 전달 - Items와 동일한 패턴 */}
+                <PQSubmissionsTable promises={promises} />
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </>
+  )
+}
\ No newline at end of file
-- 
cgit v1.2.3

