rsocials-online/src/components/campaigns/graph/nodes/BaseNode.tsx

108 lines
2.8 KiB
TypeScript

"use client";
import { Handle, Position, type NodeProps } from "@xyflow/react";
import type { CampaignNodeType } from "@/lib/types/campaign";
import { useCampaignStore } from "@/lib/stores/campaign-store";
interface BaseNodeProps {
id: string;
label: string;
type: CampaignNodeType;
icon: React.ReactNode;
color: string;
hasInput?: boolean;
hasOutput?: boolean;
hasTrueOutput?: boolean;
hasFalseOutput?: boolean;
children?: React.ReactNode;
}
export function BaseNode({
id,
label,
icon,
color,
hasInput = true,
hasOutput = true,
hasTrueOutput = false,
hasFalseOutput = false,
children,
}: BaseNodeProps) {
const selectedNodeId = useCampaignStore((s) => s.selectedNodeId);
const isSelected = selectedNodeId === id;
return (
<div
className={`
relative min-w-[180px] rounded-xl border-2 bg-card shadow-lg
transition-all duration-150
${isSelected ? "ring-2 ring-primary/50 scale-[1.02]" : "hover:shadow-xl"}
`}
style={{ borderColor: color }}
>
{hasInput && (
<Handle
type="target"
position={Position.Left}
className="!w-3 !h-3 !border-2 !border-card"
style={{ background: color }}
/>
)}
<div className="px-4 py-3">
<div className="flex items-center gap-2 mb-1">
<div
className="flex items-center justify-center w-7 h-7 rounded-lg"
style={{ backgroundColor: color + "20", color }}
>
{icon}
</div>
<span className="text-sm font-semibold text-foreground">{label}</span>
</div>
{children && (
<div className="text-xs text-muted-foreground mt-1">{children}</div>
)}
</div>
{hasOutput && !hasTrueOutput && (
<Handle
type="source"
position={Position.Right}
className="!w-3 !h-3 !border-2 !border-card"
style={{ background: color }}
/>
)}
{hasTrueOutput && (
<>
<Handle
type="source"
position={Position.Right}
id="true"
className="!w-3 !h-3 !border-2 !border-card"
style={{ background: "#22c55e", top: "35%" }}
/>
<span className="absolute right-5 text-[10px] text-emerald-500 font-medium" style={{ top: "27%" }}>
true
</span>
</>
)}
{hasFalseOutput && (
<>
<Handle
type="source"
position={Position.Right}
id="false"
className="!w-3 !h-3 !border-2 !border-card"
style={{ background: "#ef4444", top: "65%" }}
/>
<span className="absolute right-5 text-[10px] text-red-500 font-medium" style={{ top: "62%" }}>
false
</span>
</>
)}
</div>
);
}