'use client' import { useMemo, useState } from 'react' import { DndContext, DragOverlay, PointerSensor, useSensor, useSensors, useDraggable, useDroppable, type DragEndEvent, type DragStartEvent, } from '@dnd-kit/core' import type { Note } from '@/lib/types' import type { NotebookSchemaPayload, NotePropertyValues } from '@/lib/structured-views/types' import { getNoteDisplayTitle } from '@/lib/note-preview' import { useLanguage } from '@/lib/i18n' import { Plus } from 'lucide-react' import { cn } from '@/lib/utils' type NotesKanbanViewProps = { notes: Note[] schema: NotebookSchemaPayload noteValues: Record onOpen: (note: Note) => void onPropertyChange: (noteId: string, propertyId: string, value: unknown) => void onCreateNote: (prefill: Record) => void onSetGroupProperty: (propertyId: string) => void onQuickAddKanbanStatus?: () => void } function DraggableCard({ note, onOpen, dragDisabled }: { note: Note; onOpen: (note: Note) => void; dragDisabled?: boolean }) { const { t } = useLanguage() const { attributes, listeners, setNodeRef, transform, isDragging } = useDraggable({ id: note.id, disabled: dragDisabled }) const style = transform ? { transform: `translate3d(${transform.x}px, ${transform.y}px, 0)` } : undefined return (
) } function DroppableColumn({ id, children, className, }: { id: string children: React.ReactNode className?: string }) { const { setNodeRef, isOver } = useDroppable({ id }) return (
{children}
) } export function NotesKanbanView({ notes, schema, noteValues, onOpen, onPropertyChange, onCreateNote, onSetGroupProperty, onQuickAddKanbanStatus, }: NotesKanbanViewProps) { const { t } = useLanguage() const [activeId, setActiveId] = useState(null) const selectProps = schema.properties.filter((p) => p.type === 'select') const groupPropId = schema.viewSettings.kanbanGroupPropertyId && selectProps.some((p) => p.id === schema.viewSettings.kanbanGroupPropertyId) ? schema.viewSettings.kanbanGroupPropertyId : selectProps[0]?.id ?? null const groupProp = selectProps.find((p) => p.id === groupPropId) ?? null const columns = useMemo(() => { if (!groupProp) { return [{ id: 'col:__none', label: t('structuredViews.kanbanAllNotes'), value: null as string | null }] } const cols = groupProp.options.map((opt) => ({ id: `col:${opt}`, label: opt, value: opt })) return [...cols, { id: 'col:__none', label: t('structuredViews.kanbanUnassigned'), value: null }] }, [groupProp, t]) const notesByColumn = useMemo(() => { const map = new Map() for (const col of columns) map.set(col.id, []) for (const note of notes) { if (!groupProp) { map.get('col:__none')?.push(note) continue } const raw = noteValues[note.id]?.[groupProp.id] const val = typeof raw === 'string' ? raw : null const colId = val && groupProp.options.includes(val) ? `col:${val}` : 'col:__none' map.get(colId)?.push(note) } return map }, [notes, noteValues, groupProp, columns]) const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 8 } })) const handleDragStart = (e: DragStartEvent) => setActiveId(String(e.active.id)) const handleDragEnd = (e: DragEndEvent) => { setActiveId(null) const noteId = String(e.active.id) const overId = e.over?.id ? String(e.over.id) : null if (!overId || !groupProp || !overId.startsWith('col:')) return const value = overId === 'col:__none' ? null : overId.slice(4) onPropertyChange(noteId, groupProp.id, value) } const activeNote = activeId ? notes.find((n) => n.id === activeId) : null return (
{!groupProp && (

{t('structuredViews.kanbanSingleColumnHint')}

{onQuickAddKanbanStatus && ( )}
)} {groupProp && selectProps.length > 1 && (
{t('structuredViews.kanbanGroupBy')}
)}
{columns.map((col) => { const colNotes = notesByColumn.get(col.id) ?? [] return (
{col.label} {colNotes.length}
{colNotes.map((note) => ( ))} {groupProp && ( )}
) })}
{activeNote ? (
{getNoteDisplayTitle(activeNote, t('notes.untitled'))}
) : null}
) }