mirror of
https://github.com/R0m1k3/noteflow.git
synced 2026-10-11 17:29:37 +02:00
fix: resolve note todos synchronization issue between mobile and desktop
Fixed critical bug where todos added on mobile or desktop were being silently lost. Root cause: - Mobile and desktop were sending todos via the generic PUT /api/notes/:id endpoint - Backend ignored the 'todos' field in this endpoint (only processes title and content) - Users saw success messages but todos were never saved to database - On reload, todos disappeared Solution: - Added dedicated todo management methods to NotesService: * addTodo() - POST /api/notes/:id/todos * updateTodo() - PUT /api/notes/todos/:todoId * toggleTodo() - PUT /api/notes/todos/:todoId * deleteTodo() - DELETE /api/notes/todos/:todoId - Updated NoteDetailPage.tsx (mobile) to use proper API methods - Updated Index.tsx (desktop) to use proper API methods - Both versions now correctly persist todos to the database Files modified: - src/services/NotesService.ts - Added todo management methods - src/pages/mobile/NoteDetailPage.tsx - Fixed todo handlers - src/pages/Index.tsx - Fixed todo handlers in note detail view
This commit is contained in:
3 files changed
+120
-15
No files matched your search
+21
-7
@@ -1414,9 +1414,14 @@ const Index = () => {
|
||||
<Checkbox
|
||||
checked={todo.completed}
|
||||
onCheckedChange={async () => {
|
||||
if (!todo.id) return;
|
||||
const success = await NotesService.toggleTodo(todo.id, !todo.completed);
|
||||
if (success) {
|
||||
const updatedTodos = [...(openNote.todos || [])];
|
||||
updatedTodos[index] = { ...todo, completed: !todo.completed };
|
||||
await handleUpdateNote({ todos: updatedTodos });
|
||||
setOpenNote({ ...openNote, todos: updatedTodos });
|
||||
setNotes(prev => prev.map(note => note.id === openNote.id ? { ...note, todos: updatedTodos } : note));
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<span className={todo.completed ? "line-through text-muted-foreground flex-1 text-sm" : "flex-1 text-sm"}>
|
||||
@@ -1427,9 +1432,14 @@ const Index = () => {
|
||||
size="icon"
|
||||
className="h-6 w-6"
|
||||
onClick={async () => {
|
||||
const updatedTodos = [...(openNote.todos || [])];
|
||||
updatedTodos.splice(index, 1);
|
||||
await handleUpdateNote({ todos: updatedTodos });
|
||||
if (!todo.id) return;
|
||||
const success = await NotesService.deleteTodo(todo.id);
|
||||
if (success) {
|
||||
const updatedTodos = openNote.todos.filter((_, i) => i !== index);
|
||||
setOpenNote({ ...openNote, todos: updatedTodos });
|
||||
setNotes(prev => prev.map(note => note.id === openNote.id ? { ...note, todos: updatedTodos } : note));
|
||||
showSuccess("Tâche supprimée");
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Trash2 className="h-3 w-3" />
|
||||
@@ -2215,9 +2225,13 @@ const Index = () => {
|
||||
label="Tâche"
|
||||
placeholder="Entrez la tâche..."
|
||||
onConfirm={async (text) => {
|
||||
if (openNote) {
|
||||
const updatedTodos = [...(openNote.todos || []), { text, completed: false }];
|
||||
await handleUpdateNote({ todos: updatedTodos });
|
||||
if (openNote?.id) {
|
||||
const newTodo = await NotesService.addTodo(openNote.id, text);
|
||||
if (newTodo) {
|
||||
const updatedTodos = [...(openNote.todos || []), newTodo];
|
||||
setOpenNote({ ...openNote, todos: updatedTodos });
|
||||
setNotes(prev => prev.map(note => note.id === openNote.id ? { ...note, todos: updatedTodos } : note));
|
||||
}
|
||||
}
|
||||
}}
|
||||
confirmText="Ajouter"
|
||||
|
||||
@@ -80,28 +80,40 @@ export default function NoteDetailPage() {
|
||||
};
|
||||
|
||||
const handleAddTodo = async () => {
|
||||
if (!note || !todoText.trim()) return;
|
||||
const newTodo = { text: todoText, completed: false };
|
||||
if (!note?.id || !todoText.trim()) return;
|
||||
const newTodo = await NotesService.addTodo(note.id, todoText.trim());
|
||||
if (newTodo) {
|
||||
const updatedTodos = [...(note.todos || []), newTodo];
|
||||
await updateNote({ todos: updatedTodos });
|
||||
setNote({ ...note, todos: updatedTodos });
|
||||
setTodoText("");
|
||||
setAddTodoModal(false);
|
||||
showSuccess("Tâche ajoutée");
|
||||
}
|
||||
};
|
||||
|
||||
const handleToggleTodo = async (index: number) => {
|
||||
if (!note?.todos) return;
|
||||
const todo = note.todos[index];
|
||||
if (!todo.id) return;
|
||||
|
||||
const success = await NotesService.toggleTodo(todo.id, !todo.completed);
|
||||
if (success) {
|
||||
const updatedTodos = [...note.todos];
|
||||
updatedTodos[index] = { ...updatedTodos[index], completed: !updatedTodos[index].completed };
|
||||
await updateNote({ todos: updatedTodos });
|
||||
setNote({ ...note, todos: updatedTodos });
|
||||
}
|
||||
};
|
||||
|
||||
const handleDeleteTodo = async (index: number) => {
|
||||
if (!note?.todos) return;
|
||||
const updatedTodos = [...note.todos];
|
||||
updatedTodos.splice(index, 1);
|
||||
await updateNote({ todos: updatedTodos });
|
||||
const todo = note.todos[index];
|
||||
if (!todo.id) return;
|
||||
|
||||
const success = await NotesService.deleteTodo(todo.id);
|
||||
if (success) {
|
||||
const updatedTodos = note.todos.filter((_, i) => i !== index);
|
||||
setNote({ ...note, todos: updatedTodos });
|
||||
showSuccess("Tâche supprimée");
|
||||
}
|
||||
};
|
||||
|
||||
const handleImageUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
|
||||
@@ -219,6 +219,85 @@ class NotesService {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Todo management methods
|
||||
async addTodo(noteId: number, text: string): Promise<Todo | null> {
|
||||
try {
|
||||
const response = await fetch(`/api/notes/${noteId}/todos`, {
|
||||
method: "POST",
|
||||
headers: AuthService.getHeaders(),
|
||||
body: JSON.stringify({ text })
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Erreur lors de l'ajout de la tâche");
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
showSuccess("Tâche ajoutée");
|
||||
return result.todo || result;
|
||||
} catch (error) {
|
||||
showError(error instanceof Error ? error.message : "Erreur serveur");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async updateTodo(todoId: number, updates: Partial<Todo>): Promise<Todo | null> {
|
||||
try {
|
||||
const response = await fetch(`/api/notes/todos/${todoId}`, {
|
||||
method: "PUT",
|
||||
headers: AuthService.getHeaders(),
|
||||
body: JSON.stringify(updates)
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Erreur lors de la mise à jour de la tâche");
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
return result.todo || result;
|
||||
} catch (error) {
|
||||
showError(error instanceof Error ? error.message : "Erreur serveur");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async toggleTodo(todoId: number, completed: boolean): Promise<boolean> {
|
||||
try {
|
||||
const response = await fetch(`/api/notes/todos/${todoId}`, {
|
||||
method: "PUT",
|
||||
headers: AuthService.getHeaders(),
|
||||
body: JSON.stringify({ completed })
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Erreur lors de la mise à jour de la tâche");
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
showError(error instanceof Error ? error.message : "Erreur serveur");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async deleteTodo(todoId: number): Promise<boolean> {
|
||||
try {
|
||||
const response = await fetch(`/api/notes/todos/${todoId}`, {
|
||||
method: "DELETE",
|
||||
headers: AuthService.getHeaders()
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Erreur lors de la suppression de la tâche");
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
showError(error instanceof Error ? error.message : "Erreur serveur");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default new NotesService();
|
||||
Reference in new issue
Block a user