"use client";
import { useCallback, useMemo, type ReactNode } from "react";
import Link from "next/link";
import { useParams, usePathname } from "next/navigation";
import { useQuery } from "@tanstack/react-query";
import {
ChevronRight,
CircleDot,
FileText,
Folder,
FolderOpen,
FolderPlus,
MoreHorizontal,
PenTool,
Plus,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { ScrollArea } from "@/components/ui/scroll-area";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { getBaseUrl } from "@/lib/trpc";
import {
isSidebarNodeExpanded,
isSidebarSectionExpanded,
useSidebarStore,
} from "@/lib/stores/sidebar-store";
import { useWorkspaceStore } from "@/lib/stores/workspace-store";
import { cn } from "@/lib/utils";
/** Matches server `ObjectTreeNode` shape from objects.getTree */
export type TreeNodeData = {
id: string;
title: string;
type: string;
icon: string | null;
parentId: string | null;
childCount: number;
children: TreeNodeData[];
};
export type PartitionedTrees = {
projects: TreeNodeData[];
documents: TreeNodeData[];
whiteboards: TreeNodeData[];
};
function hasDescendantType(node: TreeNodeData, type: string): boolean {
if (node.type === type) return true;
return node.children.some((c) => hasDescendantType(c, type));
}
export function partitionRoots(roots: TreeNodeData[]): PartitionedTrees {
const projects: TreeNodeData[] = [];
const documents: TreeNodeData[] = [];
const whiteboards: TreeNodeData[] = [];
for (const root of roots) {
if (root.type === "project") {
projects.push(root);
continue;
}
if (root.type === "whiteboard") {
whiteboards.push(root);
continue;
}
if (root.type === "document") {
documents.push(root);
continue;
}
if (root.type === "group") {
const hasWb = hasDescendantType(root, "whiteboard");
const hasDoc = hasDescendantType(root, "document");
if (hasWb && !hasDoc) {
whiteboards.push(root);
} else if (hasDoc) {
documents.push(root);
} else {
projects.push(root);
}
continue;
}
projects.push(root);
}
return { projects, documents, whiteboards };
}
const EMPTY_PARTITIONED: PartitionedTrees = {
projects: [],
documents: [],
whiteboards: [],
};
const MOCK_PARTITIONED: PartitionedTrees = {
projects: [
{
id: "10000000-0000-4000-8000-000000000001",
title: "Project Alpha",
type: "project",
icon: null,
parentId: null,
childCount: 2,
children: [
{
id: "10000000-0000-4000-8000-000000000002",
title: "Sprint 1",
type: "group",
icon: null,
parentId: "10000000-0000-4000-8000-000000000001",
childCount: 2,
children: [
{
id: "10000000-0000-4000-8000-000000000003",
title: "Task 1",
type: "task",
icon: null,
parentId: "10000000-0000-4000-8000-000000000002",
childCount: 0,
children: [],
},
{
id: "10000000-0000-4000-8000-000000000004",
title: "Task 2",
type: "task",
icon: null,
parentId: "10000000-0000-4000-8000-000000000002",
childCount: 0,
children: [],
},
],
},
{
id: "10000000-0000-4000-8000-000000000005",
title: "Sprint 2",
type: "group",
icon: null,
parentId: "10000000-0000-4000-8000-000000000001",
childCount: 0,
children: [],
},
],
},
{
id: "10000000-0000-4000-8000-000000000006",
title: "Project Beta",
type: "project",
icon: null,
parentId: null,
childCount: 0,
children: [],
},
],
documents: [
{
id: "20000000-0000-4000-8000-000000000001",
title: "Documents",
type: "group",
icon: null,
parentId: null,
childCount: 2,
children: [
{
id: "20000000-0000-4000-8000-000000000002",
title: "Meeting Notes",
type: "document",
icon: null,
parentId: "20000000-0000-4000-8000-000000000001",
childCount: 0,
children: [],
},
{
id: "20000000-0000-4000-8000-000000000003",
title: "Product Spec",
type: "document",
icon: null,
parentId: "20000000-0000-4000-8000-000000000001",
childCount: 0,
children: [],
},
],
},
],
whiteboards: [
{
id: "30000000-0000-4000-8000-000000000001",
title: "Whiteboards",
type: "group",
icon: null,
parentId: null,
childCount: 1,
children: [
{
id: "30000000-0000-4000-8000-000000000002",
title: "Brainstorm",
type: "whiteboard",
icon: null,
parentId: "30000000-0000-4000-8000-000000000001",
childCount: 0,
children: [],
},
],
},
],
};
function TypeIcon({ type }: { type: string }) {
switch (type) {
case "project":
return