ERP-node/frontend/components/dataflow/condition/ConditionRenderer.tsx

220 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, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Trash2 } from "lucide-react";
import { ConditionNode, ColumnInfo } from "@/lib/api/dataflow";
import { getInputTypeForDataType } from "@/utils/connectionUtils";
import { WebTypeInput } from "./WebTypeInput";
interface ConditionRendererProps {
conditions: ConditionNode[];
fromTableColumns: ColumnInfo[];
fromTableName?: string;
onUpdateCondition: (index: number, field: keyof ConditionNode, value: string) => void;
onRemoveCondition: (index: number) => void;
getCurrentGroupLevel: (index: number) => number;
}
export const ConditionRenderer: React.FC<ConditionRendererProps> = ({
conditions,
fromTableColumns,
fromTableName,
onUpdateCondition,
onRemoveCondition,
getCurrentGroupLevel,
}) => {
const renderConditionValue = (condition: ConditionNode, index: number) => {
const selectedColumn = fromTableColumns.find((col) => col.columnName === condition.field);
if (!selectedColumn) {
// 컬럼이 선택되지 않은 경우 기본 input
return (
<Input
type="text"
placeholder="값"
value={String(condition.value || "")}
onChange={(e) => onUpdateCondition(index, "value", e.target.value)}
className="h-8 flex-1 text-xs"
/>
);
}
// 테이블명 정보를 포함한 컬럼 객체 생성
const columnWithTableName = {
...selectedColumn,
tableName: fromTableName,
};
// WebType 기반 input 사용
return (
<WebTypeInput
column={columnWithTableName}
value={String(condition.value || "")}
onChange={(value) => onUpdateCondition(index, "value", value)}
className="h-8 flex-1 text-xs"
placeholder="값"
/>
);
};
return (
<div className="space-y-2">
{conditions.length === 0 ? (
<div className="rounded-lg border border-dashed p-3 text-center text-xs text-gray-500">
.
<br />
.
</div>
) : (
<React.Fragment key="conditions-list">
{conditions.map((condition, index) => {
// 그룹 시작 렌더링
if (condition.type === "group-start") {
return (
<div key={condition.id} className="flex items-center gap-2">
{/* 그룹 시작 앞의 논리 연산자 - 이전 요소가 group-end가 아닌 경우에만 표시 */}
{index > 0 && conditions[index - 1]?.type !== "group-end" && (
<Select
value={condition.logicalOperator || "AND"}
onValueChange={(value: "AND" | "OR") => onUpdateCondition(index, "logicalOperator", value)}
>
<SelectTrigger className="h-8 w-24 border-primary/20 bg-accent 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-blue-300 bg-accent/50 p-2"
style={{ marginLeft: `${(condition.groupLevel || 0) * 20}px` }}
>
<span className="font-mono text-sm text-primary">(</span>
<span className="text-xs text-primary"> </span>
<Button size="sm" variant="ghost" onClick={() => onRemoveCondition(index)} className="h-6 w-6 p-0">
<Trash2 className="h-3 w-3" />
</Button>
</div>
</div>
);
}
// 그룹 끝 렌더링
if (condition.type === "group-end") {
return (
<div key={condition.id} className="flex items-center gap-2">
<div
className="flex items-center gap-2 rounded border-2 border-dashed border-blue-300 bg-accent/50 p-2"
style={{ marginLeft: `${(condition.groupLevel || 0) * 20}px` }}
>
<span className="font-mono text-sm text-primary">)</span>
<span className="text-xs text-primary"> </span>
<Button size="sm" variant="ghost" onClick={() => onRemoveCondition(index)} className="h-6 w-6 p-0">
<Trash2 className="h-3 w-3" />
</Button>
</div>
{/* 그룹 끝 다음에 다른 조건이나 그룹이 있으면 논리 연산자 표시 */}
{index < conditions.length - 1 && (
<Select
value={conditions[index + 1]?.logicalOperator || "AND"}
onValueChange={(value: "AND" | "OR") => onUpdateCondition(index + 1, "logicalOperator", value)}
>
<SelectTrigger className="h-8 w-24 border-primary/20 bg-accent text-xs">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="AND">AND</SelectItem>
<SelectItem value="OR">OR</SelectItem>
</SelectContent>
</Select>
)}
</div>
);
}
// 일반 조건 렌더링
return (
<div key={condition.id} className="flex items-center gap-2">
{/* 일반 조건 앞의 논리 연산자 - 이전 요소가 group-end가 아닌 경우에만 표시 */}
{index > 0 &&
conditions[index - 1]?.type !== "group-start" &&
conditions[index - 1]?.type !== "group-end" && (
<Select
value={condition.logicalOperator || "AND"}
onValueChange={(value: "AND" | "OR") => onUpdateCondition(index, "logicalOperator", value)}
>
<SelectTrigger className="h-8 w-24 border-primary/20 bg-accent 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-2"
style={{ marginLeft: `${getCurrentGroupLevel(index) * 20}px` }}
>
{/* 조건 필드 선택 */}
<Select
value={condition.field || ""}
onValueChange={(value) => onUpdateCondition(index, "field", value)}
>
<SelectTrigger className="h-8 flex-1 text-xs">
<SelectValue placeholder="필드 선택" />
</SelectTrigger>
<SelectContent>
{fromTableColumns.map((column) => (
<SelectItem key={column.columnName} value={column.columnName}>
{column.displayName || column.columnLabel || column.columnName}
</SelectItem>
))}
</SelectContent>
</Select>
{/* 연산자 선택 */}
<Select
value={condition.operator || "="}
onValueChange={(value) => onUpdateCondition(index, "operator", value)}
>
<SelectTrigger className="h-8 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(condition, index)}
{/* 삭제 버튼 */}
<Button size="sm" variant="ghost" onClick={() => onRemoveCondition(index)} className="h-8 w-8 p-0">
<Trash2 className="h-3 w-3" />
</Button>
</div>
</div>
);
})}
</React.Fragment>
)}
</div>
);
};