use-route-inbox.ts2.7 KBView on GitHub
import { useMemo } from 'react';

import { useActiveConnection } from '@/hooks/use-connections';
import { useLabels } from '@/modules/labels/hooks/use-labels';
import { useInboxes, type InboxConfig } from '@/modules/threads/hooks/use-inboxes';
import {
  buildInboxCompiledQuery,
  type InboxCompiledQuery,
} from '@/modules/threads/lib/inbox-compiled-query';
import { resolveRouteInbox, type RouteInboxResolution } from '@/modules/threads/lib/route-inbox';

export type RouteInbox = RouteInboxResolution & {
  /**
   * The Gmail query this route means, or `undefined` when the route is not an inbox route.
   *
   * Built here rather than read off `inbox.compiledQuery`: the system tabs (Inbox / Important
   * / Other) are local stubs with no stored query, so reading the record hands back
   * `undefined` for exactly the three tabs whose meaning is computed.
   */
  compiled: InboxCompiledQuery | undefined;
};

/**
 * The one place a `/mail/:folder` route becomes a query — shared by the email list
 * (`useThreads`) and the unified feed (`mail.tsx` → `InboxList`).
 *
 * Two surfaces asking the same route the same way is the whole point: they resolve the inbox
 * from the URL through `resolveRouteInbox` and compile it through `buildInboxCompiledQuery`,
 * so `All` and `Email` cannot disagree about what tab is open before the server is reached.
 * See apps/mail/docs/inbox-triage.md Phase 0.
 */
export function useRouteInbox(opts: { folder: string; inbox?: InboxConfig }): RouteInbox {
  const { data: activeConnection } = useActiveConnection();
  const { systemLabels } = useLabels();
  const { inboxes, importantSignal } = useInboxes();

  const hasCategoryPersonal = useMemo(
    () => systemLabels.some((label) => label.name.toLowerCase() === 'personal'),
    [systemLabels],
  );

  const resolution = useMemo(
    () => resolveRouteInbox({ inboxes, folder: opts.folder, explicitInbox: opts.inbox }),
    [inboxes, opts.folder, opts.inbox],
  );

  const compiled = useMemo<InboxCompiledQuery | undefined>(() => {
    if (resolution.systemFolderSplit) {
      return {
        compiledQuery: resolution.systemFolderSplit.compiledQuery,
        queryHash: resolution.systemFolderSplit.queryHash,
        inboxName: resolution.systemFolderSplit.inboxName,
      };
    }
    if (!resolution.inbox) return undefined;
    return buildInboxCompiledQuery({
      inbox: resolution.inbox,
      inboxes,
      hasCategoryPersonal,
      connectionEmail: activeConnection?.email,
      sessionName: activeConnection?.name,
      importantSignal,
    });
  }, [
    resolution.systemFolderSplit,
    resolution.inbox,
    inboxes,
    hasCategoryPersonal,
    activeConnection?.email,
    activeConnection?.name,
    importantSignal,
  ]);

  return { ...resolution, compiled };
}