"use client"; import { useCallback, memo } from "react"; import Link from "next/link"; import { useSortable } from "@dnd-kit/sortable"; import { CSS } from "@dnd-kit/utilities"; import { toast } from "sonner"; import type { Issue, UpdateIssueRequest } from "@/shared/types"; import { CalendarDays } from "lucide-react"; import { ActorAvatar } from "@/components/common/actor-avatar"; import { api } from "@/shared/api"; import { useIssueStore } from "@/features/issues/store"; import { PriorityIcon } from "./priority-icon"; import { PriorityPicker, AssigneePicker, DueDatePicker } from "./pickers"; import { PRIORITY_CONFIG } from "@/features/issues/config"; import type { CardProperties } from "@/features/issues/stores/view-store"; import { useViewStore } from "@/features/issues/stores/view-store-context"; function formatDate(date: string): string { return new Date(date).toLocaleDateString("en-US", { month: "short", day: "numeric", }); } /** Stops event from bubbling to Link/drag handlers */ function PickerWrapper({ children }: { children: React.ReactNode }) { const stop = (e: React.SyntheticEvent) => { e.stopPropagation(); e.preventDefault(); }; return (
{children}
); } export const BoardCardContent = memo(function BoardCardContent({ issue, editable = false, }: { issue: Issue; editable?: boolean; }) { const storeProperties = useViewStore((s) => s.cardProperties); const priorityCfg = PRIORITY_CONFIG[issue.priority]; const handleUpdate = useCallback( (updates: Partial) => { const prev = { ...issue }; useIssueStore.getState().updateIssue(issue.id, updates); api.updateIssue(issue.id, updates).catch(() => { useIssueStore.getState().updateIssue(issue.id, prev); toast.error("Failed to update issue"); }); }, [issue], ); const showPriority = storeProperties.priority; const showDescription = storeProperties.description && issue.description; const showAssignee = storeProperties.assignee && issue.assignee_type && issue.assignee_id; const showDueDate = storeProperties.dueDate && issue.due_date; const showBottom = showAssignee || showDueDate; return (
{/* Row 1: Identifier */}

{issue.identifier}

{/* Row 2: Title */}

{issue.title}

{/* Description */} {showDescription && (

{issue.description}

)} {/* Row 3: Assignee, priority badge, due date */} {(showAssignee || showPriority || showDueDate) && (
{showAssignee && (editable ? ( } /> ) : ( ))} {showPriority && (editable ? ( {priorityCfg.label} } /> ) : ( {priorityCfg.label} ))} {showDueDate && (
{editable ? ( {formatDate(issue.due_date!)} } /> ) : ( {formatDate(issue.due_date!)} )}
)}
)}
); }); export const DraggableBoardCard = memo(function DraggableBoardCard({ issue }: { issue: Issue }) { const { attributes, listeners, setNodeRef, transform, transition, isDragging, } = useSortable({ id: issue.id, data: { status: issue.status }, }); const style = { transform: CSS.Transform.toString(transform), transition, }; return (
); });