|
<!DOCTYPE html> |
|
<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; |
|
} |
|
.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; |
|
} |
|
.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; |
|
} |
|
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 { |
|
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-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; |
|
} |
|
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 { |
|
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; |
|
} |
|
@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"> |
|
<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> |
|
|
|
<div class="section tips-section"> |
|
<h3><i>💡</i> Today's Top 3 Focus Areas</h3> |
|
<div id="focus-tips"></div> |
|
</div> |
|
|
|
<div class="section full-width"> |
|
<h3><i>📊</i> Supervisor Data</h3> |
|
<pre id="supervisor-data">Loading supervisor data...</pre> |
|
</div> |
|
|
|
<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> |
|
|
|
<div class="section full-width kpi-section"> |
|
<h3><i>📈</i> KPI Summary Dashboard</h3> |
|
<div class="kpi-dashboard" id="kpi-dashboard"></div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<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; |
|
|
|
function showToast(id, message) { |
|
const toast = document.getElementById(id); |
|
toast.textContent = message; |
|
toast.classList.add('visible'); |
|
setTimeout(() => { |
|
toast.classList.remove('visible'); |
|
}, 3000); |
|
} |
|
|
|
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_name !== 'GUEST') { |
|
avatar.textContent = result.data.supervisor_name.charAt(0).toUpperCase(); |
|
} else { |
|
avatar.textContent = 'G'; |
|
} |
|
} catch (error) { |
|
avatar.textContent = 'U'; |
|
} |
|
} |
|
|
|
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); |
|
} |
|
} |
|
|
|
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.'); |
|
} |
|
|
|
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)}%`; |
|
} |
|
|
|
function markComplete(index, checkbox) { |
|
const itemDiv = checkbox.parentElement; |
|
if (checkbox.checked) { |
|
itemDiv.classList.add('completed'); |
|
} else { |
|
itemDiv.classList.remove('completed'); |
|
} |
|
updateChecklistProgress(); |
|
} |
|
|
|
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); |
|
|
|
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); |
|
actic: read |
|
checklistDiv.appendChild(itemDiv); |
|
}); |
|
updateChecklistProgress(); |
|
} else { |
|
checklistDiv.innerHTML = '<p>No checklist items available.</p>'; |
|
} |
|
|
|
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>'; |
|
} |
|
|
|
if (supervisorData.reflection_log) { |
|
reflectionHistory.push({ |
|
date: new Date().toLocaleString(), |
|
text: supervisorData.reflection_log |
|
}); |
|
updateReflectionHistory(); |
|
} |
|
|
|
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!'); |
|
await fetchSupervisorData(); |
|
} else { |
|
showToast('error', result.message); |
|
} |
|
} catch (error) { |
|
showToast('error', 'Error generating coaching output: ' + error.message); |
|
} |
|
} |
|
|
|
async function submitReflection() { |
|
const reflectionInput = document.getElementById('reflection-input'); |
|
const reflection = reflectionInput.value.trim(); |
|
|
|
if (!reflection) { |
|
showToast('error', 'Reflection cannot be empty.'); |
|
return; |
|
} |
|
|
|
try { |
|
const response = await fetch('/submit_reflection', { |
|
method: 'POST', |
|
headers: { 'Content-Type': 'application/json' }, |
|
body: JSON.stringify({ reflection }) |
|
}); |
|
const result = await response.json(); |
|
|
|
if (result.status === 'success') { |
|
showToast('success', result.message); |
|
reflectionHistory.push({ |
|
date: new Date().toLocaleString(), |
|
text: reflection |
|
}); |
|
reflectionInput.value = ''; |
|
updateReflectionHistory(); |
|
await fetchSupervisorData(); |
|
} else { |
|
showToast('error', result.message); |
|
} |
|
} catch (error) { |
|
showToast('error', 'Error submitting reflection: ' + error.message); |
|
} |
|
} |
|
|
|
function updateReflectionHistory() { |
|
const historyDiv = document.getElementById('reflection-history'); |
|
if (reflectionHistory.length > 0) { |
|
historyDiv.innerHTML = reflectionHistory.map(ref => ` |
|
<div class="reflection-entry"> |
|
<span>${ref.date}</span>: ${ref.text} |
|
</div> |
|
`).join(''); |
|
} else { |
|
historyDiv.innerHTML = '<p>No reflections yet. Start logging your thoughts!</p>'; |
|
} |
|
} |
|
|
|
function updateKPIDashboard() { |
|
const kpiDashboard = document.getElementById('kpi-dashboard'); |
|
kpiDashboard.innerHTML = ''; |
|
|
|
if (supervisorData) { |
|
const kpiData = [ |
|
{ |
|
title: 'Engagement Score', |
|
value: `${supervisorData.engagement_score}%`, |
|
progress: supervisorData.engagement_score, |
|
trend: supervisorData.engagement_score > 80 ? 'Upward' : 'Stable' |
|
}, |
|
{ |
|
title: 'KPI Flag', |
|
value: supervisorData.kpi_flag ? 'Active' : 'Inactive', |
|
class: supervisorData.kpi_flag ? 'active' : 'inactive' |
|
} |
|
]; |
|
|
|
kpiData.forEach(kpi => { |
|
const kpiCard = document.createElement('div'); |
|
kpiCard.className = 'kpi-card'; |
|
kpiCard.innerHTML = ` |
|
<h4>${kpi.title}</h4> |
|
<div class="kpi-value ${kpi.class || ''}">${kpi.value}</div> |
|
${kpi.progress !== undefined ? ` |
|
<div class="progress-bar"> |
|
<div class="progress-fill" style="width: ${kpi.progress}%"></div> |
|
</div> |
|
<div class="kpi-trend">Trend: ${kpi.trend}</div> |
|
` : ''} |
|
`; |
|
kpiDashboard.appendChild(kpiCard); |
|
}); |
|
} else { |
|
kpiDashboard.innerHTML = '<p>No KPI data available.</p>'; |
|
} |
|
} |
|
|
|
async function downloadPDF() { |
|
try { |
|
const response = await fetch('/download_pdf'); |
|
if (response.ok && response.headers.get('content-type').includes('application/pdf')) { |
|
const blob = await response.blob(); |
|
const url = window.URL.createObjectURL(blob); |
|
const a = document.createElement('a'); |
|
a.href = url; |
|
a.download = `supervisor_report_${supervisorData?.supervisor_name || 'report'}.pdf`; |
|
document.body.appendChild(a); |
|
a.click(); |
|
document.body.removeChild(a); |
|
window.URL.revokeObjectURL(url); |
|
showToast('success', 'PDF downloaded successfully!'); |
|
} else { |
|
const result = await response.json(); |
|
showToast('error', result.message); |
|
} |
|
} catch (error) { |
|
showToast('error', 'Error downloading PDF: ' + error.message); |
|
} |
|
} |
|
|
|
document.getElementById('search-bar').addEventListener('input', searchData); |
|
document.addEventListener('DOMContentLoaded', () => { |
|
setAvatar(); |
|
fetchSupervisorData(); |
|
}); |
|
</script> |
|
</body> |
|
</html> |