import { BarChart3, Trash2, Clock, Users, MessageSquare, Video, Mic, ChevronDown, ChevronUp, Hand, BarChart2, Download } from 'lucide-react'; import { useState } from 'react'; import api from '../services/api'; import { useLanguage } from '../contexts/LanguageContext'; import toast from 'react-hot-toast'; export default function AnalyticsList({ analytics, onRefresh, isOwner = true }) { const [loading, setLoading] = useState({}); const [expanded, setExpanded] = useState({}); const [exportMenu, setExportMenu] = useState({}); const { t, language } = useLanguage(); const formatDate = (dateStr) => { if (!dateStr) return '—'; return new Date(dateStr).toLocaleDateString(language === 'de' ? 'de-DE' : 'en-US', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', }); }; const formatDurationSec = (sec) => { if (!sec || sec <= 0) return '0m'; const minutes = Math.floor(sec / 60); const hours = Math.floor(minutes / 60); const mins = minutes % 60; const secs = sec % 60; if (hours > 0) return `${hours}h ${mins}m`; if (minutes > 0) return `${mins}m ${secs}s`; return `${secs}s`; }; const handleDelete = async (id) => { if (!confirm(t('analytics.deleteConfirm'))) return; setLoading(prev => ({ ...prev, [id]: 'deleting' })); try { await api.delete(`/analytics/${id}`); toast.success(t('analytics.deleted')); onRefresh?.(); } catch { toast.error(t('analytics.deleteFailed')); } finally { setLoading(prev => ({ ...prev, [id]: null })); } }; const toggleExpand = (id) => { setExpanded(prev => ({ ...prev, [id]: !prev[id] })); }; const toggleExportMenu = (id) => { setExportMenu(prev => ({ ...prev, [id]: !prev[id] })); }; const handleExport = async (id, format) => { setExportMenu(prev => ({ ...prev, [id]: false })); setLoading(prev => ({ ...prev, [id]: 'exporting' })); try { const response = await api.get(`/analytics/${id}/export/${format}`, { responseType: 'blob' }); const disposition = response.headers['content-disposition']; const match = disposition?.match(/filename="?([^"]+)"?/); const filename = match?.[1] || `analytics.${format}`; const url = window.URL.createObjectURL(response.data); const a = document.createElement('a'); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); a.remove(); window.URL.revokeObjectURL(url); toast.success(t('analytics.exportSuccess')); } catch { toast.error(t('analytics.exportFailed')); } finally { setLoading(prev => ({ ...prev, [id]: null })); } }; // Extract user summary from BBB learning analytics callback data // Payload: { meeting_id, data: { duration, start, finish, attendees: [{ name, moderator, duration, engagement: { chats, talks, raisehand, emojis, poll_votes, talk_time } }] } } const getUserSummary = (data) => { const attendees = data?.data?.attendees; if (!Array.isArray(attendees)) return []; return attendees.map(a => ({ name: a.name || '—', isModerator: !!a.moderator, duration: a.duration || 0, talkTime: a.engagement?.talk_time || 0, chats: a.engagement?.chats || 0, talks: a.engagement?.talks || 0, raiseHand: a.engagement?.raisehand || 0, emojis: a.engagement?.emojis || 0, pollVotes: a.engagement?.poll_votes || 0, })); }; const getMeetingSummary = (data) => ({ duration: data?.data?.duration || 0, start: data?.data?.start || null, finish: data?.data?.finish || null, files: data?.data?.files || [], polls: data?.data?.polls || [], }); if (!analytics || analytics.length === 0) { return (

{t('analytics.noData')}

); } return (
{analytics.map(entry => { const users = getUserSummary(entry.data); const meeting = getMeetingSummary(entry.data); const isExpanded = expanded[entry.id]; const totalParticipants = users.length; const totalMessages = users.reduce((sum, u) => sum + u.chats, 0); return (

{entry.meetingName || entry.meetingId}

{meeting.start ? formatDate(meeting.start) : formatDate(entry.createdAt)} {formatDurationSec(meeting.duration)} {totalParticipants} {t('analytics.participants')} {totalMessages} {t('analytics.messages')}
{exportMenu[entry.id] && (
)}
{isOwner && ( )}
{isExpanded && users.length > 0 && (
{users.map((u, i) => ( ))}
{t('analytics.userName')} {t('analytics.role')} {t('analytics.duration')} {t('analytics.talkTime')} {t('analytics.messages')} {t('analytics.raiseHand')} {t('analytics.reactions')}
{u.name} {u.isModerator ? t('analytics.moderator') : t('analytics.viewer')} {formatDurationSec(u.duration)} {formatDurationSec(u.talkTime)} {u.chats} {u.raiseHand} {u.emojis}
)}
); })}
); }