brain-routes.tsx2.6 KBView on GitHub
'use client';

import { useEffect } from 'react';
import { useLocation, useNavigate } from 'react-router';

/**
 * The Brain's addresses, in one place.
 *
 * `/brain` itself is the HERO — chat-dominant, so the route renders nothing at rest. A file
 * therefore cannot open "on /brain" any more; it opens in the Knowledge explorer, which is a
 * sub-page and gets the wide context column. Every call site that used to build
 * `/brain?documentId=<id>` by hand now calls `brainDocumentPath`, so the day this address moves
 * again it moves once.
 */
export const BRAIN_KNOWLEDGE_PATH = '/brain/knowledge';

/**
 * Where a standalone document opens full-screen.
 *
 * `ownerUserId` carries an org-admin's resolved teammate through the navigation — the
 * one place a file tree already scoped to that teammate (`PlaybookAopSection`) hands
 * off to a page that opens by bare `documentId` (`CompanyExplorer`) and has no other
 * way to learn whose document it is. Omit it for every self-scoped call site; a
 * present-but-self value is harmless (the server treats a `targetUserId` equal to the
 * caller as the ordinary self path).
 */
export const brainDocumentPath = (documentId: string, ownerUserId?: string): string => {
  const params = new URLSearchParams({ documentId });
  if (ownerUserId) params.set('targetUserId', ownerUserId);
  return `${BRAIN_KNOWLEDGE_PATH}?${params.toString()}`;
};

/**
 * Forwards the RETIRED Brain file addresses — `/brain?documentId=<id>` and `/brain?view=files` —
 * to `/brain/knowledge`.
 *
 * Mounted at the root layout, NOT inside the `/brain` route, and that is the whole point: at rest
 * `/brain` is chat-dominant, so `AppShell` does not render the routed page at all. A redirect
 * living inside that page would never run, and the link would land on the hero with a
 * `?documentId=` in the address bar and no document anywhere on screen.
 *
 * In-app call sites all use `brainDocumentPath` now; this exists for the links already out in the
 * world — bookmarks, agent output, and anything the app wrote to a document before the move.
 */
export function BrainLegacyAddressRedirect() {
  const { pathname, search } = useLocation();
  const navigate = useNavigate();

  useEffect(() => {
    if (pathname !== '/brain') return;
    const params = new URLSearchParams(search);
    if (!params.has('documentId') && params.get('view') !== 'files') return;
    // `replace`, so Back returns to wherever the link was followed FROM rather than bouncing
    // through the address that just forwarded.
    navigate({ pathname: BRAIN_KNOWLEDGE_PATH, search }, { replace: true });
  }, [pathname, search, navigate]);

  return null;
}