Merge pull request #123 from R0m1k3/claude/fix-notes-sync-issue-01AMeEdrKQErsM7bvhKkqEEF

Claude/fix notes sync issue 01 a me edr kq ers m7bvh kkq eef
This commit is contained in:
LogiFlow authored and GitHub committed 2025-11-27 09:50:53 +01:00
commit 4b9877dfb3
4 files changed
+129 -43

No files matched your search

+1 -20
View File
@@ -138,7 +138,6 @@
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.27.1", "@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.5", "@babel/generator": "^7.28.5",
@@ -3682,7 +3681,6 @@
"integrity": "sha512-LCCV0HdSZZZb34qifBsyWlUmok6W7ouER+oQIGBScS8EsZsQbrtFTUrDX4hOl+CS6p7cnNC4td+qrSVGSCTUfQ==", "integrity": "sha512-LCCV0HdSZZZb34qifBsyWlUmok6W7ouER+oQIGBScS8EsZsQbrtFTUrDX4hOl+CS6p7cnNC4td+qrSVGSCTUfQ==",
"devOptional": true, "devOptional": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"undici-types": "~6.21.0" "undici-types": "~6.21.0"
} }
@@ -3693,7 +3691,6 @@
"integrity": "sha512-k5dJVszUiNr1DSe8Cs+knKR6IrqhqdhpUwzqhkS8ecQTSf3THNtbfIp/umqHMpX2bv+9dkx3fwDv/86LcSfvSg==", "integrity": "sha512-k5dJVszUiNr1DSe8Cs+knKR6IrqhqdhpUwzqhkS8ecQTSf3THNtbfIp/umqHMpX2bv+9dkx3fwDv/86LcSfvSg==",
"devOptional": true, "devOptional": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"csstype": "^3.0.2" "csstype": "^3.0.2"
} }
@@ -3704,7 +3701,6 @@
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
"devOptional": true, "devOptional": true,
"license": "MIT", "license": "MIT",
"peer": true,
"peerDependencies": { "peerDependencies": {
"@types/react": "^19.2.0" "@types/react": "^19.2.0"
} }
@@ -3761,7 +3757,6 @@
"integrity": "sha512-tK3GPFWbirvNgsNKto+UmB/cRtn6TZfyw0D6IKrW55n6Vbs7KJoZtI//kpTKzE/DUmmnAFD8/Ca46s7Obs92/w==", "integrity": "sha512-tK3GPFWbirvNgsNKto+UmB/cRtn6TZfyw0D6IKrW55n6Vbs7KJoZtI//kpTKzE/DUmmnAFD8/Ca46s7Obs92/w==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "8.46.4", "@typescript-eslint/scope-manager": "8.46.4",
"@typescript-eslint/types": "8.46.4", "@typescript-eslint/types": "8.46.4",
@@ -4047,7 +4042,6 @@
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"acorn": "bin/acorn" "acorn": "bin/acorn"
}, },
@@ -4482,7 +4476,6 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"baseline-browser-mapping": "^2.8.25", "baseline-browser-mapping": "^2.8.25",
"caniuse-lite": "^1.0.30001754", "caniuse-lite": "^1.0.30001754",
@@ -5335,8 +5328,7 @@
"version": "8.6.0", "version": "8.6.0",
"resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.6.0.tgz", "resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.6.0.tgz",
"integrity": "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==", "integrity": "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==",
"license": "MIT", "license": "MIT"
"peer": true
}, },
"node_modules/embla-carousel-react": { "node_modules/embla-carousel-react": {
"version": "8.6.0", "version": "8.6.0",
@@ -5537,7 +5529,6 @@
"integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.1", "@eslint-community/regexpp": "^4.12.1",
@@ -6992,7 +6983,6 @@
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz",
"integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"jiti": "bin/jiti.js" "jiti": "bin/jiti.js"
} }
@@ -8226,7 +8216,6 @@
"resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz", "resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz",
"integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==", "integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"pg-connection-string": "^2.9.1", "pg-connection-string": "^2.9.1",
"pg-pool": "^3.10.1", "pg-pool": "^3.10.1",
@@ -8366,7 +8355,6 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"nanoid": "^3.3.11", "nanoid": "^3.3.11",
"picocolors": "^1.1.1", "picocolors": "^1.1.1",
@@ -8757,7 +8745,6 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz",
"integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
@@ -8798,7 +8785,6 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz",
"integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"scheduler": "^0.27.0" "scheduler": "^0.27.0"
}, },
@@ -9851,7 +9837,6 @@
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.18.tgz", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.18.tgz",
"integrity": "sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ==", "integrity": "sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@alloc/quick-lru": "^5.2.0", "@alloc/quick-lru": "^5.2.0",
"arg": "^5.0.2", "arg": "^5.0.2",
@@ -10056,7 +10041,6 @@
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=12" "node": ">=12"
}, },
@@ -10185,7 +10169,6 @@
"integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
@@ -10433,7 +10416,6 @@
"resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
"integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"esbuild": "^0.25.0", "esbuild": "^0.25.0",
"fdir": "^6.4.4", "fdir": "^6.4.4",
@@ -10525,7 +10507,6 @@
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=12" "node": ">=12"
}, },
+23 -9
View File
@@ -1414,9 +1414,14 @@ const Index = () => {
<Checkbox <Checkbox
checked={todo.completed} checked={todo.completed}
onCheckedChange={async () => { onCheckedChange={async () => {
const updatedTodos = [...(openNote.todos || [])]; if (!todo.id) return;
updatedTodos[index] = { ...todo, completed: !todo.completed }; const success = await NotesService.toggleTodo(todo.id, !todo.completed);
await handleUpdateNote({ todos: updatedTodos }); if (success) {
const updatedTodos = [...(openNote.todos || [])];
updatedTodos[index] = { ...todo, completed: !todo.completed };
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"}> <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" size="icon"
className="h-6 w-6" className="h-6 w-6"
onClick={async () => { onClick={async () => {
const updatedTodos = [...(openNote.todos || [])]; if (!todo.id) return;
updatedTodos.splice(index, 1); const success = await NotesService.deleteTodo(todo.id);
await handleUpdateNote({ todos: updatedTodos }); 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" /> <Trash2 className="h-3 w-3" />
@@ -2215,9 +2225,13 @@ const Index = () => {
label="Tâche" label="Tâche"
placeholder="Entrez la tâche..." placeholder="Entrez la tâche..."
onConfirm={async (text) => { onConfirm={async (text) => {
if (openNote) { if (openNote?.id) {
const updatedTodos = [...(openNote.todos || []), { text, completed: false }]; const newTodo = await NotesService.addTodo(openNote.id, text);
await handleUpdateNote({ todos: updatedTodos }); 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" confirmText="Ajouter"
+26 -14
View File
@@ -80,28 +80,40 @@ export default function NoteDetailPage() {
}; };
const handleAddTodo = async () => { const handleAddTodo = async () => {
if (!note || !todoText.trim()) return; if (!note?.id || !todoText.trim()) return;
const newTodo = { text: todoText, completed: false }; const newTodo = await NotesService.addTodo(note.id, todoText.trim());
const updatedTodos = [...(note.todos || []), newTodo]; if (newTodo) {
await updateNote({ todos: updatedTodos }); const updatedTodos = [...(note.todos || []), newTodo];
setTodoText(""); setNote({ ...note, todos: updatedTodos });
setAddTodoModal(false); setTodoText("");
showSuccess("Tâche ajoutée"); setAddTodoModal(false);
}
}; };
const handleToggleTodo = async (index: number) => { const handleToggleTodo = async (index: number) => {
if (!note?.todos) return; if (!note?.todos) return;
const updatedTodos = [...note.todos]; const todo = note.todos[index];
updatedTodos[index] = { ...updatedTodos[index], completed: !updatedTodos[index].completed }; if (!todo.id) return;
await updateNote({ todos: updatedTodos });
const success = await NotesService.toggleTodo(todo.id, !todo.completed);
if (success) {
const updatedTodos = [...note.todos];
updatedTodos[index] = { ...updatedTodos[index], completed: !updatedTodos[index].completed };
setNote({ ...note, todos: updatedTodos });
}
}; };
const handleDeleteTodo = async (index: number) => { const handleDeleteTodo = async (index: number) => {
if (!note?.todos) return; if (!note?.todos) return;
const updatedTodos = [...note.todos]; const todo = note.todos[index];
updatedTodos.splice(index, 1); if (!todo.id) return;
await updateNote({ todos: updatedTodos });
showSuccess("Tâche supprimée"); 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>) => { const handleImageUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
+79
View File
@@ -219,6 +219,85 @@ class NotesService {
return false; 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(); export default new NotesService();