Feature: Support multi-images, Google Calendar et correction RTL

Images multiples :
- Ajout table note_images dans la base de données
- Routes POST/GET/DELETE /api/notes/:id/images
- Dossier uploads/images séparé pour les images
- Support de plusieurs images par note

Google Calendar :
- Ajout table calendar_events
- Routes /api/calendar pour sync et récupération des événements
- Box Rendez-vous dans l'interface avec affichage des événements à venir
- Configuration Google Calendar dans l'admin (API key et Calendar ID)
- Synchronisation manuelle avec Google Calendar API
- Installation package googleapis

Corrections :
- Fix RichTextEditor: ajout dir="ltr" pour empêcher l'écriture RTL
- Fix Image type conflict (lucide-react vs Note interface)
- Ajout original_name à l'interface Image pour compatibilité

Interface :
- Box Rendez-vous empilée avec Todos et RSS dans la colonne droite
- Nouvel onglet Google Calendar dans l'administration
- Bouton "Synchroniser" pour rafraîchir les événements
This commit is contained in:
Claude committed 2025-11-12 09:11:11 +00:00
1 parent 44e6f7bb5e
commit 702d0c2088
10 files changed
+946 -5

No files matched your search

+62
View File
@@ -0,0 +1,62 @@
import axios from "axios";
import AuthService from "./AuthService";
export interface CalendarEvent {
id: number;
google_event_id: string;
title: string;
description?: string;
start_time: string;
end_time: string;
location?: string;
html_link?: string;
synced_at?: string;
}
class CalendarService {
private baseURL = "/api/calendar";
private getAuthHeader() {
return {
headers: {
Authorization: `Bearer ${AuthService.getToken()}`,
},
};
}
/**
* Récupérer les événements du calendrier
*/
async getEvents(limit: number = 10): Promise<CalendarEvent[]> {
try {
const response = await axios.get(`${this.baseURL}/events?limit=${limit}`, this.getAuthHeader());
return response.data;
} catch (error) {
console.error("Erreur lors de la récupération des événements:", error);
return [];
}
}
/**
* Synchroniser avec Google Calendar
*/
async sync(): Promise<{ syncedCount: number; events: number }> {
const response = await axios.post(`${this.baseURL}/sync`, {}, this.getAuthHeader());
return response.data;
}
/**
* Supprimer un événement local
*/
async deleteEvent(eventId: number): Promise<boolean> {
try {
await axios.delete(`${this.baseURL}/events/${eventId}`, this.getAuthHeader());
return true;
} catch (error) {
console.error("Erreur lors de la suppression de l'événement:", error);
return false;
}
}
}
export default new CalendarService();
+2
View File
@@ -5,6 +5,8 @@ export interface Settings {
ai_model?: string;
rss_refresh_interval?: number;
theme?: 'light' | 'dark' | 'auto';
google_calendar_api_key?: string;
google_calendar_id?: string;
}
class SettingsService {