import React, { useState, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { MagnifyingGlassIcon } from '@heroicons/react/24/solid'; import SortFilterButton, { SortOption } from './Shared/SortFilterButton'; import NoteModal from './Note/NoteModal'; import ConfirmDialog from './Shared/ConfirmDialog'; import NoteCard from './Shared/NoteCard'; import { Note } from '../entities/Note'; import { createNote, updateNote, deleteNote as apiDeleteNote, } from '../utils/notesService'; import { useStore } from '../store/useStore'; import { createProject, fetchProjects } from '../utils/projectsService'; const Notes: React.FC = () => { const { t } = useTranslation(); const [selectedNote, setSelectedNote] = useState(null); const [isNoteModalOpen, setIsNoteModalOpen] = useState(false); const [isConfirmDialogOpen, setIsConfirmDialogOpen] = useState(false); const [noteToDelete, setNoteToDelete] = useState(null); const [searchQuery, setSearchQuery] = useState(''); const [isSearchExpanded, setIsSearchExpanded] = useState(false); const [orderBy, setOrderBy] = useState('created_at:desc'); // Get notes and projects from global store const { notes, isLoading, isError, hasLoaded, loadNotes, setNotes } = useStore((state) => state.notesStore); const projects = useStore((state) => state.projectsStore.projects); const { setProjects } = useStore((state) => state.projectsStore); useEffect(() => { if (!hasLoaded && !isLoading && !isError) { loadNotes(); } }, [hasLoaded, isLoading, isError, loadNotes]); // Load projects if not available - force load every time for debugging useEffect(() => { const loadProjectsIfNeeded = async () => { try { // Fetch all projects (active and inactive) const fetchedProjects = await fetchProjects('all', ''); setProjects(fetchedProjects); } catch (error) { console.error('Error loading projects:', error); } }; loadProjectsIfNeeded(); }, []); // Remove dependencies to force it to run once // Sort options for notes const sortOptions: SortOption[] = [ { value: 'created_at:desc', label: t('sort.created_at', 'Created At') }, { value: 'title:asc', label: t('sort.name', 'Title') }, { value: 'updated_at:desc', label: t('common.updated', 'Updated') }, ]; // Handle sort change const handleSortChange = (newOrderBy: string) => { setOrderBy(newOrderBy); }; const handleDeleteNote = async () => { if (!noteToDelete) return; try { await apiDeleteNote(noteToDelete.id!); const updatedNotes = notes.filter( (note) => note.id !== noteToDelete.id ); setNotes(updatedNotes); setIsConfirmDialogOpen(false); setNoteToDelete(null); } catch (err) { console.error('Error deleting note:', err); } }; const handleEditNote = (note: Note) => { setSelectedNote(note); setIsNoteModalOpen(true); }; const handleSaveNote = async (noteData: Note) => { try { if (noteData.id) { const savedNote = await updateNote(noteData.id, noteData); const updatedNotes = notes.map((note) => note.id === noteData.id ? savedNote : note ); setNotes(updatedNotes); } else { const newNote = await createNote(noteData); setNotes([newNote, ...notes]); } setIsNoteModalOpen(false); setSelectedNote(null); } catch (err) { console.error('Error saving note:', err); } }; const handleCreateProject = async (name: string) => { try { const newProject = await createProject({ name, priority: 'low', }); return newProject; } catch (error) { console.error('Error creating project:', error); throw error; } }; const filteredNotes = notes.filter( (note) => note.title.toLowerCase().includes(searchQuery.toLowerCase()) || note.content.toLowerCase().includes(searchQuery.toLowerCase()) ); // Sort the filtered notes const sortedNotes = [...filteredNotes].sort((a, b) => { const [field, direction] = orderBy.split(':'); const isAsc = direction === 'asc'; let valueA, valueB; switch (field) { case 'title': valueA = a.title?.toLowerCase() || ''; valueB = b.title?.toLowerCase() || ''; break; case 'updated_at': valueA = a.updated_at ? new Date(a.updated_at).getTime() : 0; valueB = b.updated_at ? new Date(b.updated_at).getTime() : 0; break; case 'created_at': default: valueA = a.created_at ? new Date(a.created_at).getTime() : 0; valueB = b.created_at ? new Date(b.created_at).getTime() : 0; break; } if (valueA < valueB) return isAsc ? -1 : 1; if (valueA > valueB) return isAsc ? 1 : -1; return 0; }); if (isLoading) { return (
{t('notes.loading')}
); } if (isError) { return (
{t('notes.error')}
); } return (
{/* Notes Header */}

{t('notes.title')}

{/* Header with Search and Sort Controls */}
{/* Search Toggle Button */}
{/* Sort Filter Button */}
{/* Collapsible Search Bar */}
setSearchQuery(e.target.value)} className="w-full bg-transparent border-none focus:ring-0 focus:outline-none dark:text-white" />
{/* Notes Grid */} {sortedNotes.length === 0 ? (

{t('notes.noNotesFound')}

) : (
{sortedNotes.map((note) => ( { setNoteToDelete(note); setIsConfirmDialogOpen(true); }} showActions={true} showProject={true} /> ))}
)} {/* NoteModal */} {isNoteModalOpen && ( { setIsNoteModalOpen(false); }} onSave={handleSaveNote} onDelete={async (noteId) => { try { await apiDeleteNote(noteId); const updatedNotes = notes.filter( (note) => note.id !== noteId ); setNotes(updatedNotes); setIsNoteModalOpen(false); setSelectedNote(null); } catch (err) { console.error('Error deleting note:', err); } }} note={selectedNote} projects={ projects?.length > 0 ? projects : ([ { id: 1, name: 'Test Project 1', active: true, priority: 'low', }, { id: 2, name: 'tududi', active: true, priority: 'high', }, ] as any) } onCreateProject={handleCreateProject} /> )} {/* ConfirmDialog */} {isConfirmDialogOpen && noteToDelete && ( setIsConfirmDialogOpen(false)} /> )}
); }; export default Notes;