Fix critique: Système de notes complètement refondu pour fonctionner

Problème majeur résolu:
- L'éditeur de notes réinitialisait le contenu à chaque modification
- Causé par dangerouslySetInnerHTML qui forçait React à synchroniser
- Résultat: impossible d'éditer les notes correctement

Solution:
- Suppression de dangerouslySetInnerHTML du RichTextEditor
- Conservation du useEffect avec deps vides pour initialisation unique
- Utilisation du key prop pour forcer remount lors du changement de note
- Éditeur maintenant complètement "uncontrolled"

Migration complète Google Calendar vers OAuth 2.0:
- Remplacement de l'API Key simple par OAuth 2.0 (Client ID + Secret)
- Nouvelle table google_oauth_tokens pour stocker les tokens
- Routes OAuth:
  * GET /api/calendar/auth-url - Génère l'URL d'authentification
  * GET /api/calendar/oauth-callback - Callback OAuth avec échange de code
  * GET /api/calendar/auth-status - Vérifier le statut de connexion
  * POST /api/calendar/disconnect - Déconnecter Google
- Gestion automatique du rafraîchissement des tokens expirés
- Interface utilisateur mise à jour:
  * Champs Client ID et Client Secret
  * Indicateur de statut de connexion (connecté/non connecté)
  * Bouton "Se connecter avec Google" ouvrant popup OAuth
  * Bouton "Déconnecter"
  * URI de redirection affichée pour configuration Google Cloud Console
- Synchronisation maintenant avec calendrier principal de l'utilisateur
- Accès complet aux données privées du calendrier

Architecture:
- CalendarService.ts: Nouvelles méthodes getAuthUrl(), getAuthStatus(), disconnect()
- Settings: Ajout de google_client_id et google_client_secret
- Popup OAuth avec communication window.postMessage
- Gestion d'erreur avec re-authentification automatique si token expiré
This commit is contained in:
Claude committed 2025-11-12 10:00:33 +00:00
1 parent fea31d31bf
commit 0e8b36e1d7
6 files changed
+444 -56

No files matched your search

+34
View File
@@ -37,6 +37,40 @@ class CalendarService {
}
}
/**
* Obtenir l'URL d'authentification OAuth Google
*/
async getAuthUrl(): Promise<string> {
const response = await axios.get(`${this.baseURL}/auth-url`, this.getAuthHeader());
return response.data.authUrl;
}
/**
* Vérifier le statut d'authentification Google
*/
async getAuthStatus(): Promise<{ isAuthenticated: boolean; isExpired: boolean; needsReauth: boolean }> {
try {
const response = await axios.get(`${this.baseURL}/auth-status`, this.getAuthHeader());
return response.data;
} catch (error) {
console.error("Erreur lors de la vérification du statut OAuth:", error);
return { isAuthenticated: false, isExpired: false, needsReauth: true };
}
}
/**
* Déconnecter Google Calendar
*/
async disconnect(): Promise<boolean> {
try {
await axios.post(`${this.baseURL}/disconnect`, {}, this.getAuthHeader());
return true;
} catch (error) {
console.error("Erreur lors de la déconnexion:", error);
return false;
}
}
/**
* Synchroniser avec Google Calendar
*/
+3
View File
@@ -5,6 +5,9 @@ export interface Settings {
ai_model?: string;
rss_refresh_interval?: number;
theme?: 'light' | 'dark' | 'auto';
google_client_id?: string;
google_client_secret?: string;
// Legacy fields (kept for backward compatibility)
google_calendar_api_key?: string;
google_calendar_id?: string;
}