AkurAI Build
Menu

Public repository / 4f0b1d374fab4075f2b552b5f250bca5f28afee9

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

Latest change 10d19fe0941c186ec244d1f0e2af6b19200dcb0c - OLI-248: pure webmail logic as plain ES modules with JSDoc types; inline icon module by Ólafur Búi Ólafsson

/**
 * @typedef {{ name: string, unread?: number, total?: number }} FolderSummary
 * @typedef {{ name: string, path: string, depth: number, unread: number, total: number, children: FolderNode[] }} FolderNode
 */
/**
 * Turns flat IMAP folder names ("Projects/2026") into a collapsible tree.
 * @param {FolderSummary[]} folders
 * @returns {FolderNode[]}
 */
export function buildFolderTree(folders) {
  /** @type {FolderNode[]} */
  const roots = [];
  /** @type {Map<string, FolderNode>} */
  const byPath = new Map();
  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.
 * @param {FolderNode[]} nodes
 * @param {Record<string, boolean>} expanded
 * @returns {FolderNode[]}
 */
export function visibleFolders(nodes, expanded) {
  const rows = [];
  for (const node of nodes) {
    rows.push(node);
    if (node.children.length && (expanded[node.path] ?? true)) rows.push(...visibleFolders(node.children, expanded));
  }
  return rows;
}