"use client";
import { useCallback } 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 { useIssueViewStore, type CardProperties } from "@/features/issues/stores/view-store";
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 function BoardCardContent({
issue,
editable = false,
}: {
issue: Issue;
editable?: boolean;
}) {
const storeProperties = useIssueViewStore((s) => s.cardProperties);
const priorityCfg = PRIORITY_CONFIG[issue.priority];
const handleUpdate = useCallback(
(updates: Partial) => {
useIssueStore.getState().updateIssue(issue.id, updates);
api.updateIssue(issue.id, updates).catch(() => {
toast.error("Failed to update issue");
});
},
[issue.id]
);
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 (
{/* Priority */}
{showPriority &&
(editable ? (
{priorityCfg.label}
>
}
/>
) : (
))}
{/* Title */}
{issue.title}
{/* Description */}
{showDescription && (
{issue.description}
)}
{/* Bottom: assignee + due date */}
{showBottom && (
{showAssignee &&
(editable ? (
}
/>
) : (
))}
{showDueDate &&
(editable ? (
{formatDate(issue.due_date!)}
}
/>
) : (
{formatDate(issue.due_date!)}
))}
)}
);
}
export 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 (
);
}