"use client"; import { useState } from "react"; import { useRouter } from "next/navigation"; import { api } from "~/trpc/react"; import { toast } from "sonner"; import { X, ArrowLeft } from "lucide-react"; import { Button } from "~/components/ui/button"; import { useBreadcrumbsEffect } from "~/components/ui/breadcrumb-provider"; import { FlowDesigner, type FlowDesign, type FlowStep, type StepType, } from "./FlowDesigner"; interface ExperimentDesignerClientProps { experiment: { id: string; name: string; description: string; studyId: string; study?: { name: string; }; }; } export function ExperimentDesignerClient({ experiment, }: ExperimentDesignerClientProps) { const [saveError, setSaveError] = useState(null); const router = useRouter(); // Set breadcrumbs for the designer useBreadcrumbsEffect([ { label: "Studies", href: "/studies" }, { label: experiment.study?.name ?? "Study", href: `/studies/${experiment.studyId}`, }, { label: "Experiments", href: `/studies/${experiment.studyId}`, }, { label: experiment.name, href: `/experiments/${experiment.id}`, }, { label: "Designer", href: `/experiments/${experiment.id}/designer`, }, ]); // Fetch the experiment's design data const { data: experimentSteps, isLoading } = api.experiments.getSteps.useQuery({ experimentId: experiment.id, }); const saveDesignMutation = api.experiments.saveDesign.useMutation({ onSuccess: () => { setSaveError(null); toast.success("Experiment design saved successfully"); }, onError: (error) => { setSaveError(error.message); toast.error(`Failed to save design: ${error.message}`); }, }); const handleSave = async (design: FlowDesign) => { try { await saveDesignMutation.mutateAsync({ experimentId: experiment.id, steps: design.steps .filter((step) => step.type !== "start" && step.type !== "end") // Filter out start/end nodes .map((step) => ({ id: step.id, type: step.type as "wizard" | "robot" | "parallel" | "conditional", name: step.name, order: Math.floor(step.position.x / 250) + 1, // Calculate order from position parameters: step.parameters, description: step.description, duration: step.duration, actions: step.actions, expanded: false, children: [], parentId: undefined, })), version: design.version, }); } catch (error) { console.error("Failed to save design:", error); throw error; } }; if (isLoading) { return (

Loading experiment designer...

); } // Convert backend steps to flow format const convertToFlowSteps = (steps: any[]): FlowStep[] => { return steps.map((step, index) => ({ id: step.id, type: step.type as StepType, name: step.name, description: step.description ?? undefined, duration: step.duration ?? undefined, actions: [], // Actions will be loaded separately if needed parameters: step.parameters ?? {}, position: { x: index * 250 + 100, y: 100, }, })); }; const initialDesign: FlowDesign = { id: experiment.id, name: experiment.name, description: experiment.description, steps: experimentSteps ? convertToFlowSteps(experimentSteps) : [], version: 1, lastSaved: new Date(), }; return (
{/* Header */}
F

{experiment.name}

{experiment.description || "Visual Flow Designer"}

{experiment.study?.name ?? "Unknown Study"}
{/* Error Display */} {saveError && (

Save Error

{saveError}

)} {/* Flow Designer */}
); }