ERP-node/frontend/components/screen/panels/FlowButtonGroupPanel.tsx

175 lines
6.8 KiB
TypeScript

"use client";
import React, { useMemo } from "react";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { Separator } from "@/components/ui/separator";
import { Layers, Trash2, ArrowRight, ArrowDown, Info } from "lucide-react";
import { ComponentData } from "@/types/screen";
import { findAllButtonGroups, getButtonGroupInfo, ButtonGroupInfo } from "@/lib/utils/flowButtonGroupUtils";
interface FlowButtonGroupPanelProps {
components: ComponentData[];
onSelectGroup: (buttonIds: string[]) => void;
onDeleteGroup: (groupId: string) => void;
}
/**
* FlowButtonGroupPanel
*
* 화면의 모든 플로우 버튼 그룹을 관리하는 패널
* - 그룹 목록 표시
* - 그룹 선택 (해당 그룹의 버튼들 선택)
* - 그룹 삭제
*/
export const FlowButtonGroupPanel: React.FC<FlowButtonGroupPanelProps> = ({
components,
onSelectGroup,
onDeleteGroup,
}) => {
// 모든 버튼 그룹 찾기
const buttonGroups = useMemo(() => findAllButtonGroups(components), [components]);
// 그룹 정보 배열
const groupInfos = useMemo(() => {
return Object.entries(buttonGroups)
.map(([groupId, buttons]) => getButtonGroupInfo(groupId, buttons))
.filter((info): info is ButtonGroupInfo => info !== null);
}, [buttonGroups]);
// 그룹이 없을 때
if (groupInfos.length === 0) {
return (
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2 text-base">
<Layers className="h-5 w-5" />
</CardTitle>
<CardDescription className="text-xs"> </CardDescription>
</CardHeader>
<CardContent>
<Alert>
<Info className="h-4 w-4" />
<AlertDescription className="text-xs">
<p className="mb-2"> :</p>
<ol className="ml-4 list-decimal space-y-1 text-[11px]">
<li>2 (Shift + )</li>
<li> "플로우 그룹 생성" </li>
<li> </li>
</ol>
</AlertDescription>
</Alert>
</CardContent>
</Card>
);
}
return (
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2 text-base">
<Layers className="h-5 w-5" />
<Badge variant="secondary" className="ml-auto text-xs">
{groupInfos.length}
</Badge>
</CardTitle>
<CardDescription className="text-xs"> </CardDescription>
</CardHeader>
<CardContent className="space-y-3">
{groupInfos.map((groupInfo, index) => (
<div key={groupInfo.groupId}>
<div className="rounded-lg border border-gray-200 bg-gray-50 p-3 space-y-2">
{/* 그룹 헤더 */}
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<Badge variant="outline" className="text-xs font-mono">
#{index + 1}
</Badge>
<span className="text-xs text-muted-foreground">
{groupInfo.buttonCount}
</span>
</div>
<div className="flex items-center gap-1">
<Button
size="sm"
variant="ghost"
onClick={() => onSelectGroup(groupInfo.buttons.map((b) => b.id))}
className="h-7 px-2 text-xs"
>
</Button>
<Button
size="sm"
variant="ghost"
onClick={() => onDeleteGroup(groupInfo.groupId)}
className="h-7 px-2 text-xs text-red-600 hover:bg-red-50 hover:text-red-700"
>
<Trash2 className="h-3 w-3" />
</Button>
</div>
</div>
{/* 그룹 설정 정보 */}
<div className="flex flex-wrap items-center gap-2 text-[11px]">
<div className="flex items-center gap-1">
{groupInfo.direction === "horizontal" ? (
<ArrowRight className="h-3 w-3 text-blue-600" />
) : (
<ArrowDown className="h-3 w-3 text-blue-600" />
)}
<span className="text-gray-600">
{groupInfo.direction === "horizontal" ? "가로" : "세로"}
</span>
</div>
<span className="text-gray-400"></span>
<span className="text-gray-600"> {groupInfo.gap}px</span>
<span className="text-gray-400"></span>
<span className="text-gray-600">
{groupInfo.align === "start" && "시작점"}
{groupInfo.align === "center" && "중앙"}
{groupInfo.align === "end" && "끝점"}
{groupInfo.align === "space-between" && "양끝"}
{groupInfo.align === "space-around" && "균등배분"}
</span>
</div>
{/* 그룹 ID (디버깅용) */}
<details className="text-[10px]">
<summary className="cursor-pointer text-gray-500 hover:text-gray-700">
ID
</summary>
<code className="mt-1 block rounded bg-gray-200 px-2 py-1 text-[9px]">
{groupInfo.groupId}
</code>
</details>
{/* 버튼 목록 */}
<div className="mt-2 space-y-1">
{groupInfo.buttons.map((button) => (
<div
key={button.id}
className="flex items-center gap-2 rounded bg-white px-2 py-1.5 text-xs"
>
<div className="h-2 w-2 rounded-full bg-blue-500" />
<span className="flex-1 truncate font-medium">
{button.label || button.text || "버튼"}
</span>
<code className="text-[10px] text-gray-400">{button.id.slice(-8)}</code>
</div>
))}
</div>
</div>
{index < groupInfos.length - 1 && <Separator className="my-3" />}
</div>
))}
</CardContent>
</Card>
);
};