AkurAI Build
Menu

Public repository / 0d7f5f902b20084326479f36d4ccf2b55ee890c0

AkurAI-Mail / src/lib/webmail/folders.ts

Latest change 22202d1bde69be4ace8a299dffd91f8ff24378df - Recover deployed webmail frontend (frontend parity with EC2 a6afffc) by Ólafur Búi Ólafsson

/** Turns flat IMAP folder names ("Projects/2026") into a collapsible tree. */

export interface FolderSummary {
  name: string;
  unread?: number;
  total?: number;
}

export interface FolderNode {
  name: string;
  path: string;
  depth: number;
  unread: number;
  total: number;
  children: FolderNode[];
}

export function buildFolderTree(folders: FolderSummary[]): FolderNode[] {
  const roots: FolderNode[] = [];
  const byPath = new Map<string, FolderNode>();
  for (const folder of folders) {
    const segments = String(folder.name).split("/");
    let path = "";
    let siblings = roots;
    segments.forEach((segment, depth) => {
      path = path ? `${path}/${segment}` : segment;
      let node = byPath.get(path);
      if (!node) {
        node = { name: segment, path, depth, unread: 0, total: 0, children: [] };
        byPath.set(path, node);
        siblings.push(node);
      }
      if (depth === segments.length - 1) {
        node.unread = folder.unread ?? 0;
        node.total = folder.total ?? 0;
      }
      siblings = node.children;
    });
  }
  return roots;
}

/** Depth-first list of visible nodes; folders are expanded unless `expanded[path]` is false. */
export function visibleFolders(nodes: FolderNode[], expanded: Record<string, boolean>): FolderNode[] {
  const rows: FolderNode[] = [];
  for (const node of nodes) {
    rows.push(node);
    if (node.children.length && (expanded[node.path] ?? true)) rows.push(...visibleFolders(node.children, expanded));
  }
  return rows;
}