"use client"; import { useMemo } from "react"; import { useStore } from "zustand"; import { ArrowDown, ArrowUp, Check, ChevronDown, CircleDot, Columns3, Filter, List, SignalHigh, SlidersHorizontal, } from "lucide-react"; import { Button } from "@/components/ui/button"; import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuCheckboxItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent, } from "@/components/ui/dropdown-menu"; import { Popover, PopoverTrigger, PopoverContent, } from "@/components/ui/popover"; import { Switch } from "@/components/ui/switch"; import { ALL_STATUSES, STATUS_CONFIG, PRIORITY_ORDER, PRIORITY_CONFIG, } from "@/features/issues/config"; import { StatusIcon, PriorityIcon } from "@/features/issues/components"; import { SORT_OPTIONS, CARD_PROPERTY_OPTIONS, } from "@/features/issues/stores/view-store"; import { filterIssues } from "@/features/issues/utils/filter"; import { Tooltip, TooltipTrigger, TooltipContent } from "@/components/ui/tooltip"; import type { Issue } from "@/shared/types"; import { myIssuesViewStore, type MyIssuesScope } from "../stores/my-issues-view-store"; // --------------------------------------------------------------------------- // HoverCheck // --------------------------------------------------------------------------- const FILTER_ITEM_CLASS = "group/fitem pr-1.5! [&>[data-slot=dropdown-menu-checkbox-item-indicator]]:hidden"; function HoverCheck({ checked }: { checked: boolean }) { return (
); } // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- function getActiveFilterCount(state: { statusFilters: string[]; priorityFilters: string[]; }) { let count = 0; if (state.statusFilters.length > 0) count++; if (state.priorityFilters.length > 0) count++; return count; } function useIssueCounts(allIssues: Issue[]) { return useMemo(() => { const status = new Map(); const priority = new Map(); for (const issue of allIssues) { status.set(issue.status, (status.get(issue.status) ?? 0) + 1); priority.set(issue.priority, (priority.get(issue.priority) ?? 0) + 1); } return { status, priority }; }, [allIssues]); } // --------------------------------------------------------------------------- // Scope config // --------------------------------------------------------------------------- const SCOPES: { value: MyIssuesScope; label: string; description: string }[] = [ { value: "assigned", label: "Assigned", description: "Issues assigned to me" }, { value: "created", label: "Created", description: "Issues I created" }, { value: "agents", label: "My Agents", description: "Issues assigned to my agents" }, ]; // --------------------------------------------------------------------------- // MyIssuesHeader // --------------------------------------------------------------------------- export function MyIssuesHeader({ allIssues }: { allIssues: Issue[] }) { const viewMode = useStore(myIssuesViewStore, (s) => s.viewMode); const statusFilters = useStore(myIssuesViewStore, (s) => s.statusFilters); const priorityFilters = useStore(myIssuesViewStore, (s) => s.priorityFilters); const sortBy = useStore(myIssuesViewStore, (s) => s.sortBy); const sortDirection = useStore(myIssuesViewStore, (s) => s.sortDirection); const cardProperties = useStore(myIssuesViewStore, (s) => s.cardProperties); const scope = useStore(myIssuesViewStore, (s) => s.scope); const act = myIssuesViewStore.getState(); const counts = useIssueCounts(allIssues); const hasActiveFilters = getActiveFilterCount({ statusFilters, priorityFilters }) > 0; const sortLabel = SORT_OPTIONS.find((o) => o.value === sortBy)?.label ?? "Manual"; return (
{/* Left: scope buttons */}
{SCOPES.map((s) => ( act.setScope(s.value)} > {s.label} } /> {s.description} ))}
{/* Right: filter + display + view toggle */}
{/* Filter */} {hasActiveFilters && ( )} } /> } /> Filter {/* Status */} Status {statusFilters.length > 0 && ( {statusFilters.length} )} {ALL_STATUSES.map((s) => { const checked = statusFilters.includes(s); const count = counts.status.get(s) ?? 0; return ( act.toggleStatusFilter(s)} className={FILTER_ITEM_CLASS} > {STATUS_CONFIG[s].label} {count > 0 && ( {count} {count === 1 ? "issue" : "issues"} )} ); })} {/* Priority */} Priority {priorityFilters.length > 0 && ( {priorityFilters.length} )} {PRIORITY_ORDER.map((p) => { const checked = priorityFilters.includes(p); const count = counts.priority.get(p) ?? 0; return ( act.togglePriorityFilter(p)} className={FILTER_ITEM_CLASS} > {PRIORITY_CONFIG[p].label} {count > 0 && ( {count} {count === 1 ? "issue" : "issues"} )} ); })} {/* Reset */} {hasActiveFilters && ( <> Reset all filters )} {/* Display settings */} } /> } /> Display settings
Ordering
{sortLabel} } /> {SORT_OPTIONS.map((opt) => ( act.setSortBy(opt.value)} > {opt.label} ))}
Card properties
{CARD_PROPERTY_OPTIONS.map((opt) => ( ))}
{/* View toggle */} {viewMode === "board" ? ( ) : ( )} } /> } /> {viewMode === "board" ? "Board view" : "List view"} View act.setViewMode("board")}> Board act.setViewMode("list")}> List
); }