carnet panel

This commit is contained in:
alma 2025-04-20 18:50:29 +02:00
parent c9d483223d
commit 2fc389a091
3 changed files with 97 additions and 49 deletions

View File

@ -214,6 +214,39 @@ export default function CarnetPage() {
}
};
const handleDeleteNote = async (note: Note) => {
try {
const response = await fetch(`/api/nextcloud/files`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
id: note.id,
folder: selectedFolder
}),
});
if (!response.ok) {
throw new Error('Failed to delete note');
}
// Refresh the notes list
const notesResponse = await fetch(`/api/nextcloud/files?folder=${selectedFolder}`);
if (notesResponse.ok) {
const updatedNotes = await notesResponse.json();
setNotes(updatedNotes);
}
// If the deleted note was selected, clear the selection
if (selectedNote?.id === note.id) {
setSelectedNote(null);
}
} catch (error) {
console.error('Error deleting note:', error);
}
};
if (isLoading) {
return (
<div className="flex h-screen items-center justify-center">
@ -259,6 +292,7 @@ export default function CarnetPage() {
onNoteSelect={handleNoteSelect}
currentFolder={selectedFolder}
onNewNote={handleNewNote}
onDeleteNote={handleDeleteNote}
/>
</div>

View File

@ -1,6 +1,6 @@
"use client";
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, useRef } from 'react';
import { Image, FileText, Link, List, Plus } from 'lucide-react';
interface Note {
@ -25,6 +25,7 @@ export const Editor: React.FC<EditorProps> = ({ note, onSave, currentFolder = 'N
const [content, setContent] = useState(note?.content || '');
const [isSaving, setIsSaving] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const saveTimeout = useRef<NodeJS.Timeout>();
useEffect(() => {
const fetchNoteContent = async () => {
@ -60,10 +61,21 @@ export const Editor: React.FC<EditorProps> = ({ note, onSave, currentFolder = 'N
const handleTitleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setTitle(e.target.value);
debouncedSave();
};
const handleContentChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
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 () => {
@ -99,7 +111,6 @@ export const Editor: React.FC<EditorProps> = ({ note, onSave, currentFolder = 'N
onRefresh?.();
} catch (error) {
console.error('Error saving note:', error);
// TODO: Show error message to user
} finally {
setIsSaving(false);
}
@ -134,28 +145,6 @@ export const Editor: React.FC<EditorProps> = ({ note, onSave, currentFolder = 'N
/>
</div>
{/* Toolbar */}
<div className="px-4 py-2 border-b border-carnet-border">
<div className="flex space-x-1">
<button className="p-1.5 rounded hover:bg-carnet-hover">
<List className="h-4 w-4 text-carnet-text-muted" />
</button>
<button className="p-1.5 rounded hover:bg-carnet-hover">
<Link className="h-4 w-4 text-carnet-text-muted" />
</button>
<button className="p-1.5 rounded hover:bg-carnet-hover">
<Image className="h-4 w-4 text-carnet-text-muted" />
</button>
<button
className={`p-1.5 rounded hover:bg-carnet-hover ${isSaving ? 'opacity-50 cursor-not-allowed' : ''}`}
onClick={handleSave}
disabled={isSaving}
>
<FileText className="h-4 w-4 text-carnet-text-muted" />
</button>
</div>
</div>
{/* Editor Area */}
<div className="flex-1 p-4">
{isLoading ? (
@ -171,6 +160,11 @@ export const Editor: React.FC<EditorProps> = ({ note, onSave, currentFolder = 'N
/>
)}
</div>
{isSaving && (
<div className="absolute bottom-4 right-4 text-sm text-carnet-text-muted">
Enregistrement...
</div>
)}
</div>
);
};

View File

@ -21,6 +21,7 @@ interface NotesViewProps {
currentFolder?: string;
onNewNote?: () => void;
loading?: boolean;
onDeleteNote?: (note: Note) => void;
}
export const NotesView: React.FC<NotesViewProps> = ({
@ -28,9 +29,11 @@ export const NotesView: React.FC<NotesViewProps> = ({
onNoteSelect,
currentFolder = 'Notes',
onNewNote,
loading = false
loading = false,
onDeleteNote
}) => {
const [searchQuery, setSearchQuery] = useState('');
const [hoveredNote, setHoveredNote] = useState<string | null>(null);
const formatDate = (dateString: string) => {
return format(new Date(dateString), 'EEEE d MMM yyyy', { locale: fr });
@ -125,32 +128,49 @@ export const NotesView: React.FC<NotesViewProps> = ({
{sortNotes(notes).map((note) => (
<li
key={note.id}
onClick={() => onNoteSelect?.(note)}
className="p-4 hover:bg-carnet-hover cursor-pointer"
onMouseEnter={() => setHoveredNote(note.id)}
onMouseLeave={() => setHoveredNote(null)}
className="p-4 hover:bg-carnet-hover cursor-pointer group"
>
<div className="flex items-center space-x-2">
<Icon className="h-4 w-4 text-carnet-text-muted" />
<div className="flex-1">
{currentFolder === 'Diary' || currentFolder === 'Health' ? (
<>
<div className="text-sm font-medium text-carnet-text-primary">
{formatDate(note.lastModified)}
</div>
<div className="text-sm text-carnet-text-muted">
{formatNoteTitle(note)}
</div>
</>
) : (
<>
<div className="text-sm font-medium text-carnet-text-primary">
{note.title}
</div>
<div className="text-xs text-carnet-text-muted">
{formatDate(note.lastModified)}
</div>
</>
)}
<div className="flex items-center justify-between">
<div
className="flex items-center space-x-2 flex-1"
onClick={() => onNoteSelect?.(note)}
>
<Icon className="h-4 w-4 text-carnet-text-muted" />
<div className="flex-1">
{currentFolder === 'Diary' || currentFolder === 'Health' ? (
<>
<div className="text-sm font-medium text-carnet-text-primary">
{formatDate(note.lastModified)}
</div>
<div className="text-sm text-carnet-text-muted">
{formatNoteTitle(note)}
</div>
</>
) : (
<>
<div className="text-sm font-medium text-carnet-text-primary">
{note.title}
</div>
<div className="text-xs text-carnet-text-muted">
{formatDate(note.lastModified)}
</div>
</>
)}
</div>
</div>
{currentFolder === 'Notes' && hoveredNote === note.id && (
<button
onClick={(e) => {
e.stopPropagation();
onDeleteNote?.(note);
}}
className="p-1 text-carnet-text-muted hover:text-red-500 opacity-0 group-hover:opacity-100 transition-opacity"
>
<X className="h-4 w-4" />
</button>
)}
</div>
</li>
))}