'use client' import { Note } from '@/lib/types' import { NoteCard } from './note-card' import { useState, useMemo, useEffect } from 'react' import { NoteEditor } from './note-editor' import { reorderNotes, getNotes } from '@/app/actions/notes' import { DndContext, DragEndEvent, DragOverlay, DragStartEvent, MouseSensor, TouchSensor, useSensor, useSensors, closestCenter, PointerSensor, } from '@dnd-kit/core' import { SortableContext, rectSortingStrategy, useSortable, arrayMove, } from '@dnd-kit/sortable' import { CSS } from '@dnd-kit/utilities' import { useRouter } from 'next/navigation' interface NoteGridProps { notes: Note[] } function SortableNote({ note, onEdit }: { note: Note; onEdit: (note: Note) => void }) { const { attributes, listeners, setNodeRef, transform, transition, isDragging, } = useSortable({ id: note.id }) const style = { transform: CSS.Transform.toString(transform), transition, opacity: isDragging ? 0.5 : 1, zIndex: isDragging ? 1000 : 1, } return (
) } export function NoteGrid({ notes }: NoteGridProps) { const router = useRouter() const [editingNote, setEditingNote] = useState(null) const [activeId, setActiveId] = useState(null) const [localPinnedNotes, setLocalPinnedNotes] = useState([]) const [localUnpinnedNotes, setLocalUnpinnedNotes] = useState([]) // Sync local state with props useEffect(() => { setLocalPinnedNotes(notes.filter(note => note.isPinned).sort((a, b) => a.order - b.order)) setLocalUnpinnedNotes(notes.filter(note => !note.isPinned).sort((a, b) => a.order - b.order)) }, [notes]) const sensors = useSensors( useSensor(PointerSensor, { activationConstraint: { distance: 8, }, }), useSensor(MouseSensor, { activationConstraint: { distance: 8, }, }), useSensor(TouchSensor, { activationConstraint: { delay: 200, tolerance: 6, }, }) ) const handleDragStart = (event: DragStartEvent) => { console.log('[DND-DEBUG] Drag started:', { activeId: event.active.id, activeData: event.active.data.current }) setActiveId(event.active.id as string) } const handleDragEnd = async (event: DragEndEvent) => { const { active, over } = event console.log('[DND-DEBUG] Drag ended:', { activeId: active.id, overId: over?.id, hasOver: !!over }) setActiveId(null) if (!over || active.id === over.id) { console.log('[DND-DEBUG] Drag cancelled: no valid drop target or same element') return } const activeIdStr = active.id as string const overIdStr = over.id as string // Determine which section the dragged note belongs to const isInPinned = localPinnedNotes.some(n => n.id === activeIdStr) const targetIsInPinned = localPinnedNotes.some(n => n.id === overIdStr) console.log('[DND-DEBUG] Section check:', { activeIdStr, overIdStr, isInPinned, targetIsInPinned, pinnedNotesCount: localPinnedNotes.length, unpinnedNotesCount: localUnpinnedNotes.length }) // Only allow reordering within the same section if (isInPinned !== targetIsInPinned) { console.log('[DND-DEBUG] Drag cancelled: crossing sections (pinned/unpinned)') return } if (isInPinned) { // Reorder pinned notes const oldIndex = localPinnedNotes.findIndex(n => n.id === activeIdStr) const newIndex = localPinnedNotes.findIndex(n => n.id === overIdStr) console.log('[DND-DEBUG] Pinned reorder:', { oldIndex, newIndex }) if (oldIndex !== -1 && newIndex !== -1) { const newOrder = arrayMove(localPinnedNotes, oldIndex, newIndex) setLocalPinnedNotes(newOrder) console.log('[DND-DEBUG] Calling reorderNotes for pinned notes') await reorderNotes(activeIdStr, overIdStr) // Refresh notes from server to sync state console.log('[DND-DEBUG] Refreshing notes from server after reorder') await refreshNotesFromServer() } else { console.log('[DND-DEBUG] Invalid indices for pinned reorder') } } else { // Reorder unpinned notes const oldIndex = localUnpinnedNotes.findIndex(n => n.id === activeIdStr) const newIndex = localUnpinnedNotes.findIndex(n => n.id === overIdStr) console.log('[DND-DEBUG] Unpinned reorder:', { oldIndex, newIndex }) if (oldIndex !== -1 && newIndex !== -1) { const newOrder = arrayMove(localUnpinnedNotes, oldIndex, newIndex) setLocalUnpinnedNotes(newOrder) console.log('[DND-DEBUG] Calling reorderNotes for unpinned notes') await reorderNotes(activeIdStr, overIdStr) // Refresh notes from server to sync state console.log('[DND-DEBUG] Refreshing notes from server after reorder') await refreshNotesFromServer() } else { console.log('[DND-DEBUG] Invalid indices for unpinned reorder') } } } // Function to refresh notes from server without full page reload const refreshNotesFromServer = async () => { console.log('[DND-DEBUG] Fetching fresh notes from server...') const freshNotes = await getNotes() console.log('[DND-DEBUG] Received fresh notes:', freshNotes.length) // Update local state with fresh data const pinned = freshNotes.filter(note => note.isPinned).sort((a, b) => a.order - b.order) const unpinned = freshNotes.filter(note => !note.isPinned).sort((a, b) => a.order - b.order) setLocalPinnedNotes(pinned) setLocalUnpinnedNotes(unpinned) console.log('[DND-DEBUG] Local state updated with fresh server data') } // Find active note from either section const activeNote = activeId ? localPinnedNotes.find(n => n.id === activeId) || localUnpinnedNotes.find(n => n.id === activeId) : null return ( <>
{localPinnedNotes.length > 0 && (

Pinned

n.id)} strategy={rectSortingStrategy}>
{localPinnedNotes.map((note) => ( ))}
)} {localUnpinnedNotes.length > 0 && (
{localPinnedNotes.length > 0 && (

Others

)} n.id)} strategy={rectSortingStrategy}>
{localUnpinnedNotes.map((note) => ( ))}
)} {activeNote ? (
{}} isDragging={true} />
) : null}
{notes.length === 0 && (

No notes yet

Create your first note to get started

)}
{editingNote && ( setEditingNote(null)} /> )} ) }