Files
sam-react-prod/src/components/molecules/TableActions.tsx
byeongcheolryu 3be5714805 refactor: 품목관리 시스템 리팩토링 및 Sales 페이지 추가
DynamicItemForm 개선:
- 품목코드 자동생성 기능 추가
- 조건부 표시 로직 개선
- 불필요한 컴포넌트 정리 (DynamicField, DynamicSection 등)
- 타입 시스템 단순화

새로운 기능:
- Sales 페이지 마이그레이션 (견적관리, 거래처관리)
- 공통 컴포넌트 추가 (atoms, molecules, organisms, templates)

문서화:
- 구현 문서 및 참조 문서 추가

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 12:48:41 +09:00

89 lines
2.6 KiB
TypeScript

"use client";
import { Button } from "@/components/ui/button";
import { LucideIcon, Eye, Edit, Trash2, Copy, Download, MoreHorizontal } from "lucide-react";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
export interface TableAction {
type: "view" | "edit" | "delete" | "copy" | "download" | "custom";
label?: string;
icon?: LucideIcon;
onClick: () => void;
variant?: "default" | "ghost" | "outline" | "destructive";
hidden?: boolean;
}
interface TableActionsProps {
actions: TableAction[];
layout?: "buttons" | "dropdown" | "auto";
}
const defaultIcons: Record<string, LucideIcon> = {
view: Eye,
edit: Edit,
delete: Trash2,
copy: Copy,
download: Download
};
export const TableActions = ({ actions, layout = "auto" }: TableActionsProps) => {
const visibleActions = actions.filter(a => !a.hidden);
// 자동 레이아웃: 3개 이하는 버튼, 4개 이상은 드롭다운
const useDropdown = layout === "dropdown" || (layout === "auto" && visibleActions.length > 3);
if (visibleActions.length === 0) return null;
// 드롭다운 레이아웃
if (useDropdown) {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="sm">
<MoreHorizontal className="w-4 h-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
{visibleActions.map((action, index) => {
const Icon = action.icon || (action.type !== "custom" ? defaultIcons[action.type] : null);
return (
<DropdownMenuItem
key={index}
onClick={action.onClick}
className={action.variant === "destructive" ? "text-destructive" : ""}
>
{Icon && <Icon className="w-4 h-4 mr-2" />}
{action.label || action.type.charAt(0).toUpperCase() + action.type.slice(1)}
</DropdownMenuItem>
);
})}
</DropdownMenuContent>
</DropdownMenu>
);
}
// 버튼 레이아웃
return (
<div className="flex gap-1">
{visibleActions.map((action, index) => {
const Icon = action.icon || (action.type !== "custom" ? defaultIcons[action.type] : null);
return (
<Button
key={index}
variant={action.variant || "ghost"}
size="sm"
onClick={action.onClick}
title={action.label || action.type}
>
{Icon && <Icon className="w-4 h-4" />}
</Button>
);
})}
</div>
);
};