"use client"; import React, { useState, useEffect, useRef } from 'react'; import { Image, FileText, Link, List, Plus } from 'lucide-react'; import { useRouter } from 'next/navigation'; import { useSession } from 'next-auth/react'; interface Note { id: string; title: string; content: string; lastModified: string; type: string; mime: string; etag: string; } interface EditorProps { note?: Note | null; onSave?: (note: Note) => void; currentFolder?: string; onRefresh?: () => void; } export const Editor: React.FC = ({ note, onSave, currentFolder = 'Notes', onRefresh }) => { const [title, setTitle] = useState(note?.title || ''); const [content, setContent] = useState(note?.content || ''); const [isSaving, setIsSaving] = useState(false); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const saveTimeout = useRef(); const router = useRouter(); const { data: session, status } = useSession(); // Content cache for notes const contentCache = useRef>({}); const CACHE_EXPIRATION = 15 * 60 * 1000; // 15 minutes in milliseconds useEffect(() => { // Redirect to login if not authenticated if (status === 'unauthenticated') { router.push('/signin'); } }, [status, router]); useEffect(() => { const fetchNoteContent = async () => { if (note?.id) { setIsLoading(true); setError(null); // First check in-memory cache const cachedContent = contentCache.current[note.id]; if (cachedContent && (Date.now() - cachedContent.timestamp) < CACHE_EXPIRATION) { console.log(`Using cached content for note ${note.title}`); setContent(cachedContent.content); setIsLoading(false); return; } // Then check localStorage cache try { const localStorageKey = `note-content-${note.id}`; const storedCache = localStorage.getItem(localStorageKey); if (storedCache) { const { content, timestamp } = JSON.parse(storedCache); if ((Date.now() - timestamp) < CACHE_EXPIRATION) { console.log(`Using localStorage cached content for note ${note.title}`); setContent(content); // Update in-memory cache contentCache.current[note.id] = { content, timestamp }; setIsLoading(false); return; } } } catch (error) { console.error('Error accessing localStorage content cache:', error); } // If cache miss, fetch from API try { const response = await fetch(`/api/storage/files/content?path=${encodeURIComponent(note.id)}`); if (response.status === 401) { console.error('Authentication error, redirecting to login'); router.push('/signin'); return; } if (!response.ok) { const errorText = await response.text(); throw new Error(`Failed to fetch note content: ${response.status} ${errorText}`); } const data = await response.json(); setContent(data.content); // Update both caches const newTimestamp = Date.now(); contentCache.current[note.id] = { content: data.content, timestamp: newTimestamp }; try { localStorage.setItem(`note-content-${note.id}`, JSON.stringify({ content: data.content, timestamp: newTimestamp })); } catch (error) { console.error('Error saving content to localStorage:', error); } } catch (error) { console.error('Error fetching note content:', error); setError('Failed to load note content. Please try again later.'); } finally { setIsLoading(false); } } }; if (note) { setTitle(note.title); if (note.id) { fetchNoteContent(); } else { setContent(''); } } else { setTitle(''); setContent(''); } }, [note, router, CACHE_EXPIRATION]); const handleTitleChange = (e: React.ChangeEvent) => { setTitle(e.target.value); debouncedSave(); }; const handleContentChange = (e: React.ChangeEvent) => { setContent(e.target.value); debouncedSave(); }; const debouncedSave = () => { if (saveTimeout.current) { clearTimeout(saveTimeout.current); } saveTimeout.current = setTimeout(() => { handleSave(); }, 1000); // Save after 1 second of inactivity }; const handleSave = async () => { if (!title || !content) return; if (!session) { console.error('No active session, cannot save'); setError('You must be logged in to save notes'); return; } setIsSaving(true); setError(null); try { // Construct the full note ID if it doesn't exist yet const noteId = note?.id || `user-${session.user.id}/${currentFolder.toLowerCase()}/${title}${title.endsWith('.md') ? '' : '.md'}`; const endpoint = '/api/storage/files'; const method = note?.id ? 'PUT' : 'POST'; console.log('Saving note:', { id: noteId, title, folder: currentFolder, contentLength: content.length }); const response = await fetch(endpoint, { method, headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ id: noteId, title, content, folder: currentFolder.toLowerCase() }), }); if (response.status === 401) { console.error('Authentication error, redirecting to login'); router.push('/signin'); return; } if (!response.ok) { const errorData = await response.text(); console.error('Failed to save note:', { status: response.status, statusText: response.statusText, data: errorData }); setError(`Failed to save note: ${response.statusText}`); throw new Error(`Failed to save note: ${response.status} ${response.statusText}`); } const savedNote = await response.json(); console.log('Note saved successfully:', savedNote); // Update content cache after successful save const newTimestamp = Date.now(); // Update in-memory cache contentCache.current[noteId] = { content, timestamp: newTimestamp }; // Update localStorage cache try { localStorage.setItem(`note-content-${noteId}`, JSON.stringify({ content, timestamp: newTimestamp })); } catch (error) { console.error('Error updating content cache in localStorage:', error); } setError(null); onSave?.({ ...savedNote, content }); onRefresh?.(); } catch (error) { console.error('Error saving note:', error); } finally { setIsSaving(false); } }; if (!session && status !== 'loading') { return (

Authentication Required

Please log in to access your notes

); } if (!note) { return (

Sélectionnez une note

Choisissez une note existante ou créez-en une nouvelle

); } return (
{/* Title Bar */}
{/* Error Display */} {error && (
{error}
)} {/* Editor Area */}
{isLoading ? (
) : (