ERP-node/frontend/components/dataflow/connection/ActionConditionRenderer.tsx

259 lines
9.3 KiB
TypeScript

"use client";
import React from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectLabel,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { Trash2 } from "lucide-react";
import { ConditionNode, ColumnInfo } from "@/lib/api/dataflow";
import { DataSaveSettings } from "@/types/connectionTypes";
import { getInputTypeForDataType } from "@/utils/connectionUtils";
import { WebTypeInput } from "../condition/WebTypeInput";
interface ActionConditionRendererProps {
condition: ConditionNode;
condIndex: number;
actionIndex: number;
settings: DataSaveSettings;
onSettingsChange: (settings: DataSaveSettings) => void;
fromTableColumns: ColumnInfo[];
toTableColumns: ColumnInfo[];
fromTableName?: string;
toTableName?: string;
getActionCurrentGroupLevel: (conditions: ConditionNode[], conditionIndex: number) => number;
}
export const ActionConditionRenderer: React.FC<ActionConditionRendererProps> = ({
condition,
condIndex,
actionIndex,
settings,
onSettingsChange,
fromTableColumns,
toTableColumns,
fromTableName,
toTableName,
getActionCurrentGroupLevel,
}) => {
const removeConditionGroup = (groupId: string) => {
const newActions = [...settings.actions];
newActions[actionIndex].conditions = newActions[actionIndex].conditions!.filter((c) => c.groupId !== groupId);
onSettingsChange({ ...settings, actions: newActions });
};
const removeCondition = () => {
const newActions = [...settings.actions];
newActions[actionIndex].conditions = newActions[actionIndex].conditions!.filter((_, i) => i !== condIndex);
onSettingsChange({ ...settings, actions: newActions });
};
const updateCondition = (field: string, value: any) => {
const newActions = [...settings.actions];
(newActions[actionIndex].conditions![condIndex] as any)[field] = value;
onSettingsChange({ ...settings, actions: newActions });
};
const updateLogicalOperator = (targetIndex: number, value: "AND" | "OR") => {
const newActions = [...settings.actions];
newActions[actionIndex].conditions![targetIndex].logicalOperator = value;
onSettingsChange({ ...settings, actions: newActions });
};
const renderConditionValue = () => {
// 선택된 테이블 타입에 따라 컬럼 찾기
const targetColumns = condition.tableType === "from" ? fromTableColumns : toTableColumns;
const selectedColumn = targetColumns.find((col) => col.columnName === condition.field);
if (!selectedColumn) {
// 컬럼이 선택되지 않은 경우 기본 input
return (
<Input
type="text"
placeholder="값"
value={String(condition.value || "")}
onChange={(e) => updateCondition("value", e.target.value)}
className="h-6 flex-1 text-xs"
/>
);
}
// 테이블명 정보를 포함한 컬럼 객체 생성
const tableName = condition.tableType === "from" ? fromTableName : toTableName;
const columnWithTableName = {
...selectedColumn,
tableName: tableName,
};
// WebType 기반 input 사용
return (
<WebTypeInput
column={columnWithTableName}
value={String(condition.value || "")}
onChange={(value) => updateCondition("value", value)}
className="h-6 flex-1 text-xs"
placeholder="값"
/>
);
};
// 그룹 시작 렌더링
if (condition.type === "group-start") {
return (
<div className="flex items-center gap-2">
{/* 그룹 시작 앞의 논리 연산자 */}
{condIndex > 0 && (
<Select
value={settings.actions[actionIndex].conditions![condIndex - 1]?.logicalOperator || "AND"}
onValueChange={(value: "AND" | "OR") => updateLogicalOperator(condIndex - 1, value)}
>
<SelectTrigger className="h-6 w-24 border-green-200 bg-green-50 text-xs">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="AND">AND</SelectItem>
<SelectItem value="OR">OR</SelectItem>
</SelectContent>
</Select>
)}
<div
className="flex items-center gap-2 rounded border-2 border-dashed border-green-300 bg-green-50/50 p-1"
style={{ marginLeft: `${(condition.groupLevel || 0) * 15}px` }}
>
<span className="font-mono text-xs text-green-600">(</span>
<span className="text-xs text-green-600"> </span>
<Button
size="sm"
variant="ghost"
onClick={() => removeConditionGroup(condition.groupId!)}
className="h-4 w-4 p-0"
>
<Trash2 className="h-2 w-2" />
</Button>
</div>
</div>
);
}
// 그룹 끝 렌더링
if (condition.type === "group-end") {
return (
<div className="flex items-center gap-2">
<div
className="flex items-center gap-2 rounded border-2 border-dashed border-green-300 bg-green-50/50 p-1"
style={{ marginLeft: `${(condition.groupLevel || 0) * 15}px` }}
>
<span className="font-mono text-xs text-green-600">)</span>
<span className="text-xs text-green-600"> </span>
<Button
size="sm"
variant="ghost"
onClick={() => removeConditionGroup(condition.groupId!)}
className="h-4 w-4 p-0"
>
<Trash2 className="h-2 w-2" />
</Button>
</div>
</div>
);
}
// 일반 조건 렌더링
return (
<div className="flex items-center gap-2">
{/* 그룹 내 첫 번째 조건이 아닐 때만 논리 연산자 표시 */}
{condIndex > 0 && settings.actions[actionIndex].conditions![condIndex - 1]?.type !== "group-start" && (
<Select
value={settings.actions[actionIndex].conditions![condIndex - 1]?.logicalOperator || "AND"}
onValueChange={(value: "AND" | "OR") => updateLogicalOperator(condIndex - 1, value)}
>
<SelectTrigger className="h-6 w-24 border-green-200 bg-green-50 text-xs">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="AND">AND</SelectItem>
<SelectItem value="OR">OR</SelectItem>
</SelectContent>
</Select>
)}
<div
className="flex flex-1 items-center gap-2 rounded border bg-white p-1"
style={{
marginLeft: `${getActionCurrentGroupLevel(settings.actions[actionIndex].conditions || [], condIndex) * 15}px`,
}}
>
{/* 1단계: 테이블 선택 */}
<Select
value={condition.tableType || ""}
onValueChange={(value: "from" | "to") => {
updateCondition("tableType", value);
// 테이블이 변경되면 필드 초기화
updateCondition("field", "");
}}
>
<SelectTrigger className="h-6 w-20 text-xs">
<SelectValue placeholder="테이블" />
</SelectTrigger>
<SelectContent>
{fromTableColumns.length > 0 && <SelectItem value="from">{fromTableName || "From 테이블"}</SelectItem>}
{toTableColumns.length > 0 && <SelectItem value="to">{toTableName || "To 테이블"}</SelectItem>}
</SelectContent>
</Select>
{/* 2단계: 선택된 테이블의 컬럼 선택 */}
<Select
value={condition.field || ""}
onValueChange={(value) => updateCondition("field", value)}
disabled={!condition.tableType}
>
<SelectTrigger className="h-6 flex-1 text-xs">
<SelectValue placeholder={condition.tableType ? "컬럼" : "테이블을 먼저 선택하세요"} />
</SelectTrigger>
<SelectContent>
{condition.tableType === "from" &&
fromTableColumns.map((column) => (
<SelectItem key={column.columnName} value={column.columnName}>
{column.displayName || column.columnLabel || column.columnName}
</SelectItem>
))}
{condition.tableType === "to" &&
toTableColumns.map((column) => (
<SelectItem key={column.columnName} value={column.columnName}>
{column.displayName || column.columnLabel || column.columnName}
</SelectItem>
))}
</SelectContent>
</Select>
<Select
value={condition.operator || "="}
onValueChange={(value: "=" | "!=" | ">" | "<" | ">=" | "<=" | "LIKE") => updateCondition("operator", value)}
>
<SelectTrigger className="h-6 w-20 text-xs">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="=">=</SelectItem>
<SelectItem value="!=">!=</SelectItem>
<SelectItem value=">">&gt;</SelectItem>
<SelectItem value="<">&lt;</SelectItem>
<SelectItem value=">=">&gt;=</SelectItem>
<SelectItem value="<=">&lt;=</SelectItem>
<SelectItem value="LIKE">LIKE</SelectItem>
</SelectContent>
</Select>
{renderConditionValue()}
<Button size="sm" variant="ghost" onClick={removeCondition} className="h-6 w-6 p-0">
<Trash2 className="h-2 w-2" />
</Button>
</div>
</div>
);
};