summaryrefslogtreecommitdiff
path: root/components/vendor-data-plant/project-swicher.tsx
diff options
context:
space:
mode:
authorjoonhoekim <26rote@gmail.com>2025-11-27 17:53:34 +0900
committerjoonhoekim <26rote@gmail.com>2025-11-27 17:53:34 +0900
commit5870b73785715d1585531e655c06d8c068eb64ac (patch)
tree1d19e1482f5210cc56e778158b51e810f9717c46 /components/vendor-data-plant/project-swicher.tsx
parent95984e67b8d57fbe1431fcfedf3bb682f28416b3 (diff)
(김준회) Revert "(대표님) EDP 작업사항"
태그 가져오기 실패 등 에러로 인한 Revert 처리
Diffstat (limited to 'components/vendor-data-plant/project-swicher.tsx')
-rw-r--r--components/vendor-data-plant/project-swicher.tsx163
1 files changed, 104 insertions, 59 deletions
diff --git a/components/vendor-data-plant/project-swicher.tsx b/components/vendor-data-plant/project-swicher.tsx
index 9b8f9bea..d3123709 100644
--- a/components/vendor-data-plant/project-swicher.tsx
+++ b/components/vendor-data-plant/project-swicher.tsx
@@ -1,7 +1,6 @@
"use client"
import * as React from "react"
-import { Check, ChevronsUpDown } from "lucide-react"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import {
@@ -17,103 +16,149 @@ import {
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover"
+import { Check, ChevronsUpDown, Loader2 } from "lucide-react"
-interface PackageData {
- packageCode: string
- packageName: string | null
+interface ContractInfo {
+ contractId: number
+ contractName: string
}
-interface ProjectData {
+interface ProjectInfo {
projectId: number
projectCode: string
projectName: string
- projectType: string
- packages: PackageData[]
+ contracts: ContractInfo[]
}
interface ProjectSwitcherProps {
isCollapsed: boolean
- projects: ProjectData[]
- selectedProjectId: number
- selectedPackageCode: string | null
- onSelectPackage: (projectId: number, packageCode: string) => void
+ projects: ProjectInfo[]
+
+ // 상위가 관리하는 "현재 선택된 contractId"
+ selectedContractId: number | null
+
+ // 콜백: 사용자가 "어떤 contract"를 골랐는지
+ // => 우리가 projectId도 찾아서 상위 state를 같이 갱신해야 함
+ onSelectContract: (projectId: number, contractId: number) => void
+
+ // 로딩 상태 (선택사항)
+ isLoading?: boolean
}
export function ProjectSwitcher({
isCollapsed,
projects,
- selectedProjectId,
- selectedPackageCode,
- onSelectPackage,
+ selectedContractId,
+ onSelectContract,
+ isLoading = false,
}: ProjectSwitcherProps) {
- const [open, setOpen] = React.useState(false)
+ const [popoverOpen, setPopoverOpen] = React.useState(false)
+ const [searchTerm, setSearchTerm] = React.useState("")
- // 현재 선택된 프로젝트와 패키지 정보
- const selectedProject = projects.find(p => p.projectId === selectedProjectId)
- const selectedPackage = selectedProject?.packages.find(
- pkg => pkg.packageCode === selectedPackageCode
- )
+ // 현재 선택된 contract 객체 찾기
+ const selectedContract = React.useMemo(() => {
+ if (!selectedContractId) return null
+ for (const proj of projects) {
+ const found = proj.contracts.find((c) => c.contractId === selectedContractId)
+ if (found) {
+ return { ...found, projectId: proj.projectId, projectName: proj.projectName }
+ }
+ }
+ return null
+ }, [projects, selectedContractId])
+
+ // Trigger label => 계약 이름 or placeholder
+ const triggerLabel = selectedContract?.contractName ?? "Select a contract"
+ // 검색어에 따른 필터링된 프로젝트/계약 목록
+ const filteredProjects = React.useMemo(() => {
+ if (!searchTerm) return projects
+
+ return projects.map(project => ({
+ ...project,
+ contracts: project.contracts.filter(contract =>
+ contract.contractName.toLowerCase().includes(searchTerm.toLowerCase()) ||
+ project.projectName.toLowerCase().includes(searchTerm.toLowerCase())
+ )
+ })).filter(project => project.contracts.length > 0)
+ }, [projects, searchTerm])
- console.log(projects,"projects")
+ // 계약 선택 핸들러
+ function handleSelectContract(projectId: number, contractId: number) {
+ onSelectContract(projectId, contractId)
+ setPopoverOpen(false)
+ setSearchTerm("") // 검색어 초기화
+ }
- const displayText = selectedPackage
- ? `${selectedProject?.projectCode} - ${selectedPackage.packageCode}`
- : selectedProject?.projectCode || "Select Package"
+ // 총 계약 수 계산 (빈 상태 표시용)
+ const totalContracts = filteredProjects.reduce((sum, project) => sum + project.contracts.length, 0)
return (
- <Popover open={open} onOpenChange={setOpen}>
+ <Popover open={popoverOpen} onOpenChange={setPopoverOpen}>
<PopoverTrigger asChild>
<Button
+ type="button"
variant="outline"
- role="combobox"
- aria-expanded={open}
- aria-label="Select a package"
- className={cn("w-full justify-between", isCollapsed && "w-[50px]")}
+ className={cn(
+ "justify-between relative",
+ isCollapsed ? "h-9 w-9 shrink-0 items-center justify-center p-0" : "w-full h-9"
+ )}
+ disabled={isLoading}
+ aria-label="Select Contract"
>
- {isCollapsed ? (
- <ChevronsUpDown className="h-4 w-4" />
+ {isLoading ? (
+ <>
+ <span className={cn(isCollapsed && "hidden")}>Loading...</span>
+ <Loader2 className={cn("h-4 w-4 animate-spin", !isCollapsed && "ml-2")} />
+ </>
) : (
<>
- <span className="truncate">{displayText}</span>
- <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
+ <span className={cn("truncate flex-grow text-left", isCollapsed && "hidden")}>
+ {triggerLabel}
+ </span>
+ <ChevronsUpDown className={cn("h-4 w-4 opacity-50 flex-shrink-0", isCollapsed && "hidden")} />
</>
)}
</Button>
</PopoverTrigger>
- <PopoverContent className="w-[300px] p-0">
+
+ <PopoverContent className="w-[320px] p-0" align="start">
<Command>
- <CommandInput placeholder="Search package..." />
- <CommandList>
- <CommandEmpty>No package found.</CommandEmpty>
- {projects.map((project) => (
- <CommandGroup key={project.projectId} heading={project.projectName}>
- {project.packages.map((pkg) => (
+ <CommandInput
+ placeholder="Search contracts..."
+ value={searchTerm}
+ onValueChange={setSearchTerm}
+ />
+
+ <CommandList
+ className="max-h-[320px]"
+ onWheel={(e) => {
+ e.stopPropagation() // 이벤트 전파 차단
+ const target = e.currentTarget
+ target.scrollTop += e.deltaY // 직접 스크롤 처리
+ }}
+ >
+ <CommandEmpty>
+ {totalContracts === 0 ? "No contracts found." : "No search results."}
+ </CommandEmpty>
+
+ {filteredProjects.map((project) => (
+ <CommandGroup key={project.projectCode} heading={project.projectName}>
+ {project.contracts.map((contract) => (
<CommandItem
- key={`${project.projectId}-${pkg.packageCode}`}
- onSelect={() => {
- onSelectPackage(project.projectId, pkg.packageCode)
- setOpen(false)
- }}
- className="text-sm"
+ key={contract.contractId}
+ onSelect={() => handleSelectContract(project.projectId, contract.contractId)}
+ value={`${project.projectName} ${contract.contractName}`}
+ className="truncate"
+ title={contract.contractName}
>
+ <span className="truncate">{contract.contractName}</span>
<Check
className={cn(
- "mr-2 h-4 w-4",
- selectedProjectId === project.projectId &&
- selectedPackageCode === pkg.packageCode
- ? "opacity-100"
- : "opacity-0"
+ "ml-auto h-4 w-4 flex-shrink-0",
+ selectedContractId === contract.contractId ? "opacity-100" : "opacity-0"
)}
/>
- <div className="flex flex-col">
- <span className="font-medium">{pkg.packageCode}</span>
- {pkg.packageName && (
- <span className="text-xs text-muted-foreground">
- {pkg.packageName}
- </span>
- )}
- </div>
</CommandItem>
))}
</CommandGroup>