"use client"; import { useState, useMemo } from "react"; import { Button } from "@/components/ui/button"; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, } from "@/components/ui/command"; import { Popover, PopoverContent, PopoverTrigger, } from "@/components/ui/popover"; import { CategoryIcon } from "@/components/ui/category-icon"; import { ChevronsUpDown, Check, Wallet, X } from "lucide-react"; import { cn } from "@/lib/utils"; import type { Account, Folder } from "@/lib/types"; interface AccountFilterComboboxProps { accounts: Account[]; folders: Folder[]; value: string[]; // ["all"] | [accountId, accountId, ...] onChange: (value: string[]) => void; className?: string; } export function AccountFilterCombobox({ accounts, folders, value, onChange, className, }: AccountFilterComboboxProps) { const [open, setOpen] = useState(false); // Get root folders (folders without parent) - same as folders/page.tsx const rootFolders = useMemo( () => folders.filter((f) => f.parentId === null), [folders] ); // Get child folders for a given parent - same as FolderTreeItem const getChildFolders = (parentId: string) => folders.filter((f) => f.parentId === parentId); // Get accounts in a specific folder - same as FolderTreeItem const getFolderAccounts = (folderId: string) => accounts.filter((a) => a.folderId === folderId); // Get accounts without folder const orphanAccounts = useMemo( () => accounts.filter((a) => !a.folderId), [accounts] ); const selectedAccounts = accounts.filter((a) => value.includes(a.id)); const isAll = value.includes("all") || value.length === 0; // Get all accounts in a folder and its descendants recursively const getAllAccountsInFolder = (folderId: string): Account[] => { const directAccounts = getFolderAccounts(folderId); const childFoldersList = getChildFolders(folderId); const childAccounts = childFoldersList.flatMap((cf) => getAllAccountsInFolder(cf.id) ); return [...directAccounts, ...childAccounts]; }; const handleSelect = (newValue: string) => { if (newValue === "all") { onChange(["all"]); return; } let newSelection: string[]; if (isAll) { newSelection = [newValue]; } else if (value.includes(newValue)) { newSelection = value.filter((v) => v !== newValue); if (newSelection.length === 0) { newSelection = ["all"]; } } else { newSelection = [...value, newValue]; } onChange(newSelection); }; const handleSelectFolder = (folderId: string) => { const allFolderAccounts = getAllAccountsInFolder(folderId); const allFolderAccountIds = allFolderAccounts.map((a) => a.id); if (allFolderAccountIds.length === 0) return; const allSelected = allFolderAccountIds.every((id) => value.includes(id)); if (allSelected) { const newSelection = value.filter( (v) => !allFolderAccountIds.includes(v) ); onChange(newSelection.length > 0 ? newSelection : ["all"]); } else { if (isAll) { onChange(allFolderAccountIds); } else { const newSelection = [...new Set([...value, ...allFolderAccountIds])]; onChange(newSelection); } } }; const clearSelection = () => { onChange(["all"]); }; const isFolderSelected = (folderId: string) => { const folderAccounts = getAllAccountsInFolder(folderId); if (folderAccounts.length === 0) return false; return folderAccounts.every((a) => value.includes(a.id)); }; const isFolderPartiallySelected = (folderId: string) => { const folderAccounts = getAllAccountsInFolder(folderId); if (folderAccounts.length === 0) return false; const selectedCount = folderAccounts.filter((a) => value.includes(a.id) ).length; return selectedCount > 0 && selectedCount < folderAccounts.length; }; // Recursive render function - mirrors FolderTreeItem logic const renderFolder = (folder: Folder, depth: number, parentPath: string) => { const folderAccounts = getFolderAccounts(folder.id); const childFoldersList = getChildFolders(folder.id); const currentPath = parentPath ? `${parentPath} ${folder.name}` : folder.name; const paddingLeft = depth * 16 + 8; return (