ERP-node/frontend/lib/registry/pop-components/pop-shared/TableCombobox.tsx

117 lines
3.4 KiB
TypeScript

"use client";
import React, { useState, useMemo } from "react";
import { Check, ChevronsUpDown } from "lucide-react";
import { Button } from "@/components/ui/button";
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from "@/components/ui/command";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { cn } from "@/lib/utils";
import type { TableInfo } from "../pop-dashboard/utils/dataFetcher";
interface TableComboboxProps {
tables: TableInfo[];
value: string;
onSelect: (tableName: string) => void;
placeholder?: string;
}
export function TableCombobox({
tables,
value,
onSelect,
placeholder = "테이블을 선택하세요",
}: TableComboboxProps) {
const [open, setOpen] = useState(false);
const [search, setSearch] = useState("");
const selectedLabel = useMemo(() => {
const found = tables.find((t) => t.tableName === value);
return found ? (found.displayName || found.tableName) : "";
}, [tables, value]);
const filtered = useMemo(() => {
if (!search) return tables;
const q = search.toLowerCase();
return tables.filter(
(t) =>
t.tableName.toLowerCase().includes(q) ||
(t.displayName && t.displayName.toLowerCase().includes(q))
);
}, [tables, search]);
return (
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
variant="outline"
role="combobox"
aria-expanded={open}
className="mt-1 h-8 w-full justify-between text-xs"
>
{value ? selectedLabel : placeholder}
<ChevronsUpDown className="ml-2 h-3.5 w-3.5 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent
className="p-0"
style={{ width: "var(--radix-popover-trigger-width)" }}
align="start"
>
<Command shouldFilter={false}>
<CommandInput
placeholder="테이블명 또는 한글명 검색..."
className="text-xs"
value={search}
onValueChange={setSearch}
/>
<CommandList>
<CommandEmpty className="py-4 text-center text-xs">
.
</CommandEmpty>
<CommandGroup>
{filtered.map((table) => (
<CommandItem
key={table.tableName}
value={table.tableName}
onSelect={() => {
onSelect(table.tableName);
setOpen(false);
setSearch("");
}}
className="text-xs"
>
<Check
className={cn(
"mr-2 h-3.5 w-3.5",
value === table.tableName ? "opacity-100" : "opacity-0"
)}
/>
<div className="flex flex-col">
<span>{table.displayName || table.tableName}</span>
{table.displayName && (
<span className="text-[10px] text-muted-foreground">
{table.tableName}
</span>
)}
</div>
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
);
}