ERP-node/frontend/components/dataflow/node-editor/nodes/ConditionNode.tsx

94 lines
3.5 KiB
TypeScript

"use client";
import { memo } from "react";
import { Handle, Position, NodeProps } from "reactflow";
import { GitBranch } from "lucide-react";
import { CompactNodeShell } from "./CompactNodeShell";
import type { ConditionNodeData } from "@/types/node-editor";
const OPERATOR_LABELS: Record<string, string> = {
EQUALS: "=", NOT_EQUALS: "!=",
GREATER_THAN: ">", LESS_THAN: "<",
GREATER_THAN_OR_EQUAL: ">=", LESS_THAN_OR_EQUAL: "<=",
LIKE: "포함", NOT_LIKE: "미포함",
IN: "IN", NOT_IN: "NOT IN",
IS_NULL: "NULL", IS_NOT_NULL: "NOT NULL",
EXISTS_IN: "EXISTS", NOT_EXISTS_IN: "NOT EXISTS",
};
export const ConditionNode = memo(({ data, selected }: NodeProps<ConditionNodeData>) => {
const condCount = data.conditions?.length || 0;
const summary = condCount > 0
? `${condCount}개 조건 (${data.logic || "AND"})`
: "조건을 설정해 주세요";
return (
<div
className={`rounded-lg border bg-zinc-900 shadow-lg transition-all ${
selected ? "border-violet-500 shadow-violet-500/20" : "border-zinc-700"
}`}
style={{ minWidth: "260px", maxWidth: "320px" }}
>
<Handle
type="target"
position={Position.Left}
className="!h-2.5 !w-2.5 !border-2 !border-amber-500 !bg-zinc-900"
/>
{/* 헤더 */}
<div className="flex items-center gap-2.5 px-3 py-2.5">
<div className="flex h-7 w-7 flex-shrink-0 items-center justify-center rounded-md bg-amber-500/20">
<GitBranch className="h-3.5 w-3.5 text-amber-400" />
</div>
<div className="min-w-0 flex-1">
<div className="text-xs font-semibold text-zinc-200">
{data.displayName || "조건 분기"}
</div>
<div className="line-clamp-2 text-[10px] leading-relaxed text-zinc-500">{summary}</div>
</div>
</div>
{/* 조건 미리보기 */}
{condCount > 0 && (
<div className="space-y-0.5 border-t border-zinc-800 px-3 py-2 text-[10px] text-zinc-400">
{data.conditions!.slice(0, 2).map((c, i) => (
<div key={i} className="flex items-center gap-1 flex-wrap">
{i > 0 && <span className="text-amber-500">{data.logic}</span>}
<span className="font-mono text-zinc-300">{c.field}</span>
<span className="text-amber-400">{OPERATOR_LABELS[c.operator] || c.operator}</span>
{c.value !== undefined && c.value !== null && (
<span className="text-zinc-500">{String(c.value)}</span>
)}
</div>
))}
{condCount > 2 && <span className="text-zinc-600"> {condCount - 2}</span>}
</div>
)}
{/* 분기 출력 */}
<div className="border-t border-zinc-800">
<div className="relative flex items-center justify-end px-3 py-1.5">
<span className="text-[10px] font-medium text-emerald-400"></span>
<Handle
type="source"
position={Position.Right}
id="true"
className="!h-2.5 !w-2.5 !border-2 !border-emerald-500 !bg-zinc-900"
/>
</div>
<div className="relative flex items-center justify-end border-t border-zinc-800/50 px-3 py-1.5">
<span className="text-[10px] font-medium text-pink-400"></span>
<Handle
type="source"
position={Position.Right}
id="false"
className="!h-2.5 !w-2.5 !border-2 !border-pink-500 !bg-zinc-900"
/>
</div>
</div>
</div>
);
});
ConditionNode.displayName = "ConditionNode";