Team Communication Optimizer
Overall Communication Score
0
out of 100
Communication Types
Recent Communication Log
Log a New Communication
Manage Teams
Manage Team Members
No communication logs for this period.
'; } function renderCommTypeChart(labels, data) { const ctx = document.getElementById('comm-type-chart').getContext('2d'); if (commTypeChart) { commTypeChart.destroy(); } commTypeChart = new Chart(ctx, { type: 'doughnut', data: { labels: labels, datasets: [{ data: data, backgroundColor: ['#3b82f6', '#10b981', '#f97316', '#8b5cf6', '#ec4899', '#64748b'], borderColor: '#ffffff', borderWidth: 2 }] }, options: { responsive: true, maintainAspectRatio: true, plugins: { legend: { position: 'bottom' } } } }); } function renderLogForm() { logMemberSelect.innerHTML = state.members.map(m => ``).join(''); logTypeSelect.innerHTML = Object.keys(COMM_TYPES).map(key => ``).join(''); } function renderConfiguration() { teamsList.innerHTML = state.teams.map(team => `
${team.name}
`).join('') || 'No teams created.
'; memberTeamSelect.innerHTML = state.teams.map(t => ``).join(''); membersList.innerHTML = state.members.map(member => { const team = state.teams.find(t => t.id === member.teamId); return `
${member.name} (${team?.name || 'No team'})
`}).join('') || 'No members added.
'; } // SECTION: Event Handlers function handleTabClick(tabName) { state.activeTab = tabName; render(); } function handleNavClick(dir) { const i = TABS.indexOf(state.activeTab); const newI = i + dir; if (newI >= 0 && newI < TABS.length) { state.activeTab = TABS[newI]; render(); } } function handleAddTeam(e) { e.preventDefault(); const name = teamNameInput.value.trim(); if (name) { const newTeam = { id: Date.now(), name }; state.teams.push(newTeam); if (state.teams.length === 1) state.selectedTeamId = newTeam.id; teamNameInput.value = ''; saveState(); render(); } } function handleDeleteTeam(teamId) { state.teams = state.teams.filter(t => t.id !== teamId); state.members = state.members.filter(m => m.teamId !== teamId); if (state.selectedTeamId === teamId) { state.selectedTeamId = state.teams.length > 0 ? state.teams[0].id : null; } saveState(); render(); } function handleAddMember(e) { e.preventDefault(); const name = memberNameInput.value.trim(); const teamId = parseInt(memberTeamSelect.value); if (name && teamId) { state.members.push({ id: Date.now(), name, teamId }); memberNameInput.value = ''; saveState(); render(); } } function handleDeleteMember(memberId) { state.members = state.members.filter(m => m.id !== memberId); saveState(); render(); } function handleLogSubmit(e) { e.preventDefault(); const log = { id: Date.now(), memberId: parseInt(logMemberSelect.value), type: logTypeSelect.value, clarity: parseInt(logClarityInput.value), sentiment: logSentimentSelect.value, notes: logNotesTextarea.value.trim(), date: new Date().toISOString() }; state.logs.push(log); saveState(); logCommForm.reset(); alert('Communication logged!'); state.activeTab = 'dashboard'; render(); } function handleFilterChange() { state.selectedTeamId = parseInt(teamFilter.value); state.dateRange = dateRangeFilter.value; renderDashboard(); } function generatePDF() { const { jsPDF } = window.jspdf; const doc = new jsPDF({ orientation: 'p', unit: 'mm', format: 'a4' }); if (!state.selectedTeamId) { alert("Please select a team."); return; } const selectedTeam = state.teams.find(t => t.id === state.selectedTeamId); const date = new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' }); const filteredLogs = getFilteredLogs(); doc.setFontSize(22); doc.setFont('helvetica', 'bold'); doc.text('Communication Analysis Report', 105, 20, { align: 'center' }); doc.setFontSize(16); doc.setFont('helvetica', 'normal'); doc.text(`Team: ${selectedTeam.name}`, 105, 30, { align: 'center' }); doc.setFontSize(10); doc.setTextColor(150); doc.text(`Report Generated: ${date}`, 105, 35, { align: 'center' }); doc.setFontSize(14); doc.setFont('helvetica', 'bold'); doc.setTextColor(40); doc.text('Summary', 14, 50); doc.setLineWidth(0.5); doc.line(14, 52, 196, 52); doc.setFontSize(11); doc.setFont('helvetica', 'normal'); doc.text(`Overall Communication Score: ${commScoreEl.textContent}/100`, 14, 60); doc.text(`Total Interactions Logged (${state.dateRange} days): ${filteredLogs.length}`, 14, 67); if (commTypeChart && commTypeChart.canvas) { const chartImage = commTypeChart.canvas.toDataURL('image/png'); doc.addImage(chartImage, 'PNG', 14, 75, 80, 80); } const tableHead = [['Date', 'Member', 'Type', 'Clarity', 'Sentiment', 'Notes']]; const tableBody = filteredLogs.map(log => { const member = state.members.find(m => m.id === log.memberId); return [ new Date(log.date).toLocaleDateString(), member?.name || 'N/A', COMM_TYPES[log.type]?.label || log.type, `${log.clarity}/5`, log.sentiment.charAt(0).toUpperCase() + log.sentiment.slice(1), log.notes ]; }); doc.autoTable({ head: tableHead, body: tableBody, startY: 165, theme: 'grid', headStyles: { fillColor: [37, 99, 235] }, didDrawPage: data => { doc.setFontSize(8); doc.setTextColor(150); doc.text('Page ' + data.pageNumber, data.settings.margin.left, doc.internal.pageSize.height - 10); } }); doc.save(`${selectedTeam.name}_Comm_Report_${new Date().toISOString().slice(0, 10)}.pdf`); } // SECTION: Event Listeners Object.keys(tabButtons).forEach(id => tabButtons[id]?.addEventListener('click', () => handleTabClick(id))); prevTabBtn?.addEventListener('click', () => handleNavClick(-1)); nextTabBtn?.addEventListener('click', () => handleNavClick(1)); teamFilter?.addEventListener('change', handleFilterChange); dateRangeFilter?.addEventListener('change', handleFilterChange); downloadPdfBtn?.addEventListener('click', generatePDF); logCommForm?.addEventListener('submit', handleLogSubmit); addTeamForm?.addEventListener('submit', handleAddTeam); addMemberForm?.addEventListener('submit', handleAddMember); teamsList?.addEventListener('click', e => { if (e.target.classList.contains('delete-team-btn')) { if (confirm('Delete this team and all its members?')) handleDeleteTeam(parseInt(e.target.dataset.id)); } }); membersList?.addEventListener('click', e => { if (e.target.classList.contains('delete-member-btn')) { if (confirm('Delete this member?')) handleDeleteMember(parseInt(e.target.dataset.id)); } }); // SECTION: Initial Load loadState(); render(); });