summaryrefslogblamecommitdiff
path: root/makima/frontend/src/routes/exec-redirect.tsx
blob: d2f863c4e39d8ec9722aa968df0dafa1c979f448 (plain) (tree)


























































                                                                                         
/**
 * ExecRedirect — wraps the standalone task page (`MeshPage`) at `/exec/:id`
 * so that, when the user has document-mode enabled AND the task is attached
 * to a directive, we forward them to `/directives/<dirId>?task=<taskId>`
 * (the doc-mode task surface). For orphan tasks or non-doc-mode users we
 * just render the existing MeshPage.
 *
 * Why a wrapper rather than a redirect at route level: we need the task's
 * `directiveId` field, which only the API returns. We optimistically render
 * a loading shim while the lookup happens, then either replace the URL or
 * mount the legacy page.
 */
import { useEffect, useState } from "react";
import { useNavigate, useParams } from "react-router";
import { getTask, type Task } from "../lib/api";
import { useUserSettings } from "../hooks/useUserSettings";
import MeshPage from "./mesh";

export default function ExecRedirect() {
  const { id } = useParams<{ id: string }>();
  const navigate = useNavigate();
  const { settings, loading: settingsLoading } = useUserSettings();
  const [decided, setDecided] = useState<"redirect" | "stay" | null>(null);

  useEffect(() => {
    if (!id || settingsLoading) return;
    let cancelled = false;
    getTask(id)
      .then((task: Task) => {
        if (cancelled) return;
        const documentMode = settings?.documentModeEnabled ?? false;
        const directiveId = (task as Task & { directiveId?: string | null })
          .directiveId ?? null;
        if (documentMode && directiveId) {
          navigate(`/directives/${directiveId}?task=${id}`, { replace: true });
          return;
        }
        setDecided("stay");
      })
      .catch(() => {
        // If we can't read the task (404, network, etc.), just let the
        // legacy MeshPage handle the error display.
        if (!cancelled) setDecided("stay");
      });
    return () => {
      cancelled = true;
    };
  }, [id, settingsLoading, settings?.documentModeEnabled, navigate]);

  if (decided === null) {
    return (
      <div className="flex-1 flex items-center justify-center min-h-screen bg-[#0a1628]">
        <p className="text-[#7788aa] font-mono text-xs">Loading…</p>
      </div>
    );
  }

  return <MeshPage />;
}