Spaces:
Build error
Build error
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>AI Coach Dashboard</title> | |
<style> | |
body { | |
font-family: 'Roboto', Arial, sans-serif; | |
margin: 0; | |
padding: 0; | |
background: linear-gradient(135deg, #f0f2f5 0%, #e9ecef 100%); | |
color: #2d3748; | |
line-height: 1.6; | |
} | |
.header { | |
background: linear-gradient(to right, #1a3c7a, #2957a4); | |
padding: 15px 25px; | |
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); | |
position: sticky; | |
top: 0; | |
z-index: 100; | |
} | |
.header-title { | |
color: #fff; | |
margin: 0; | |
font-size: 26px; | |
font-weight: 700; | |
text-align: center; | |
padding-bottom: 10px; | |
} | |
.header-actions { | |
display: flex; | |
align-items: center; | |
justify-content: space-between; | |
gap: 20px; | |
} | |
.avatar { | |
width: 42px; | |
height: 42px; | |
background: linear-gradient(to right, #f6ad55, #ed8936); | |
color: #fff; | |
border-radius: 50%; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
font-size: 20px; | |
font-weight: 600; | |
cursor: pointer; | |
position: relative; | |
transition: transform 0.2s ease; | |
} | |
.avatar:hover { | |
transform: scale(1.05); | |
background: linear-gradient(to right, #ed8936, #dd6b20); | |
} | |
.dropdown { | |
display: none; | |
position: absolute; | |
top: 50px; | |
right: 0; | |
background-color: #fff; | |
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.1); | |
border-radius: 10px; | |
min-width: 160px; | |
z-index: 101; | |
overflow: hidden; | |
} | |
.dropdown.active { | |
display: block; | |
} | |
.dropdown a { | |
display: block; | |
padding: 12px 20px; | |
color: #2d3748; | |
text-decoration: none; | |
font-size: 15px; | |
transition: background 0.3s ease; | |
} | |
.dropdown a:hover { | |
background-color: #f7fafc; | |
} | |
.search-container { | |
position: relative; | |
flex: 1; | |
max-width: 500px; | |
} | |
.search-bar { | |
width: 100%; | |
padding: 12px 45px 12px 20px; | |
border: 2px solid #e2e8f0; | |
border-radius: 25px; | |
font-size: 15px; | |
box-sizing: border-box; | |
transition: border-color 0.3s ease, box-shadow 0.3s ease; | |
background-color: #fff; | |
} | |
.search-bar:focus { | |
border-color: #ed8936; | |
outline: none; | |
box-shadow: 0 0 8px rgba(237, 137, 54, 0.3); | |
} | |
.mic-icon { | |
position: absolute; | |
right: 15px; | |
top: 50%; | |
transform: translateY(-50%); | |
width: 22px; | |
height: 22px; | |
background: url('https://img.icons8.com/ios-filled/50/000000/microphone.png') no-repeat center; | |
background-size: contain; | |
cursor: pointer; | |
opacity: 0.6; | |
transition: opacity 0.3s ease; | |
} | |
.mic-icon:hover { | |
opacity: 1; | |
} | |
.search-results { | |
position: absolute; | |
top: 50px; | |
left: 0; | |
right: 0; | |
background-color: #fff; | |
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.1); | |
border-radius: 10px; | |
max-height: 220px; | |
overflow-y: auto; | |
z-index: 100; | |
display: none; | |
} | |
.search-results.active { | |
display: block; | |
} | |
.search-results p { | |
padding: 10px 15px; | |
margin: 0; | |
font-size: 14px; | |
color: #4a5568; | |
border-bottom: 1px solid #edf2f7; | |
transition: background 0.2s ease; | |
} | |
.search-results p:hover { | |
background-color: #f7fafc; | |
} | |
.search-results p:last-child { | |
border-bottom: none; | |
} | |
.action-bar { | |
background-color: #fff; | |
padding: 15px 25px; | |
display: flex; | |
justify-content: center; | |
gap: 20px; | |
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); | |
position: sticky; | |
top: 90px; | |
z-index: 99; | |
} | |
.container { | |
max-width: 1200px; | |
margin: 40px auto; | |
padding: 0 25px; | |
} | |
.content-grid { | |
display: grid; | |
grid-template-columns: 1fr 1fr; | |
gap: 30px; | |
margin-bottom: 40px; | |
} | |
.section { | |
padding: 25px; | |
background-color: #fff; | |
border-radius: 12px; | |
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); | |
border-left: 5px solid #ed8936; | |
transition: transform 0.2s ease, box-shadow 0.3s ease; | |
} | |
.section:hover { | |
transform: translateY(-5px); | |
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.1); | |
} | |
.section.full-width { | |
grid-column: span 2; | |
} | |
h3 { | |
margin: 0 0 20px 0; | |
color: #1a3c7a; | |
font-size: 22px; | |
font-weight: 600; | |
display: flex; | |
align-items: center; | |
gap: 10px; | |
} | |
h3 i { | |
font-size: 20px; | |
color: #ed8936; | |
} | |
/* Daily Checklist Section */ | |
.checklist-header { | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
margin-bottom: 20px; | |
} | |
.progress-circle { | |
width: 50px; | |
height: 50px; | |
background: conic-gradient(#ed8936 var(--progress), #e2e8f0 0); | |
border-radius: 50%; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
font-size: 14px; | |
font-weight: 600; | |
color: #2d3748; | |
position: relative; | |
} | |
.progress-circle::before { | |
content: ''; | |
position: absolute; | |
width: 40px; | |
height: 40px; | |
background-color: #fff; | |
border-radius: 50%; | |
} | |
.progress-circle span { | |
position: relative; | |
z-index: 1; | |
} | |
.checklist-item { | |
display: flex; | |
align-items: center; | |
margin-bottom: 15px; | |
font-size: 16px; | |
padding: 10px; | |
border-radius: 8px; | |
transition: background 0.2s ease; | |
} | |
.checklist-item:hover { | |
background-color: #f7fafc; | |
} | |
.checklist-item input { | |
width: 20px; | |
height: 20px; | |
margin-right: 15px; | |
accent-color: #ed8936; | |
cursor: pointer; | |
} | |
.checklist-item label { | |
flex: 1; | |
color: #4a5568; | |
cursor: pointer; | |
} | |
.checklist-item.completed label { | |
text-decoration: line-through; | |
color: #a0aec0; | |
} | |
/* Focus Tips Section */ | |
.tip-card { | |
background: linear-gradient(145deg, #e6f0fa, #d1e3ff); | |
padding: 20px; | |
border-radius: 10px; | |
margin-bottom: 15px; | |
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05); | |
transition: transform 0.2s ease; | |
} | |
.tip-card:hover { | |
transform: translateY(-3px); | |
} | |
.tip-card h4 { | |
margin: 0 0 15px 0; | |
color: #1a3c7a; | |
font-size: 18px; | |
font-weight: 600; | |
} | |
.tip-card ul { | |
padding-left: 20px; | |
margin: 0; | |
list-style-type: disc; | |
} | |
.tip-card li { | |
margin-bottom: 10px; | |
font-size: 15px; | |
color: #4a5568; | |
} | |
/* Supervisor Data Section */ | |
pre { | |
background-color: #f7fafc; | |
padding: 15px; | |
border: 1px solid #e2e8f0; | |
border-radius: 8px; | |
white-space: pre-wrap; | |
font-size: 15px; | |
max-height: 250px; | |
overflow-y: auto; | |
color: #4a5568; | |
} | |
/* Reflection Journal Section */ | |
.reflection-journal { | |
display: flex; | |
flex-direction: column; | |
gap: 20px; | |
} | |
.reflection-input-area { | |
display: flex; | |
flex-direction: column; | |
gap: 15px; | |
} | |
.reflection-journal textarea { | |
width: 100%; | |
height: 120px; | |
padding: 15px; | |
border: 2px solid #e2e8f0; | |
border-radius: 10px; | |
resize: none; | |
font-size: 15px; | |
box-sizing: border-box; | |
transition: border-color 0.3s ease, box-shadow 0.3s ease; | |
background-color: #f7fafc; | |
} | |
.reflection-journal textarea:focus { | |
border-color: #ed8936; | |
outline: none; | |
box-shadow: 0 0 8px rgba(237, 137, 54, 0.3); | |
} | |
.reflection-history { | |
max-height: 200px; | |
overflow-y: auto; | |
padding: 15px; | |
background-color: #f7fafc; | |
border-radius: 10px; | |
border: 1px solid #e2e8f0; | |
} | |
.reflection-entry { | |
margin-bottom: 15px; | |
padding-bottom: 10px; | |
border-bottom: 1px solid #e2e8f0; | |
font-size: 14px; | |
color: #4a5568; | |
} | |
.reflection-entry:last-child { | |
border-bottom: none; | |
margin-bottom: 0; | |
} | |
.reflection-entry span { | |
font-weight: 600; | |
color: #2d3748; | |
} | |
/* KPI Summary Dashboard Section */ | |
.kpi-dashboard { | |
display: grid; | |
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); | |
gap: 20px; | |
padding: 20px; | |
background: linear-gradient(145deg, #fff, #f7fafc); | |
border-radius: 12px; | |
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); | |
} | |
.kpi-card { | |
padding: 20px; | |
border-radius: 10px; | |
background-color: #fff; | |
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); | |
text-align: center; | |
transition: transform 0.2s ease; | |
} | |
.kpi-card:hover { | |
transform: translateY(-3px); | |
} | |
.kpi-card h4 { | |
margin: 0 0 10px 0; | |
font-size: 16px; | |
color: #1a3c7a; | |
font-weight: 600; | |
} | |
.kpi-value { | |
font-size: 24px; | |
font-weight: 700; | |
color: #ed8936; | |
margin-bottom: 10px; | |
} | |
.progress-bar { | |
width: 100%; | |
height: 8px; | |
background-color: #e2e8f0; | |
border-radius: 4px; | |
overflow: hidden; | |
} | |
.progress-fill { | |
height: 100%; | |
background: linear-gradient(to right, #ed8936, #f6ad55); | |
transition: width 0.5s ease; | |
} | |
.kpi-trend { | |
font-size: 13px; | |
color: #718096; | |
margin-top: 8px; | |
} | |
.kpi-flag { | |
display: inline-block; | |
padding: 5px 10px; | |
border-radius: 5px; | |
font-size: 12px; | |
font-weight: 600; | |
margin-top: 8px; | |
} | |
.kpi-flag.active { | |
background-color: #48bb78; | |
color: #fff; | |
} | |
.kpi-flag.inactive { | |
background-color: #f56565; | |
color: #fff; | |
} | |
/* Buttons */ | |
button { | |
padding: 12px 25px; | |
background: linear-gradient(to right, #f6ad55, #ed8936); | |
color: #fff; | |
border: none; | |
border-radius: 8px; | |
cursor: pointer; | |
font-size: 15px; | |
font-weight: 600; | |
transition: transform 0.1s ease, background 0.3s ease; | |
} | |
button:hover { | |
background: linear-gradient(to right, #ed8936, #dd6b20); | |
transform: scale(1.02); | |
} | |
.download-btn { | |
background: linear-gradient(to right, #38a169, #48bb78); | |
} | |
.download-btn:hover { | |
background: linear-gradient(to right, #2f855a, #38a169); | |
} | |
/* Toast Notifications */ | |
.toast { | |
position: fixed; | |
top: 20px; | |
right: 20px; | |
padding: 15px 25px; | |
border-radius: 8px; | |
z-index: 102; | |
display: none; | |
font-size: 15px; | |
font-weight: 500; | |
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); | |
} | |
.toast.error { | |
background-color: #f56565; | |
color: #fff; | |
} | |
.toast.success { | |
background-color: #48bb78; | |
color: #fff; | |
} | |
.toast.visible { | |
display: block; | |
} | |
/* Responsive Design */ | |
@media (max-width: 900px) { | |
.content-grid { | |
grid-template-columns: 1fr; | |
} | |
.section.full-width { | |
grid-column: span 1; | |
} | |
.kpi-dashboard { | |
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); | |
} | |
} | |
@media (max-width: 700px) { | |
body { | |
padding: 0; | |
} | |
.header { | |
padding: 10px 15px; | |
} | |
.header-title { | |
font-size: 22px; | |
padding-bottom: 8px; | |
} | |
.header-actions { | |
flex-wrap: wrap; | |
gap: 10px; | |
} | |
.search-container { | |
flex: 100%; | |
max-width: 100%; | |
} | |
.avatar { | |
width: 38px; | |
height: 38px; | |
font-size: 18px; | |
} | |
.dropdown { | |
top: 48px; | |
min-width: 140px; | |
} | |
.action-bar { | |
top: 70px; | |
flex-direction: column; | |
gap: 10px; | |
padding: 10px 15px; | |
} | |
.container { | |
padding: 20px 15px; | |
margin: 15px 0; | |
} | |
h3 { | |
font-size: 20px; | |
} | |
.section { | |
padding: 20px; | |
} | |
.progress-circle { | |
width: 40px; | |
height: 40px; | |
font-size: 12px; | |
} | |
.progress-circle::before { | |
width: 32px; | |
height: 32px; | |
} | |
.checklist-item, .tip-card li, .reflection-journal textarea, pre { | |
font-size: 14px; | |
} | |
.kpi-value { | |
font-size: 20px; | |
} | |
.kpi-card h4 { | |
font-size: 14px; | |
} | |
button { | |
width: 100%; | |
padding: 10px; | |
font-size: 14px; | |
} | |
.toast { | |
top: 10px; | |
right: 10px; | |
padding: 10px 15px; | |
font-size: 14px; | |
} | |
} | |
</style> | |
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap" rel="stylesheet"> | |
</head> | |
<body> | |
<div class="header"> | |
<h2 class="header-title">AI Coach Dashboard</h2> | |
<div class="header-actions"> | |
<div class="search-container"> | |
<input type="text" class="search-bar" id="search-bar" placeholder="Search checklists, tips, reflections..."> | |
<div class="mic-icon" onclick="simulateVoiceSearch()"></div> | |
<div class="search-results" id="search-results"></div> | |
</div> | |
<div class="avatar" id="avatar" onclick="toggleDropdown()">?</div> | |
<div class="dropdown" id="dropdown"> | |
<a href="#" onclick="viewProfile()">View Profile</a> | |
<a href="#" onclick="logout()">Logout</a> | |
</div> | |
</div> | |
</div> | |
<div class="action-bar"> | |
<button onclick="generateCoaching()">Generate Coaching Output</button> | |
<button class="download-btn" onclick="downloadPDF()" id="download-btn">Download PDF Summary</button> | |
</div> | |
<div class="container"> | |
<div class="content-grid"> | |
<!-- Daily Checklist Section --> | |
<div class="section checklist-section"> | |
<div class="checklist-header"> | |
<h3><i>📋</i> Daily Checklist</h3> | |
<div class="progress-circle" id="checklist-progress"><span>0%</span></div> | |
</div> | |
<div id="checklist-items"></div> | |
</div> | |
<!-- Focus Tips Section --> | |
<div class="section tips-section"> | |
<h3><i>💡</i> Today's Top 3 Focus Areas</h3> | |
<div id="focus-tips"></div> | |
</div> | |
<!-- Supervisor Data Section --> | |
<div class="section full-width"> | |
<h3><i>📊</i> Supervisor Data</h3> | |
<pre id="supervisor-data">Loading supervisor data...</pre> | |
</div> | |
<!-- Reflection Journal Section --> | |
<div class="section full-width reflection-journal"> | |
<h3><i>📝</i> Reflection Journal</h3> | |
<div class="reflection-input-area"> | |
<textarea id="reflection-input" placeholder="Log your reflections for today..."></textarea> | |
<button onclick="submitReflection()">Submit Reflection</button> | |
</div> | |
<div class="reflection-history" id="reflection-history"> | |
<p>No reflections yet. Start logging your thoughts!</p> | |
</div> | |
</div> | |
<!-- KPI Summary Dashboard Section --> | |
<div class="section full-width kpi-section"> | |
<h3><i>📈</i> KPI Summary Dashboard</h3> | |
<div class="kpi-dashboard" id="kpi-dashboard"> | |
<!-- KPIs will be populated dynamically --> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Toast Notifications --> | |
<div id="error" class="toast error"></div> | |
<div id="success" class="toast success"></div> | |
<script> | |
let supervisorData = null; | |
let coachingOutput = null; | |
let reflectionHistory = []; | |
let checklistProgress = 0; | |
let totalChecklistItems = 0; | |
// Toast Notification Function | |
function showToast(id, message) { | |
const toast = document.getElementById(id); | |
toast.textContent = message; | |
toast.classList.add('visible'); | |
setTimeout(() => { | |
toast.classList.remove('visible'); | |
}, 3000); | |
} | |
// Set Avatar Initial | |
async function setAvatar() { | |
const avatar = document.getElementById('avatar'); | |
try { | |
const response = await fetch('/get_supervisor_data'); | |
const result = await response.json(); | |
if (result.status === 'success' && result.data.supervisor_id !== 'GUEST') { | |
const username = result.data.supervisor_id.split('_')[1] || 'User'; | |
avatar.textContent = username.charAt(0).toUpperCase(); | |
} else { | |
avatar.textContent = 'G'; | |
} | |
} catch (error) { | |
avatar.textContent = 'U'; | |
} | |
} | |
// Dropdown Toggle | |
function toggleDropdown() { | |
const dropdown = document.getElementById('dropdown'); | |
dropdown.classList.toggle('active'); | |
} | |
function viewProfile() { | |
showToast('error', 'Profile view not implemented yet.'); | |
} | |
async function logout() { | |
try { | |
const response = await fetch('/logout', { | |
method: 'POST', | |
headers: { 'Content-Type': 'application/json' } | |
}); | |
const result = await response.json(); | |
if (result.status === 'success') { | |
window.location.href = '/login'; | |
} else { | |
showToast('error', result.message); | |
} | |
} catch (error) { | |
showToast('error', 'Error during logout: ' + error.message); | |
} | |
} | |
// Search Functionality | |
function searchData() { | |
const query = document.getElementById('search-bar').value.toLowerCase().trim(); | |
const resultsDiv = document.getElementById('search-results'); | |
resultsDiv.innerHTML = ''; | |
resultsDiv.classList.remove('active'); | |
if (!query) return; | |
const searchableContent = []; | |
if (coachingOutput && coachingOutput.checklist) { | |
coachingOutput.checklist.forEach(item => searchableContent.push(`Checklist: ${item}`)); | |
} | |
if (coachingOutput && coachingOutput.tips) { | |
coachingOutput.tips.forEach(tip => searchableContent.push(`Tip: ${tip}`)); | |
} | |
if (supervisorData && supervisorData.reflection_log) { | |
searchableContent.push(`Reflection: ${supervisorData.reflection_log}`); | |
} | |
if (reflectionHistory.length > 0) { | |
reflectionHistory.forEach(ref => searchableContent.push(`Past Reflection: ${ref.text}`)); | |
} | |
const results = searchableContent.filter(item => item.toLowerCase().includes(query)); | |
if (results.length > 0) { | |
results.forEach(result => { | |
const p = document.createElement('p'); | |
p.textContent = result; | |
resultsDiv.appendChild(p); | |
}); | |
resultsDiv.classList.add('active'); | |
} else { | |
const p = document.createElement('p'); | |
p.textContent = 'No results found.'; | |
resultsDiv.appendChild(p); | |
resultsDiv.classList.add('active'); | |
} | |
} | |
function simulateVoiceSearch() { | |
showToast('error', 'Voice search not implemented yet.'); | |
} | |
// Update Checklist Progress | |
function updateChecklistProgress() { | |
const completedItems = document.querySelectorAll('.checklist-item.completed').length; | |
checklistProgress = totalChecklistItems > 0 ? (completedItems / totalChecklistItems) * 100 : 0; | |
const progressCircle = document.getElementById('checklist-progress'); | |
progressCircle.style.setProperty('--progress', `${checklistProgress}%`); | |
progressCircle.querySelector('span').textContent = `${Math.round(checklistProgress)}%`; | |
} | |
async function fetchSupervisorData() { | |
try { | |
const response = await fetch('/get_supervisor_data'); | |
const result = await response.json(); | |
if (result.status === 'success') { | |
supervisorData = result.data; | |
document.getElementById('supervisor-data').textContent = JSON.stringify(supervisorData, null, 2); | |
// Populate Daily Checklist from Salesforce | |
const checklistDiv = document.getElementById('checklist-items'); | |
if (supervisorData.daily_checklist) { | |
const checklistItems = supervisorData.daily_checklist.split('\n').filter(item => item.trim()); | |
totalChecklistItems = checklistItems.length; | |
checklistDiv.innerHTML = ''; | |
checklistItems.forEach((item, index) => { | |
const itemDiv = document.createElement('div'); | |
itemDiv.className = 'checklist-item'; | |
itemDiv.innerHTML = ` | |
<input type="checkbox" id="checklist-${index}" onchange="markComplete(${index}, this)"> | |
<label for="checklist-${index}">${item}</label> | |
`; | |
checklistDiv.appendChild(itemDiv); | |
}); | |
updateChecklistProgress(); | |
} else { | |
checklistDiv.innerHTML = '<p>No checklist items available.</p>'; | |
} | |
// Populate Focus Tips from Salesforce | |
const tipsDiv = document.getElementById('focus-tips'); | |
if (supervisorData.suggested_tips) { | |
const tips = supervisorData.suggested_tips.split('\n').filter(tip => tip.trim()); | |
tipsDiv.innerHTML = ''; | |
const tipCard = document.createElement('div'); | |
tipCard.className = 'tip-card'; | |
tipCard.innerHTML = ` | |
<h4>Today's Top 3 Focus Areas</h4> | |
<ul> | |
${tips.map(tip => `<li>${tip}</li>`).join('')} | |
</ul> | |
`; | |
tipsDiv.appendChild(tipCard); | |
} else { | |
tipsDiv.innerHTML = '<p>No focus tips available.</p>'; | |
} | |
// Populate Reflection History | |
if (supervisorData.reflection_log) { | |
reflectionHistory.push({ | |
date: new Date().toLocaleString(), | |
text: supervisorData.reflection_log | |
}); | |
updateReflectionHistory(); | |
} | |
// Update Download Link | |
const downloadBtn = document.getElementById('download-btn'); | |
if (supervisorData.download_link) { | |
downloadBtn.onclick = () => window.open(supervisorData.download_link, '_blank'); | |
downloadBtn.textContent = 'Download Report'; | |
} else { | |
downloadBtn.onclick = downloadPDF; | |
downloadBtn.textContent = 'Download PDF Summary'; | |
} | |
updateKPIDashboard(); | |
} else { | |
showToast('error', result.message); | |
document.getElementById('supervisor-data').textContent = 'Failed to load supervisor data.'; | |
} | |
} catch (error) { | |
showToast('error', 'Error fetching supervisor data: ' + error.message); | |
document.getElementById('supervisor-data').textContent = 'Failed to load supervisor data.'; | |
} | |
} | |
async function generateCoaching() { | |
if (!supervisorData) { | |
showToast('error', 'Supervisor data not loaded. Please refresh the page.'); | |
return; | |
} | |
try { | |
const response = await fetch('/generate', { | |
method: 'POST', | |
headers: { 'Content-Type': 'application/json' }, | |
body: JSON.stringify(supervisorData) | |
}); | |
const result = await response.json(); | |
if (result.status === 'success') { | |
coachingOutput = result.output; | |
showToast('success', 'Coaching output generated successfully!'); | |
// Populate Daily Checklist | |
const checklistDiv = document.getElementById('checklist-items'); | |
checklistDiv.innerHTML = ''; | |
if (coachingOutput.checklist && coachingOutput.checklist.length > 0) { | |
totalChecklistItems = coachingOutput.checklist.length; | |
coachingOutput.checklist.forEach((item, index) => { | |
const itemDiv = document.createElement('div'); | |
itemDiv.className = 'checklist-item'; | |
itemDiv.innerHTML = ` | |
<input type="checkbox" id="checklist-${index}" onchange="markComplete(${index}, this)"> | |
<label for="checklist-${index}">${item}</label> | |
`; | |
checklistDiv.appendChild(itemDiv); | |
}); | |
updateChecklistProgress(); | |
} else { | |
checklistDiv.innerHTML = '<p>No checklist items available.</p>'; | |
} | |
// Populate Focus Tips | |
const tipsDiv = document.getElementById('focus-tips'); | |
tipsDiv.innerHTML = ''; | |
if (coachingOutput.tips && coachingOutput.tips.length > 0) { | |
const tipCard = document.createElement('div'); | |
tipCard.className = 'tip-card'; | |
tipCard.innerHTML = ` | |
<h4>Today's Top 3 Focus Areas</h4> | |
<ul> | |
${coachingOutput.tips.map(tip => `<li>${tip}</li>`).join('')} | |
</ul> | |
`; | |
tipsDiv.appendChild(tipCard); | |
} else { | |
tipsDiv.innerHTML = '<p>No focus tips available.</p>'; | |
} | |
updateKPIDashboard(); | |
} else { | |
showToast('error', result.message); | |
document.getElementById('checklist-items').innerHTML = '<p>Failed to generate checklist.</p>'; | |
document.getElementById('focus-tips').innerHTML = '<p>Failed to generate focus tips.</p>'; | |
} | |
} catch (error) { | |
showToast('error', 'Error generating coaching output: ' + error.message); | |
document.getElementById('checklist-items').innerHTML = '<p>Failed to generate checklist.</p>'; | |
document.getElementById('focus-tips').innerHTML = '<p>Failed to generate focus tips.</p>'; | |
} | |
} | |
function markComplete(index, checkbox) { | |
const itemDiv = checkbox.parentElement; | |
if (checkbox.checked) { | |
itemDiv.classList.add('completed'); | |
} else { | |
itemDiv.classList.remove('completed'); | |
} | |
updateChecklistProgress(); | |
showToast('success', `Checklist item ${index + 1} marked as ${checkbox.checked ? 'complete' : 'incomplete'} (simulated).`); | |
} | |
function updateReflectionHistory() { | |
const historyDiv = document.getElementById('reflection-history'); | |
historyDiv.innerHTML = ''; | |
if (reflectionHistory.length > 0) { | |
reflectionHistory.forEach(ref => { | |
const entryDiv = document.createElement('div'); | |
entryDiv.className = 'reflection-entry'; | |
entryDiv.innerHTML = `<span>${ref.date}:</span> ${ref.text}`; | |
historyDiv.appendChild(entryDiv); | |
}); | |
} else { | |
historyDiv.innerHTML = '<p>No reflections yet. Start logging your thoughts!</p>'; | |
} | |
} | |
async function submitReflection() { | |
const reflectionInput = document.getElementById('reflection-input').value.trim(); | |
if (!reflectionInput) { | |
showToast('error', 'Please enter a reflection before submitting.'); | |
return; | |
} | |
if (!supervisorData) { | |
showToast('error', 'Supervisor data not loaded. Please refresh the page.'); | |
return; | |
} | |
try { | |
const response = await fetch('/submit_reflection', { | |
method: 'POST', | |
headers: { 'Content-Type': 'application/json' }, | |
body: JSON.stringify({ reflection: reflectionInput }) | |
}); | |
const result = await response.json(); | |
if (result.status === 'success') { | |
supervisorData.reflection_log = reflectionInput; | |
document.getElementById('supervisor-data').textContent = JSON.stringify(supervisorData, null, 2); | |
reflectionHistory.push({ | |
date: new Date().toLocaleString(), | |
text: reflectionInput | |
}); | |
updateReflectionHistory(); | |
document.getElementById('reflection-input').value = ''; | |
showToast('success', result.message); | |
generateCoaching(); | |
} else { | |
showToast('error', result.message); | |
} | |
} catch (error) { | |
showToast('error', 'Error submitting reflection: ' + error.message); | |
} | |
} | |
function updateKPIDashboard() { | |
const kpiDashboard = document.getElementById('kpi-dashboard'); | |
kpiDashboard.innerHTML = ''; | |
// KPI 1: Engagement Score | |
const engagementScore = supervisorData && supervisorData.engagement_score ? supervisorData.engagement_score : 85; | |
const engagementCard = document.createElement('div'); | |
engagementCard.className = 'kpi-card'; | |
engagementCard.innerHTML = ` | |
<h4>Engagement Score</h4> | |
<div class="kpi-value">${engagementScore}%</div> | |
<div class="progress-bar"> | |
<div class="progress-fill" style="width: ${engagementScore}%"></div> | |
</div> | |
<p class="kpi-trend">Target: 90%</p> | |
`; | |
kpiDashboard.appendChild(engagementCard); | |
// KPI 2: Task Completion Rate | |
const taskCompletionRate = checklistProgress; | |
const taskCard = document.createElement('div'); | |
taskCard.className = 'kpi-card'; | |
taskCard.innerHTML = ` | |
<h4>Task Completion Rate</h4> | |
<div class="kpi-value">${Math.round(taskCompletionRate)}%</div> | |
<div class="progress-bar"> | |
<div class="progress-fill" style="width: ${taskCompletionRate}%"></div> | |
</div> | |
<p class="kpi-trend">Based on Daily Checklist</p> | |
`; | |
kpiDashboard.appendChild(taskCard); | |
// KPI 3: Reflection Frequency | |
const reflectionFrequency = reflectionHistory.length; | |
const reflectionCard = document.createElement('div'); | |
reflectionCard.className = 'kpi-card'; | |
reflectionCard.innerHTML = ` | |
<h4>Reflection Frequency</h4> | |
<div class="kpi-value">${reflectionFrequency}</div> | |
<div class="progress-bar"> | |
<div class="progress-fill" style="width: ${(reflectionFrequency / 5) * 100}%"></div> | |
</div> | |
<p class="kpi-trend">Goal: 5 per week</p> | |
`; | |
kpiDashboard.appendChild(reflectionCard); | |
// KPI 4: KPI Flag | |
const kpiFlag = supervisorData && supervisorData.kpi_flag !== undefined ? supervisorData.kpi_flag : false; | |
const flagCard = document.createElement('div'); | |
flagCard.className = 'kpi-card'; | |
flagCard.innerHTML = ` | |
<h4>KPI Flag Status</h4> | |
<div class="kpi-value"> | |
<span class="kpi-flag ${kpiFlag ? 'active' : 'inactive'}">${kpiFlag ? 'Active' : 'Inactive'}</span> | |
</div> | |
<p class="kpi-trend">Performance Indicator</p> | |
`; | |
kpiDashboard.appendChild(flagCard); | |
} | |
function downloadPDF() { | |
if (!supervisorData || !supervisorData.download_link) { | |
showToast('error', 'No download link available.'); | |
return; | |
} | |
window.open(supervisorData.download_link, '_blank'); | |
} | |
// Event Listeners | |
document.getElementById('search-bar').addEventListener('input', searchData); | |
window.onload = () => { | |
fetchSupervisorData(); | |
setAvatar(); | |
}; | |
</script> | |
</body> | |
</html> |