Files
noteflow/src/services/NotesService.ts
T
Claude b36525919f Feature: Affichage tags et icône priorité dans les cartes notes
Ajout de deux nouvelles fonctionnalités pour les notes:

1. Affichage des tags dans les cartes repliées:
- Les tags sont maintenant visibles dans les cartes de notes sans avoir à les ouvrir
- Badge avec icône TagIcon et nom du tag
- Chargement automatique des tags depuis la base de données

2. Icône de priorité cliquable:
- Bouton "!" en haut à droite de chaque carte de note
- Rouge (!) quand la note est prioritaire (toujours visible)
- Gris clair (!) quand non prioritaire (visible au hover)
- Toggle au clic pour marquer/démarquer comme prioritaire
- Les notes prioritaires sont triées en premier

Backend:
- Route PATCH /api/notes/:id/priority pour toggle la priorité
- Modification GET /api/notes pour charger tags et priority
- Tri par priority DESC, updated_at DESC
- Migration automatique pour ajouter colonne priority
- Index pour performance des requêtes de tri

Frontend:
- Interface Note étendue avec tags et priority
- Méthode togglePriority dans NotesService
- Affichage conditionnel de l'icône (toujours visible si prioritaire)
- Empêche le clic sur l'icône d'ouvrir la note (stopPropagation)

Migration:
- Ajout automatique de la colonne priority (INTEGER DEFAULT 0)
- Création d'index idx_notes_priority pour performance
- Fichier de migration 002_add_priority.sql créé pour référence
2025-11-12 21:41:34 +00:00

195 lines
4.8 KiB
TypeScript

import AuthService from "./AuthService";
import { showError, showSuccess } from "@/utils/toast";
interface Todo {
id?: number;
text: string;
completed: boolean;
position?: number;
}
interface Image {
id?: number;
filename: string;
original_name?: string;
}
interface NoteFile {
id?: number;
filename: string;
original_name?: string;
size?: number;
}
export interface Note {
id?: number;
title: string;
content: string;
archived?: boolean;
created_at?: string;
updated_at?: string;
todos: Todo[];
images: Image[];
files?: NoteFile[];
tags?: Array<{ id: number; name: string }>;
priority?: boolean;
}
class NotesService {
async getNotes(): Promise<Note[]> {
try {
const response = await fetch("/api/notes", {
headers: AuthService.getHeaders()
});
if (!response.ok) {
throw new Error("Erreur lors de la récupération des notes");
}
const notes = await response.json();
// Ensure todos and images are always arrays
return notes.map((note: Note) => ({
...note,
todos: note.todos || [],
images: note.images || []
}));
} catch (error) {
showError(error instanceof Error ? error.message : "Erreur serveur");
return [];
}
}
async createNote(title: string, content: string = ""): Promise<Note | null> {
try {
const response = await fetch("/api/notes", {
method: "POST",
headers: AuthService.getHeaders(),
body: JSON.stringify({ title, content, todos: [] })
});
if (!response.ok) {
throw new Error("Erreur lors de la création de la note");
}
showSuccess("Note créée avec succès");
const note = await response.json();
return {
...note,
todos: note.todos || [],
images: note.images || []
};
} catch (error) {
showError(error instanceof Error ? error.message : "Erreur serveur");
return null;
}
}
async updateNote(note: Note): Promise<boolean> {
if (!note.id) return false;
try {
const response = await fetch(`/api/notes/${note.id}`, {
method: "PUT",
headers: AuthService.getHeaders(),
body: JSON.stringify({
...note,
todos: note.todos || [],
images: note.images || []
})
});
if (!response.ok) {
throw new Error("Erreur lors de la mise à jour de la note");
}
return true;
} catch (error) {
showError(error instanceof Error ? error.message : "Erreur serveur");
return false;
}
}
async deleteNote(noteId: number): Promise<boolean> {
try {
const response = await fetch(`/api/notes/${noteId}`, {
method: "DELETE",
headers: AuthService.getHeaders()
});
if (!response.ok) {
throw new Error("Erreur lors de la suppression de la note");
}
showSuccess("Note supprimée avec succès");
return true;
} catch (error) {
showError(error instanceof Error ? error.message : "Erreur serveur");
return false;
}
}
async uploadImage(noteId: number, file: File): Promise<Image | null> {
const formData = new FormData();
formData.append("image", file);
try {
const response = await fetch(`/api/notes/${noteId}/images`, {
method: "POST",
headers: {
"Authorization": AuthService.getHeaders().Authorization
},
body: formData
});
if (!response.ok) {
throw new Error("Erreur lors de l'upload de l'image");
}
const result = await response.json();
return result.image || result;
} catch (error) {
showError(error instanceof Error ? error.message : "Erreur serveur");
return null;
}
}
async deleteImage(noteId: number, imageId: number): Promise<boolean> {
try {
const response = await fetch(`/api/notes/${noteId}/images/${imageId}`, {
method: "DELETE",
headers: AuthService.getHeaders()
});
if (!response.ok) {
throw new Error("Erreur lors de la suppression de l'image");
}
return true;
} catch (error) {
showError(error instanceof Error ? error.message : "Erreur serveur");
return false;
}
}
async togglePriority(noteId: number, priority: boolean): Promise<boolean> {
try {
const response = await fetch(`/api/notes/${noteId}/priority`, {
method: "PATCH",
headers: AuthService.getHeaders(),
body: JSON.stringify({ priority })
});
if (!response.ok) {
throw new Error("Erreur lors de la mise à jour de la priorité");
}
return true;
} catch (error) {
showError(error instanceof Error ? error.message : "Erreur serveur");
return false;
}
}
}
export default new NotesService();