| |
| |
| |
| |
|
|
| class FeedbackStorage { |
| constructor() { |
| this.storageKey = 'ml_academy_feedbacks'; |
| this.feedbacks = this.loadFeedbacks(); |
| } |
|
|
| |
| 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 []; |
| } |
| } |
|
|
| |
| 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; |
| } |
| } |
|
|
| |
| addFeedback(feedbackData) { |
| const feedback = { |
| id: this.generateId(), |
| timestamp: new Date().toISOString(), |
| ...feedbackData |
| }; |
| |
| this.feedbacks.push(feedback); |
| this.saveFeedbacks(); |
| |
| |
| this.exportToFile(); |
| |
| return feedback; |
| } |
|
|
| |
| generateId() { |
| return 'fb_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9); |
| } |
|
|
| |
| getAllFeedbacks() { |
| return this.feedbacks; |
| } |
|
|
| |
| getFeedbacksByDateRange(startDate, endDate) { |
| return this.feedbacks.filter(fb => { |
| const fbDate = new Date(fb.timestamp); |
| return fbDate >= startDate && fbDate <= endDate; |
| }); |
| } |
|
|
| |
| 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; |
|
|
| |
| const difficultyDistribution = {}; |
| this.feedbacks.forEach(fb => { |
| const diff = fb.difficulty || 'non-specifie'; |
| difficultyDistribution[diff] = (difficultyDistribution[diff] || 0) + 1; |
| }); |
|
|
| |
| 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); |
|
|
| |
| 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 |
| }; |
| } |
|
|
| |
| 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); |
| |
| |
| this.lastExportUrl = url; |
| |
| return url; |
| } |
|
|
| |
| 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); |
| } |
|
|
| |
| 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); |
| } |
|
|
| |
| clearAll() { |
| if (confirm('Attention : Cette action supprimera tous les feedbacks. Continuer ?')) { |
| this.feedbacks = []; |
| this.saveFeedbacks(); |
| return true; |
| } |
| return false; |
| } |
| } |
|
|
| |
| const feedbackStorage = new FeedbackStorage(); |
|
|
| |
| function submitFeedback(formData) { |
| const feedback = feedbackStorage.addFeedback(formData); |
| console.log('Feedback enregistre:', feedback); |
| return feedback; |
| } |
|
|
| |
| 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; |
| } |
|
|
| |
| window.FeedbackStorage = FeedbackStorage; |
| window.feedbackStorage = feedbackStorage; |
| window.submitFeedback = submitFeedback; |
| window.showFeedbackStats = showFeedbackStats; |
|
|