"use client"; import { useState } from "react"; import { useSortable } from "@dnd-kit/sortable"; import { CSS } from "@dnd-kit/utilities"; import { useTheme } from "next-themes"; import { Archive, GripVertical, MoreVertical, Pencil, StickyNote, Trash2 } from "lucide-react"; import { cn } from "@/lib/utils"; import { Button } from "@/components/ui/button"; import { TodoCheckbox } from "@/components/board/todo-checkbox"; import { MouseFollowTooltip } from "@/components/board/mouse-follow-tooltip"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { getComplementaryColor, getGroupColor } from "@/lib/colors"; import { useBoard } from "@/components/board/board-context"; import { NotesDialog } from "@/components/board/notes-dialog"; import { TodoCreatePopover } from "@/components/board/todo-create-popover"; import { TodoEditDialog } from "@/components/board/todo-edit-dialog"; import { TodoProgressPie } from "@/components/board/todo-progress-pie"; import { EditGroupDialog } from "@/components/board/edit-group-dialog"; import { ConfirmDeleteDialog } from "@/components/confirm-delete-dialog"; import type { GroupDTO, TodoDTO } from "@/types/board"; export function GroupCard({ group }: { group: GroupDTO }) { const { toggleTodoDone, removeGroup, archiveGroup } = useBoard(); const { resolvedTheme } = useTheme(); const [editingTodo, setEditingTodo] = useState(null); const [editOpen, setEditOpen] = useState(false); const [confirmOpen, setConfirmOpen] = useState(false); const { attributes, listeners, setNodeRef, setActivatorNodeRef, transform, transition, isDragging, isOver, } = useSortable({ id: group.id, data: { type: "group", categoryId: group.categoryId }, }); // Another card is being dragged and is currently hovering over this one // -- signal "it'll land near here" with a ring, distinct from this // card's own accent-colored border. (isDragging guards against this // card ever ringing itself while it's the one being moved.) const isDropTarget = isOver && !isDragging; const color = getGroupColor(group.color); const isDark = resolvedTheme === "dark"; const borderColor = isDark ? color.dark : color.light; // A subdued tint of the same stroke color, blended into the theme's own // card surface -- not a fixed pastel, so it automatically stays correct // if the neutral card token ever changes, and needs no separate // light/dark background palette to hand-tune. const backgroundColor = isDark ? `color-mix(in srgb, ${color.dark} 18%, var(--card))` : `color-mix(in srgb, ${color.light} 12%, var(--card))`; // Opposing hue from the group's own color, for the progress pie below -- // so it reads as a distinct accent rather than blending into the border. const pieAccentColor = getComplementaryColor( isDark ? color.dark : color.light, isDark ? "dark" : "light" ); // Only offer archiving once there's actually something done -- a group // with no to-dos yet, or with any still open, isn't "finished" yet. const canArchive = group.todos.length > 0 && group.todos.every((t) => t.completed); const completedCount = group.todos.filter((t) => t.completed).length; return ( <>

{group.title}

} /> setEditOpen(true)}> Edit setConfirmOpen(true)}> Delete group
{canArchive && ( )}
{editingTodo && ( !open && setEditingTodo(null)} /> )} removeGroup(group.id, group.categoryId)} /> ); }