/* ═══════════════════════════════════════════════════════════════════════════ ML ACADEMY — FEEDBACK STORAGE SYSTEM Stocke les feedbacks au format JSON pour traitement ulterieur ═══════════════════════════════════════════════════════════════════════════ */ class FeedbackStorage { constructor() { this.storageKey = 'ml_academy_feedbacks'; this.feedbacks = this.loadFeedbacks(); } // Charge tous les feedbacks depuis le stockage loadFeedbacks() { try { const stored = localStorage.getItem(this.storageKey); return stored ? JSON.parse(stored) : []; } catch (e) { console.error('Erreur lors du chargement des feedbacks:', e); return []; } } // Sauvegarde tous les feedbacks saveFeedbacks() { try { localStorage.setItem(this.storageKey, JSON.stringify(this.feedbacks)); return true; } catch (e) { console.error('Erreur lors de la sauvegarde des feedbacks:', e); return false; } } // Ajoute un nouveau feedback addFeedback(feedbackData) { const feedback = { id: this.generateId(), timestamp: new Date().toISOString(), ...feedbackData }; this.feedbacks.push(feedback); this.saveFeedbacks(); // Exporte automatiquement vers un fichier JSON telechargeable this.exportToFile(); return feedback; } // Genere un ID unique generateId() { return 'fb_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9); } // Recupere tous les feedbacks getAllFeedbacks() { return this.feedbacks; } // Recupere les feedbacks par date getFeedbacksByDateRange(startDate, endDate) { return this.feedbacks.filter(fb => { const fbDate = new Date(fb.timestamp); return fbDate >= startDate && fbDate <= endDate; }); } // Recupere les statistiques getStatistics() { if (this.feedbacks.length === 0) { return { total: 0, averageRating: 0, difficultyDistribution: {}, commonDifficulties: [], commonSuggestions: [] }; } const ratings = this.feedbacks.map(fb => parseInt(fb.rating) || 0); const averageRating = ratings.reduce((a, b) => a + b, 0) / ratings.length; // Distribution des difficultes const difficultyDistribution = {}; this.feedbacks.forEach(fb => { const diff = fb.difficulty || 'non-specifie'; difficultyDistribution[diff] = (difficultyDistribution[diff] || 0) + 1; }); // Points difficiles communs const difficultyCount = {}; this.feedbacks.forEach(fb => { if (fb.difficiles && Array.isArray(fb.difficiles)) { fb.difficiles.forEach(d => { difficultyCount[d] = (difficultyCount[d] || 0) + 1; }); } }); const commonDifficulties = Object.entries(difficultyCount) .sort((a, b) => b[1] - a[1]) .slice(0, 5); // Suggestions communes const suggestionCount = {}; this.feedbacks.forEach(fb => { if (fb.suggestions && Array.isArray(fb.suggestions)) { fb.suggestions.forEach(s => { suggestionCount[s] = (suggestionCount[s] || 0) + 1; }); } }); const commonSuggestions = Object.entries(suggestionCount) .sort((a, b) => b[1] - a[1]) .slice(0, 5); return { total: this.feedbacks.length, averageRating: averageRating.toFixed(2), difficultyDistribution, commonDifficulties, commonSuggestions }; } // Exporte les feedbacks vers un fichier JSON exportToFile() { const data = { exportDate: new Date().toISOString(), totalFeedbacks: this.feedbacks.length, feedbacks: this.feedbacks, statistics: this.getStatistics() }; const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' }); const url = URL.createObjectURL(blob); // Stocke l'URL pour telechargement ulterieur this.lastExportUrl = url; return url; } // Telecharge le fichier JSON downloadFeedbacks() { const url = this.exportToFile(); const a = document.createElement('a'); a.href = url; a.download = `ml_academy_feedbacks_${new Date().toISOString().split('T')[0]}.json`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); } // Exporte vers CSV pour Excel exportToCSV() { if (this.feedbacks.length === 0) return null; const headers = [ 'ID', 'Date', 'Nom', 'Email', 'Projet', 'Note', 'Difficulte', 'Rythme', 'Parties Utiles', 'Points Difficiles', 'Question Principale', 'Commentaire' ]; const rows = this.feedbacks.map(fb => [ fb.id, fb.timestamp, fb.name || '', fb.email || '', fb.project || '', fb.rating || '', fb.difficulty || '', fb.rythme || '', (fb.utiles || []).join(';'), (fb.difficiles || []).join(';'), (fb.mainQuestion || '').replace(/"/g, '""'), (fb.freeComment || '').replace(/"/g, '""') ]); const csv = [ headers.join(','), ...rows.map(row => row.map(cell => `"${cell}"`).join(',')) ].join('\n'); const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `ml_academy_feedbacks_${new Date().toISOString().split('T')[0]}.csv`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); } // Efface tous les feedbacks (avec confirmation) clearAll() { if (confirm('Attention : Cette action supprimera tous les feedbacks. Continuer ?')) { this.feedbacks = []; this.saveFeedbacks(); return true; } return false; } } // Instance globale const feedbackStorage = new FeedbackStorage(); // Fonction pour soumettre un feedback depuis le formulaire function submitFeedback(formData) { const feedback = feedbackStorage.addFeedback(formData); console.log('Feedback enregistre:', feedback); return feedback; } // Fonction pour afficher les statistiques dans la console function showFeedbackStats() { const stats = feedbackStorage.getStatistics(); console.log('=== Statistiques des Feedbacks ==='); console.log(`Total: ${stats.total}`); console.log(`Note moyenne: ${stats.averageRating}/5`); console.log('Distribution des difficultes:', stats.difficultyDistribution); console.log('Points difficiles communs:', stats.commonDifficulties); console.log('Suggestions communes:', stats.commonSuggestions); return stats; } // Exporte pour utilisation externe window.FeedbackStorage = FeedbackStorage; window.feedbackStorage = feedbackStorage; window.submitFeedback = submitFeedback; window.showFeedbackStats = showFeedbackStats;