diff --git a/frontend/components/Area/AreaModal.tsx b/frontend/components/Area/AreaModal.tsx index 080c824..d5f5ff1 100644 --- a/frontend/components/Area/AreaModal.tsx +++ b/frontend/components/Area/AreaModal.tsx @@ -8,7 +8,7 @@ interface AreaModalProps { isOpen: boolean; onClose: () => void; onSave: (areaData: Partial) => Promise; - onDelete?: (areaId: number) => Promise; + onDelete?: (areaUid: string) => Promise; area?: Area | null; } diff --git a/frontend/components/Areas.tsx b/frontend/components/Areas.tsx index 7e12478..134c362 100644 --- a/frontend/components/Areas.tsx +++ b/frontend/components/Areas.tsx @@ -273,7 +273,7 @@ const Areas: React.FC = () => { isOpen={isAreaModalOpen} onClose={() => setIsAreaModalOpen(false)} onSave={handleSaveArea} - onDelete={async (areaUid) => { + onDelete={async (areaUid: string) => { try { await deleteArea(areaUid); const updatedAreas = await fetchAreas(); diff --git a/frontend/components/Inbox/InboxItemDetail.tsx b/frontend/components/Inbox/InboxItemDetail.tsx index 98e1033..254e400 100644 --- a/frontend/components/Inbox/InboxItemDetail.tsx +++ b/frontend/components/Inbox/InboxItemDetail.tsx @@ -663,8 +663,20 @@ const InboxItemDetail: React.FC = ({ type="button" onClick={(e) => { e.stopPropagation(); - if (onUpdate && item.id !== undefined) { - onUpdate(item.id); + if (onUpdate) { + const identifier = + item.uid ?? + (item.id !== undefined + ? String(item.id) + : null); + + if (identifier) { + onUpdate(identifier); + } else { + console.warn( + 'Inbox item is missing an identifier for update.' + ); + } } setIsDropdownOpen(false); }} diff --git a/frontend/components/Note/NoteDetails.tsx b/frontend/components/Note/NoteDetails.tsx index 0b9b896..5497506 100644 --- a/frontend/components/Note/NoteDetails.tsx +++ b/frontend/components/Note/NoteDetails.tsx @@ -70,14 +70,20 @@ const NoteDetails: React.FC = () => { const handleSaveNote = async (updatedNote: Note) => { try { - if (updatedNote.id !== undefined) { + const noteIdentifier = + updatedNote.uid ?? + (updatedNote.id !== undefined + ? String(updatedNote.id) + : null); + + if (noteIdentifier) { const savedNote = await apiUpdateNote( - updatedNote.id, + noteIdentifier, updatedNote ); setNote(savedNote); } else { - console.error('Error: Note ID is undefined.'); + console.error('Error: Note identifier is undefined.'); } } catch (err) { console.error('Error saving note:', err); diff --git a/frontend/components/Project/ProjectDetails.tsx b/frontend/components/Project/ProjectDetails.tsx index 7c267ed..ffe5229 100644 --- a/frontend/components/Project/ProjectDetails.tsx +++ b/frontend/components/Project/ProjectDetails.tsx @@ -546,10 +546,17 @@ const ProjectDetails: React.FC = () => { setIsNoteModalOpen(true); }; - const handleDeleteNote = async (noteId: number) => { + const handleDeleteNote = async (noteIdentifier: string) => { try { - await apiDeleteNote(noteId); - setNotes(notes.filter((n) => n.id !== noteId)); + await apiDeleteNote(noteIdentifier); + setNotes( + notes.filter((n) => { + const currentIdentifier = + n.uid ?? + (n.id !== undefined ? String(n.id) : undefined); + return currentIdentifier !== noteIdentifier; + }) + ); setNoteToDelete(null); setIsConfirmDialogOpen(false); } catch { @@ -561,8 +568,17 @@ const ProjectDetails: React.FC = () => { const handleSaveNote = async (noteData: Note) => { try { let savedNote: Note; - if (noteData.id) { - savedNote = await updateNote(noteData.id, noteData); + const noteIdentifier = + noteData.uid ?? + (noteData.id !== undefined + ? String(noteData.id) + : null); + + let isUpdate = false; + + if (noteIdentifier) { + savedNote = await updateNote(noteIdentifier, noteData); + isUpdate = true; } else { savedNote = await createNote(noteData); } @@ -575,9 +591,25 @@ const ProjectDetails: React.FC = () => { // If updated note moved to another project, remove it from this list if (savedNote.id && savedNote.project_id !== project?.id) { setNotes(notes.filter((n) => n.id !== savedNote.id)); - } else if (noteData.id) { + } else if (isUpdate) { + const savedIdentifier = + savedNote.uid ?? + (savedNote.id !== undefined + ? String(savedNote.id) + : null); + setNotes( - notes.map((n) => (n.uid === savedNote.uid ? savedNote : n)) + notes.map((n) => { + const currentIdentifier = + n.uid ?? + (n.id !== undefined + ? String(n.id) + : undefined); + + return currentIdentifier === savedIdentifier + ? savedNote + : n; + }) ); } else { setNotes([savedNote, ...notes]); @@ -1217,7 +1249,17 @@ const ProjectDetails: React.FC = () => { handleDeleteNote(noteToDelete.id!)} + onConfirm={() => { + const identifier = + noteToDelete?.uid ?? + (noteToDelete?.id !== undefined + ? String(noteToDelete.id) + : null); + + if (identifier) { + handleDeleteNote(identifier); + } + }} onCancel={() => { setIsConfirmDialogOpen(false); setNoteToDelete(null); diff --git a/frontend/components/Shared/NoteCard.tsx b/frontend/components/Shared/NoteCard.tsx index a3e2780..53415f4 100644 --- a/frontend/components/Shared/NoteCard.tsx +++ b/frontend/components/Shared/NoteCard.tsx @@ -7,19 +7,12 @@ import { EllipsisVerticalIcon, } from '@heroicons/react/24/outline'; import MarkdownRenderer from './MarkdownRenderer'; +import { Note } from '../../entities/Note'; interface NoteCardProps { - note: { - uid: string; - title: string; - content?: string; - tags?: { name: string; uid?: string }[]; - Tags?: { name: string; uid?: string }[]; - project?: { name: string; id?: number; uid?: string }; - Project?: { name: string; id?: number; uid?: string }; - }; - onEdit?: (note: any) => void; - onDelete?: (note: any) => void; + note: Note; + onEdit?: (note: Note) => void; + onDelete?: (note: Note) => void; showActions?: boolean; showProject?: boolean; } @@ -38,6 +31,8 @@ const NoteCard: React.FC = ({ const tags = note.tags || note.Tags || []; const project = note.project || note.Project; + const noteIdentifier = + note.uid ?? (note.id !== undefined ? String(note.id) : 'note'); useEffect(() => { const handleClickOutside = (event: MouseEvent) => { @@ -61,7 +56,7 @@ const NoteCard: React.FC = ({ return (
= ({ className="text-gray-500 hover:text-gray-700 dark:text-gray-300 dark:hover:text-gray-400 focus:outline-none transition-opacity duration-300 p-1" aria-label={t('notes.toggleDropdownMenu')} type="button" - data-testid={`note-dropdown-${note.uid}`} + data-testid={`note-dropdown-${noteIdentifier}`} > @@ -222,7 +217,7 @@ const NoteCard: React.FC = ({ setDropdownOpen(false); }} className="block px-4 py-2 text-sm text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-600 w-full text-left rounded-t-md" - data-testid={`note-edit-${note.uid}`} + data-testid={`note-edit-${noteIdentifier}`} > {t('notes.edit', 'Edit')} @@ -236,7 +231,7 @@ const NoteCard: React.FC = ({ setDropdownOpen(false); }} className="block px-4 py-2 text-sm text-red-500 dark:text-red-300 hover:bg-gray-100 dark:hover:bg-gray-600 w-full text-left rounded-b-md" - data-testid={`note-delete-${note.uid}`} + data-testid={`note-delete-${noteIdentifier}`} > {t('notes.delete', 'Delete')}