mirror of
https://github.com/Luchexx/wacrm.git
synced 2026-11-02 09:19:51 +00:00
92 lines
2.6 KiB
TypeScript
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} />;
|
|
}
|