wacrm/src/app/(dashboard)/flows/[id]/page.tsx

92 lines
2.6 KiB
TypeScript

"use client";
import { useEffect, useState } from "react";
import { useParams, useRouter } from "next/navigation";
import { Loader2 } from "lucide-react";
import { toast } from "sonner";
import { useTranslations } from "next-intl";
import { FlowEditorShell } from "@/components/flows/flow-editor-shell";
import type { FlowRow, FlowNodeRow } from "@/lib/flows/types";
/**
* Flow editor shell.
*
* Loads `{flow, nodes}` from `/api/flows/[id]` and hands it to
* `<FlowBuilder>`. Owns the loading/error state so the builder can
* focus purely on editing.
*
* Open to every authenticated user — the beta gate that previously
* 404'd non-beta accounts was removed in PR #134. The API still
* 404s on a flow id the caller doesn't own (RLS), which becomes the
* "Flow not found" state below.
*/
export default function FlowEditorPage() {
const router = useRouter();
const params = useParams<{ id: string }>();
const t = useTranslations("Flows.edit");
const [flow, setFlow] = useState<FlowRow | null>(null);
const [nodes, setNodes] = useState<FlowNodeRow[]>([]);
const [loading, setLoading] = useState(true);
const [notFound, setNotFound] = useState(false);
useEffect(() => {
if (!params.id) return;
let cancelled = false;
(async () => {
try {
const res = await fetch(`/api/flows/${params.id}`);
if (res.status === 404) {
if (!cancelled) setNotFound(true);
return;
}
if (!res.ok) throw new Error(`Failed: ${res.status}`);
const json = (await res.json()) as {
flow: FlowRow;
nodes: FlowNodeRow[];
};
if (!cancelled) {
setFlow(json.flow);
setNodes(json.nodes ?? []);
}
} catch (err) {
if (!cancelled) {
console.error(err);
toast.error(t("loadError"));
}
} finally {
if (!cancelled) setLoading(false);
}
})();
return () => {
cancelled = true;
};
}, [params.id]);
if (loading) {
return (
<div className="flex h-full items-center justify-center">
<Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
</div>
);
}
if (notFound || !flow) {
return (
<div className="flex h-full flex-col items-center justify-center gap-3">
<p className="text-sm text-muted-foreground">{t("notFound")}</p>
<button
type="button"
onClick={() => router.push("/flows")}
className="text-sm text-primary hover:opacity-80"
>
{t("backToFlows")}
</button>
</div>
);
}
return <FlowEditorShell initialFlow={flow} initialNodes={nodes} />;
}