|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>Construction Supervisor AI Coach</title> |
|
<style> |
|
:root { |
|
--primary-blue: #2563EB; |
|
--secondary-orange: #F97316; |
|
--accent-yellow: #FBBF24; |
|
--success-green: #48BB78; |
|
--error-red: #F56565; |
|
--warning-yellow: #ECC94B; |
|
--background-light: #F7FAFC; |
|
--card-bg: #FFFFFF; |
|
--text-dark: #1A202C; |
|
--text-muted: #718096; |
|
} |
|
|
|
body { |
|
font-family: 'Roboto', Arial, sans-serif; |
|
margin: 0; |
|
padding: 0; |
|
background-color: #F5F7FA; |
|
color: var(--text-dark); |
|
line-height: 1.6; |
|
display: flex; |
|
} |
|
|
|
|
|
.sidebar { |
|
width: 200px; |
|
background-color: var(--card-bg); |
|
height: 100vh; |
|
position: fixed; |
|
top: 0; |
|
left: 0; |
|
padding: 20px; |
|
box-shadow: 2px 0 5px rgba(0, 0, 0, 0.1); |
|
display: flex; |
|
flex-direction: column; |
|
gap: 10px; |
|
} |
|
|
|
.sidebar h1 { |
|
font-size: 18px; |
|
color: var(--primary-blue); |
|
margin: 0 0 20px 0; |
|
} |
|
|
|
.sidebar a { |
|
display: flex; |
|
align-items: center; |
|
gap: 10px; |
|
padding: 10px 15px; |
|
color: var(--text-muted); |
|
text-decoration: none; |
|
border-radius: 5px; |
|
transition: background 0.3s ease; |
|
} |
|
|
|
.sidebar a.active { |
|
background-color: #E6F0FA; |
|
color: var(--primary-blue); |
|
} |
|
|
|
.sidebar a:hover { |
|
background-color: #E6F0FA; |
|
} |
|
|
|
.sidebar img { |
|
width: 20px; |
|
height: 20px; |
|
} |
|
|
|
|
|
.main-content { |
|
margin-left: 200px; |
|
padding: 20px; |
|
flex: 1; |
|
} |
|
|
|
.header { |
|
display: flex; |
|
justify-content: space-between; |
|
align-items: center; |
|
padding: 10px 20px; |
|
background-color: var(--card-bg); |
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); |
|
} |
|
|
|
.header .user-info { |
|
display: flex; |
|
align-items: center; |
|
gap: 10px; |
|
} |
|
|
|
.header .user-info img { |
|
width: 20px; |
|
height: 20px; |
|
} |
|
|
|
.header .user-info span { |
|
font-size: 14px; |
|
color: var(--text-muted); |
|
} |
|
|
|
.header .user-info .avatar { |
|
width: 30px; |
|
height: 30px; |
|
background-color: var(--primary-blue); |
|
color: #FFFFFF; |
|
border-radius: 50%; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
font-size: 16px; |
|
} |
|
|
|
|
|
.section { |
|
background-color: var(--card-bg); |
|
padding: 20px; |
|
border-radius: 8px; |
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05); |
|
margin-bottom: 20px; |
|
} |
|
|
|
.section h2 { |
|
font-size: 24px; |
|
color: var(--text-dark); |
|
margin: 0 0 10px 0; |
|
} |
|
|
|
.section p { |
|
font-size: 14px; |
|
color: var(--text-muted); |
|
margin: 0 0 20px 0; |
|
} |
|
|
|
|
|
.dashboard-grid { |
|
display: grid; |
|
grid-template-columns: 1fr 1fr; |
|
gap: 20px; |
|
} |
|
|
|
.checklist-item { |
|
display: flex; |
|
align-items: center; |
|
gap: 10px; |
|
padding: 10px 0; |
|
font-size: 14px; |
|
} |
|
|
|
.checklist-item input { |
|
accent-color: var(--primary-blue); |
|
} |
|
|
|
.checklist-item label { |
|
flex: 1; |
|
color: var(--text-dark); |
|
} |
|
|
|
.checklist-item label.category-safety { |
|
color: var(--error-red); |
|
} |
|
|
|
.checklist-item label.category-materials { |
|
color: var(--primary-blue); |
|
} |
|
|
|
.checklist-item label.category-inspection { |
|
color: var(--warning-yellow); |
|
} |
|
|
|
.project-progress { |
|
display: flex; |
|
flex-direction: column; |
|
gap: 10px; |
|
} |
|
|
|
.project-progress .progress-bar { |
|
width: 100%; |
|
height: 10px; |
|
background-color: #E2E8F0; |
|
border-radius: 5px; |
|
overflow: hidden; |
|
} |
|
|
|
.project-progress .progress-fill { |
|
height: 100%; |
|
background-color: var(--primary-blue); |
|
transition: width 0.5s ease; |
|
} |
|
|
|
.metrics-grid { |
|
display: grid; |
|
grid-template-columns: repeat(3, 1fr); |
|
gap: 10px; |
|
} |
|
|
|
.metric-card { |
|
text-align: center; |
|
padding: 10px; |
|
border-radius: 5px; |
|
background-color: #F9FAFB; |
|
} |
|
|
|
.metric-card h4 { |
|
font-size: 14px; |
|
color: var(--text-muted); |
|
margin: 0 0 5px 0; |
|
} |
|
|
|
.metric-card .value { |
|
font-size: 24px; |
|
font-weight: 700; |
|
color: var(--primary-blue); |
|
} |
|
|
|
.metric-card .trend { |
|
font-size: 12px; |
|
color: var(--error-red); |
|
} |
|
|
|
.tips-card { |
|
padding: 15px; |
|
border-radius: 5px; |
|
margin-bottom: 10px; |
|
font-size: 14px; |
|
} |
|
|
|
.tips-card.warning { |
|
background-color: #FEF3C7; |
|
color: var(--warning-yellow); |
|
} |
|
|
|
.tips-card.info { |
|
background-color: #EBF5FF; |
|
color: var(--primary-blue); |
|
} |
|
|
|
.tips-card.medium { |
|
background-color: #F3F4F6; |
|
color: var(--text-muted); |
|
} |
|
|
|
|
|
.mood-buttons { |
|
display: flex; |
|
gap: 10px; |
|
margin-bottom: 15px; |
|
} |
|
|
|
.mood-buttons button { |
|
padding: 8px 15px; |
|
border: 1px solid #E2E8F0; |
|
border-radius: 5px; |
|
background-color: var(--card-bg); |
|
color: var(--text-muted); |
|
cursor: pointer; |
|
transition: background 0.3s ease; |
|
} |
|
|
|
.mood-buttons button.active { |
|
background-color: var(--primary-blue); |
|
color: #FFFFFF; |
|
border-color: var(--primary-blue); |
|
} |
|
|
|
.reflection-input textarea { |
|
width: 100%; |
|
height: 100px; |
|
padding: 10px; |
|
border: 1px solid #E2E8F0; |
|
border-radius: 5px; |
|
resize: none; |
|
font-size: 14px; |
|
margin-bottom: 10px; |
|
} |
|
|
|
.reflection-history .entry { |
|
padding: 10px 0; |
|
border-bottom: 1px solid #E2E8F0; |
|
font-size: 14px; |
|
} |
|
|
|
.reflection-history .entry:last-child { |
|
border-bottom: none; |
|
} |
|
|
|
.reflection-history .entry .date { |
|
font-weight: 600; |
|
color: var(--text-dark); |
|
} |
|
|
|
.reflection-history .entry .mood { |
|
padding: 2px 8px; |
|
border-radius: 5px; |
|
font-size: 12px; |
|
margin-left: 10px; |
|
} |
|
|
|
.reflection-history .entry .mood.concerned { |
|
background-color: #FEF3C7; |
|
color: var(--warning-yellow); |
|
} |
|
|
|
.reflection-history .entry .mood.satisfied { |
|
background-color: #D1FAE5; |
|
color: var(--success-green); |
|
} |
|
|
|
.reflection-history .entry .mood.neutral { |
|
background-color: #F3F4F6; |
|
color: var(--text-muted); |
|
} |
|
|
|
|
|
.report-form { |
|
display: flex; |
|
flex-direction: column; |
|
gap: 15px; |
|
} |
|
|
|
.report-form input, |
|
.report-form select { |
|
padding: 10px; |
|
border: 1px solid #E2E8F0; |
|
border-radius: 5px; |
|
font-size: 14px; |
|
} |
|
|
|
.report-form .date-range { |
|
display: flex; |
|
gap: 10px; |
|
} |
|
|
|
.report-list .report-item { |
|
display: flex; |
|
justify-content: space-between; |
|
align-items: center; |
|
padding: 10px; |
|
border-bottom: 1px solid #E2E8F0; |
|
font-size: 14px; |
|
} |
|
|
|
.report-list .report-item:last-child { |
|
border-bottom: none; |
|
} |
|
|
|
.report-list .report-item .status { |
|
padding: 2px 8px; |
|
border-radius: 5px; |
|
font-size: 12px; |
|
background-color: #D1FAE5; |
|
color: var(--success-green); |
|
} |
|
|
|
|
|
.milestones-header { |
|
display: flex; |
|
justify-content: space-between; |
|
align-items: center; |
|
margin-bottom: 15px; |
|
} |
|
|
|
.milestone-item { |
|
display: flex; |
|
justify-content: space-between; |
|
align-items: center; |
|
padding: 15px; |
|
border-radius: 5px; |
|
margin-bottom: 10px; |
|
font-size: 14px; |
|
} |
|
|
|
.milestone-item.completed { |
|
background-color: #D1FAE5; |
|
} |
|
|
|
.milestone-item.in-progress { |
|
background-color: #EBF5FF; |
|
} |
|
|
|
.milestone-item.not-started { |
|
background-color: #F3F4F6; |
|
} |
|
|
|
.milestone-item .progress-bar { |
|
width: 100%; |
|
height: 5px; |
|
background-color: #E2E8F0; |
|
border-radius: 5px; |
|
overflow: hidden; |
|
margin-top: 5px; |
|
} |
|
|
|
.milestone-item .progress-fill { |
|
height: 100%; |
|
background-color: var(--primary-blue); |
|
transition: width 0.5s ease; |
|
} |
|
|
|
.milestone-item .status { |
|
padding: 2px 8px; |
|
border-radius: 5px; |
|
font-size: 12px; |
|
} |
|
|
|
.milestone-item .status.completed { |
|
background-color: var(--success-green); |
|
color: #FFFFFF; |
|
} |
|
|
|
.milestone-item .status.in-progress { |
|
background-color: var(--primary-blue); |
|
color: #FFFFFF; |
|
} |
|
|
|
.milestone-item .status.not-started { |
|
background-color: var(--text-muted); |
|
color: #FFFFFF; |
|
} |
|
|
|
|
|
.profile-grid { |
|
display: grid; |
|
grid-template-columns: 1fr 2fr; |
|
gap: 20px; |
|
align-items: center; |
|
margin-bottom: 20px; |
|
} |
|
|
|
.profile-grid .avatar { |
|
width: 80px; |
|
height: 80px; |
|
background-color: var(--primary-blue); |
|
color: #FFFFFF; |
|
border-radius: 50%; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
font-size: 40px; |
|
} |
|
|
|
.profile-details p { |
|
margin: 5px 0; |
|
font-size: 14px; |
|
} |
|
|
|
.preferences-form { |
|
display: flex; |
|
flex-direction: column; |
|
gap: 15px; |
|
} |
|
|
|
.preferences-form .toggle { |
|
display: flex; |
|
align-items: center; |
|
gap: 10px; |
|
} |
|
|
|
.preferences-form .toggle input { |
|
width: 40px; |
|
height: 20px; |
|
appearance: none; |
|
background-color: #E2E8F0; |
|
border-radius: 20px; |
|
position: relative; |
|
cursor: pointer; |
|
outline: none; |
|
} |
|
|
|
.preferences-form .toggle input:checked { |
|
background-color: var(--primary-blue); |
|
} |
|
|
|
.preferences-form .toggle input::before { |
|
content: ''; |
|
width: 16px; |
|
height: 16px; |
|
background-color: #FFFFFF; |
|
border-radius: 50%; |
|
position: absolute; |
|
top: 2px; |
|
left: 2px; |
|
transition: transform 0.3s ease; |
|
} |
|
|
|
.preferences-form .toggle input:checked::before { |
|
transform: translateX(20px); |
|
} |
|
|
|
.preferences-form select { |
|
padding: 10px; |
|
border: 1px solid #E2E8F0; |
|
border-radius: 5px; |
|
font-size: 14px; |
|
} |
|
|
|
|
|
button { |
|
padding: 10px 20px; |
|
background-color: var(--primary-blue); |
|
color: #FFFFFF; |
|
border: none; |
|
border-radius: 5px; |
|
cursor: pointer; |
|
font-size: 14px; |
|
transition: background 0.3s ease; |
|
} |
|
|
|
button:hover { |
|
background-color: #1E4DB7; |
|
} |
|
|
|
button.secondary { |
|
background-color: #E2E8F0; |
|
color: var(--text-dark); |
|
} |
|
|
|
button.secondary:hover { |
|
background-color: #D1D5DB; |
|
} |
|
|
|
|
|
.toast { |
|
position: fixed; |
|
top: 20px; |
|
right: 20px; |
|
padding: 10px 20px; |
|
border-radius: 5px; |
|
z-index: 1000; |
|
display: none; |
|
font-size: 14px; |
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); |
|
} |
|
|
|
.toast.error { |
|
background-color: var(--error-red); |
|
color: #FFFFFF; |
|
} |
|
|
|
.toast.success { |
|
background-color: var(--success-green); |
|
color: #FFFFFF; |
|
} |
|
|
|
.toast.visible { |
|
display: block; |
|
} |
|
|
|
|
|
@media (max-width: 768px) { |
|
.sidebar { |
|
width: 60px; |
|
padding: 10px; |
|
} |
|
|
|
.sidebar h1 { |
|
font-size: 14px; |
|
} |
|
|
|
.sidebar a { |
|
padding: 5px; |
|
justify-content: center; |
|
} |
|
|
|
.sidebar a span { |
|
display: none; |
|
} |
|
|
|
.main-content { |
|
margin-left: 60px; |
|
padding: 10px; |
|
} |
|
|
|
.dashboard-grid { |
|
grid-template-columns: 1fr; |
|
} |
|
|
|
.metrics-grid { |
|
grid-template-columns: 1fr; |
|
} |
|
|
|
.profile-grid { |
|
grid-template-columns: 1fr; |
|
text-align: center; |
|
} |
|
|
|
.profile-grid .avatar { |
|
margin: 0 auto; |
|
} |
|
} |
|
</style> |
|
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap" rel="stylesheet"> |
|
</head> |
|
<body> |
|
|
|
<div class="sidebar"> |
|
<h1>STPL Coach</h1> |
|
<a href="#dashboard" class="active" onclick="showSection('dashboard')"><img src="https://img.icons8.com/ios-filled/50/dashboard.png" alt="Dashboard"> <span>Dashboard</span></a> |
|
<a href="#reflections" onclick="showSection('reflections')"><img src="https://img.icons8.com/ios-filled/50/book.png" alt="Reflections"> <span>Reflections</span></a> |
|
<a href="#reports" onclick="showSection('reports')"><img src="https://img.icons8.com/ios-filled/50/report-card.png" alt="Reports"> <span>Reports</span></a> |
|
<a href="#milestones" onclick="showSection('milestones')"><img src="https://img.icons8.com/ios-filled/50/milestone.png" alt="Milestones"> <span>Milestones</span></a> |
|
<a href="#profile" onclick="showSection('profile')"><img src="https://img.icons8.com/ios-filled/50/user.png" alt="Profile"> <span>Profile</span></a> |
|
</div> |
|
|
|
|
|
<div class="main-content"> |
|
<div class="header"> |
|
<div></div> |
|
<div class="user-info"> |
|
<img src="https://img.icons8.com/ios-filled/50/bell.png" alt="Notifications"> |
|
<span>Senior Construction Supervisor</span> |
|
<div class="avatar">A</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="section dashboard-section" id="dashboard-section"> |
|
<h2>Good morning, Alex</h2> |
|
<p>Here's your checklist summary for today</p> |
|
<div class="dashboard-grid"> |
|
<div> |
|
<h3>Today's Checklist</h3> |
|
<p>1 of 5 complete</p> |
|
<div id="checklist-items"> |
|
<div class="checklist-item"> |
|
<input type="checkbox" id="checklist-0" onchange="markComplete(0, this)"> |
|
<label for="checklist-0" class="category-safety">Review safety equipment status for concrete pouring team</label> |
|
</div> |
|
<div class="checklist-item"> |
|
<input type="checkbox" id="checklist-1" onchange="markComplete(1, this)"> |
|
<label for="checklist-1" class="category-materials">Verify delivery of steel reinforcement for floor 3</label> |
|
</div> |
|
<div class="checklist-item"> |
|
<input type="checkbox" id="checklist-2" onchange="markComplete(2, this)"> |
|
<label for="checklist-2">Coordinate with electrical contractor on conduit installation</label> |
|
</div> |
|
<div class="checklist-item"> |
|
<input type="checkbox" id="checklist-3" onchange="markComplete(3, this)"> |
|
<label for="checklist-3" class="category-inspection">Inspect temporary weather protection measures</label> |
|
</div> |
|
<div class="checklist-item"> |
|
<input type="checkbox" id="checklist-4" onchange="markComplete(4, this)"> |
|
<label for="checklist-4">Update project timeline based on foundation completion</label> |
|
</div> |
|
</div> |
|
|
|
<h3>Today's Coaching Tips</h3> |
|
<div class="tips-card warning"> |
|
<strong>Focus on Weather Preparedness:</strong> Weather forecasts show rain in the next 48 hours. Ensure all open areas are properly covered and drainage systems are clear. |
|
</div> |
|
<div class="tips-card info"> |
|
<strong>Team Motivation:</strong> The concrete team has been exceeding expectations. Consider acknowledging their performance in the next team meeting to boost morale. |
|
</div> |
|
<div class="tips-card medium"> |
|
<strong>Schedule Optimization:</strong> Based on current pace, electrical work can begin 2 days earlier than planned. Consider adjusting the schedule to improve overall timeline. |
|
</div> |
|
</div> |
|
<div> |
|
<h3>Project Progress</h3> |
|
<div class="project-progress"> |
|
<p>Riverfront Commercial Complex<br>Aug 15, 2023 - Feb 28, 2025</p> |
|
<p><strong>Overall Progress:</strong> 35%</p> |
|
<div class="progress-bar"> |
|
<div class="progress-fill" style="width: 35%"></div> |
|
</div> |
|
<p><strong>Current Milestone:</strong> Structural Steel Erection (65% Complete)<br>Due: Dec 15, 2023</p> |
|
</div> |
|
|
|
<h3>Performance Metrics</h3> |
|
<div class="metrics-grid"> |
|
<div class="metric-card"> |
|
<h4>Engagement</h4> |
|
<div class="value">87%</div> |
|
<p class="trend">Weekly Engagement Trend: High</p> |
|
</div> |
|
<div class="metric-card"> |
|
<h4>Completion</h4> |
|
<div class="value">92%</div> |
|
</div> |
|
<div class="metric-card"> |
|
<h4>Stress</h4> |
|
<div class="value">7 days</div> |
|
</div> |
|
</div> |
|
<p>2 KPI Flags</p> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="section reflections-section" id="reflections-section" style="display: none;"> |
|
<h2>Reflection Journal</h2> |
|
<p>Record daily reflections and insights to improve your leadership</p> |
|
<h3>Add Daily Reflection</h3> |
|
<div class="reflection-input"> |
|
<p>How are you feeling today?</p> |
|
<div class="mood-buttons"> |
|
<button onclick="selectMood('Satisfied')">Satisfied</button> |
|
<button onclick="selectMood('Motivated')">Motivated</button> |
|
<button onclick="selectMood('Neutral')">Neutral</button> |
|
<button onclick="selectMood('Concerned')">Concerned</button> |
|
<button onclick="selectMood('Frustrated')">Frustrated</button> |
|
</div> |
|
<textarea id="reflection-input" placeholder="Share your thoughts on today’s progress, challenges, or learnings..."></textarea> |
|
<button class="secondary" onclick="submitReflection()">Submit Reflection</button> |
|
</div> |
|
<h3>Reflection History</h3> |
|
<div class="reflection-history" id="reflection-history"> |
|
<div class="entry"> |
|
<span class="date">Nov 15, 2023</span><span class="mood concerned">Concerned</span> |
|
<p>Faced challenges with the concrete supplier today. Need to improve communication channels and possibly consider backup suppliers for critical phases.</p> |
|
<p><strong>Learned:</strong> Always have contingency plans for key materials.</p> |
|
</div> |
|
<div class="entry"> |
|
<span class="date">Nov 14, 2023</span><span class="mood satisfied">Satisfied</span> |
|
<p>Team excelled during the steel installation. The morning huddle approach is working well, setting daily priorities.</p> |
|
<p><strong>Learned:</strong> Regular brief check-ins improve team alignment.</p> |
|
</div> |
|
<div class="entry"> |
|
<span class="date">Nov 13, 2023</span><span class="mood neutral">Neutral</span> |
|
<p>Safety inspection identified several minor issues that were quickly addressed. Need to remind the team about proper ladder protocols.</p> |
|
<p><strong>Learned:</strong> Regular safety reminders are necessary even for experienced workers.</p> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="section reports-section" id="reports-section" style="display: none;"> |
|
<h2>Reports & Analytics</h2> |
|
<p>Generate and download reports for your performance and project status</p> |
|
<h3>Generate New Report</h3> |
|
<div class="report-form"> |
|
<input type="text" placeholder="Enter report title" id="report-title"> |
|
<select id="report-type"> |
|
<option value="Weekly Summary">Weekly Summary</option> |
|
<option value="Monthly Review">Monthly Review</option> |
|
</select> |
|
<div class="date-range"> |
|
<input type="date" id="start-date" value="2025-04-30"> |
|
<input type="date" id="end-date" value="2025-05-07"> |
|
</div> |
|
<div> |
|
<input type="checkbox" id="include-metrics" checked> |
|
<label for="include-metrics">Performance metrics & KPIs</label> |
|
</div> |
|
<div> |
|
<input type="checkbox" id="include-reflections" checked> |
|
<label for="include-reflections">Daily reflections & learnings</label> |
|
</div> |
|
<button class="secondary" onclick="generateReport()">Generate Report</button> |
|
</div> |
|
<h3>Your Reports</h3> |
|
<div class="report-list" id="report-list"> |
|
<div class="report-item"> |
|
<div> |
|
<p>Weekly Performance Summary</p> |
|
<p>Nov 12, 2023 • Weekly Summary</p> |
|
<p>Completion: 92% • Milestones: 2 • Improvements: 3</p> |
|
</div> |
|
<div> |
|
<span class="status">Generated</span> |
|
<button onclick="downloadReport('weekly')">Download</button> |
|
</div> |
|
</div> |
|
<div class="report-item"> |
|
<div> |
|
<p>October Monthly Review</p> |
|
<p>Nov 1, 2023 • Monthly Performance</p> |
|
<p>Completion: 88% • Milestones: 4 • Improvements: 5</p> |
|
</div> |
|
<div> |
|
<span class="status">Generated</span> |
|
<button onclick="downloadReport('monthly')">Download</button> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="section milestones-section" id="milestones-section" style="display: none;"> |
|
<div class="milestones-header"> |
|
<div> |
|
<h2>Project Milestones</h2> |
|
<p>Track and update project milestones for Riverfront Commercial Complex</p> |
|
</div> |
|
<div> |
|
<button class="secondary" onclick="syncSalesforce()">Sync with Salesforce</button> |
|
<button onclick="addMilestone()">Add Milestone</button> |
|
</div> |
|
</div> |
|
<div id="milestones-list"> |
|
<div class="milestone-item completed"> |
|
<div> |
|
<p><strong>Foundation Completion</strong></p> |
|
<p>Due: Oct 30, 2023</p> |
|
<p>Complete site foundation work including footings, piers, and foundation walls</p> |
|
<div class="progress-bar"> |
|
<div class="progress-fill" style="width: 100%"></div> |
|
</div> |
|
</div> |
|
<span class="status completed">Completed</span> |
|
</div> |
|
<div class="milestone-item in-progress"> |
|
<div> |
|
<p><strong>Structural Steel Erection</strong></p> |
|
<p>Due: Dec 15, 2023</p> |
|
<p>Erect the structural steel components for the main building frame</p> |
|
<div class="progress-bar"> |
|
<div class="progress-fill" style="width: 65%"></div> |
|
</div> |
|
</div> |
|
<span class="status in-progress">In Progress</span> |
|
</div> |
|
<div class="milestone-item not-started"> |
|
<div> |
|
<p><strong>Building Envelope</strong></p> |
|
<p>Due: Mar 1, 2024</p> |
|
<p>Complete exterior walls, roofing, and weatherproofing</p> |
|
<div class="progress-bar"> |
|
<div class="progress-fill" style="width: 0%"></div> |
|
</div> |
|
</div> |
|
<span class="status not-started">Not Started</span> |
|
</div> |
|
<div class="milestone-item not-started"> |
|
<div> |
|
<p><strong>MEP Rough-in</strong></p> |
|
<p>Due: May 15, 2024</p> |
|
<p>Complete mechanical, electrical, and plumbing rough-in work</p> |
|
<div class="progress-bar"> |
|
<div class="progress-fill" style="width: 0%"></div> |
|
</div> |
|
</div> |
|
<span class="status not-started">Not Started</span> |
|
</div> |
|
<div class="milestone-item not-started"> |
|
<div> |
|
<p><strong>Interior Finishing</strong></p> |
|
<p>Due: Oct 30, 2024</p> |
|
<p>Complete all interior finishes including drywall, flooring, and fixtures</p> |
|
<div class="progress-bar"> |
|
<div class="progress-fill" style="width: 0%"></div> |
|
</div> |
|
</div> |
|
<span class="status not-started">Not Started</span> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="section profile-section" id="profile-section" style="display: none;"> |
|
<h2>Profile & Settings</h2> |
|
<p>Manage your profile and AI coaching preferences</p> |
|
<h3>Supervisor Profile</h3> |
|
<div class="profile-grid"> |
|
<div class="avatar">A</div> |
|
<div class="profile-details"> |
|
<p><strong>Name:</strong> Alex Rivera</p> |
|
<p><strong>Email:</strong> [email protected]</p> |
|
<p><strong>Phone:</strong> (555) 123-4567</p> |
|
<p><strong>Role:</strong> Senior Construction Supervisor</p> |
|
<p><strong>Company:</strong> STPL Construction</p> |
|
<p><strong>Experience:</strong> 12 years</p> |
|
</div> |
|
</div> |
|
<h3>Coaching Preferences</h3> |
|
<div class="preferences-form"> |
|
<div class="toggle"> |
|
<label>AI Coaching Notifications</label> |
|
<input type="checkbox" id="notifications-toggle" checked> |
|
</div> |
|
<p>Receive push notifications for new coaching tips and checklist reminders</p> |
|
<div> |
|
<label>Coaching Frequency</label> |
|
<select id="coaching-frequency"> |
|
<option value="Daily">Daily</option> |
|
<option value="Weekly">Weekly</option> |
|
</select> |
|
</div> |
|
<div> |
|
<label>Preferred Time</label> |
|
<select id="preferred-time"> |
|
<option value="Morning 6:00 AM">Morning 6:00 AM</option> |
|
<option value="Evening 6:00 PM">Evening 6:00 PM</option> |
|
</select> |
|
</div> |
|
<button onclick="savePreferences()">Save Preferences</button> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div id="error" class="toast error"></div> |
|
<div id="success" class="toast success"></div> |
|
|
|
<script> |
|
let supervisorData = { |
|
supervisor_id: 'SUP_001', |
|
role: 'Senior Construction Supervisor', |
|
project_id: 'Riverfront_001', |
|
milestones: [ |
|
{ name: 'Foundation Completion', status: 'Completed', progress: 100, due: '2023-10-30' }, |
|
{ name: 'Structural Steel Erection', status: 'In Progress', progress: 65, due: '2023-12-15' }, |
|
{ name: 'Building Envelope', status: 'Not Started', progress: 0, due: '2024-03-01' }, |
|
{ name: 'MEP Rough-in', status: 'Not Started', progress: 0, due: '2024-05-15' }, |
|
{ name: 'Interior Finishing', status: 'Not Started', progress: 0, due: '2024-10-30' } |
|
], |
|
reflection_log: '', |
|
engagement_score: 87, |
|
completion_rate: 92, |
|
stress_days: 7 |
|
}; |
|
let coachingOutput = { |
|
checklist: [ |
|
'Review safety equipment status for concrete pouring team', |
|
'Verify delivery of steel reinforcement for floor 3', |
|
'Coordinate with electrical contractor on conduit installation', |
|
'Inspect temporary weather protection measures', |
|
'Update project timeline based on foundation completion' |
|
], |
|
tips: [ |
|
'Focus on Weather Preparedness: Weather forecasts show rain in the next 48 hours. Ensure all open areas are properly covered and drainage systems are clear.', |
|
'Team Motivation: The concrete team has been exceeding expectations. Consider acknowledging their performance in the next team meeting to boost morale.', |
|
'Schedule Optimization: Based on current pace, electrical work can begin 2 days earlier than planned. Consider adjusting the schedule to improve overall timeline.' |
|
], |
|
quote: 'Success is the sum of small efforts, repeated day in and day out.' |
|
}; |
|
let reflectionHistory = [ |
|
{ date: 'Nov 15, 2023', mood: 'Concerned', text: 'Faced challenges with the concrete supplier today. Need to improve communication channels and possibly consider backup suppliers for critical phases.', learned: 'Always have contingency plans for key materials.' }, |
|
{ date: 'Nov 14, 2023', mood: 'Satisfied', text: 'Team excelled during the steel installation. The morning huddle approach is working well, setting daily priorities.', learned: 'Regular brief check-ins improve team alignment.' }, |
|
{ date: 'Nov 13, 2023', mood: 'Neutral', text: 'Safety inspection identified several minor issues that were quickly addressed. Need to remind the team about proper ladder protocols.', learned: 'Regular safety reminders are necessary even for experienced workers.' } |
|
]; |
|
let checklistProgress = 0; |
|
let totalChecklistItems = coachingOutput.checklist.length; |
|
let selectedMood = ''; |
|
|
|
|
|
function showToast(id, message) { |
|
const toast = document.getElementById(id); |
|
toast.textContent = message; |
|
toast.classList.add('visible'); |
|
setTimeout(() => { |
|
toast.classList.remove('visible'); |
|
}, 3000); |
|
} |
|
|
|
|
|
function showSection(section) { |
|
document.querySelectorAll('.section').forEach(s => s.style.display = 'none'); |
|
document.getElementById(`${section}-section`).style.display = 'block'; |
|
document.querySelectorAll('.sidebar a').forEach(a => a.classList.remove('active')); |
|
document.querySelector(`.sidebar a[href="#${section}"]`).classList.add('active'); |
|
} |
|
|
|
|
|
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'}.`); |
|
} |
|
|
|
function updateChecklistProgress() { |
|
const completedItems = document.querySelectorAll('#checklist-items input:checked').length; |
|
checklistProgress = totalChecklistItems > 0 ? (completedItems / totalChecklistItems) * 100 : 0; |
|
} |
|
|
|
|
|
function selectMood(mood) { |
|
selectedMood = mood; |
|
document.querySelectorAll('.mood-buttons button').forEach(btn => btn.classList.remove('active')); |
|
document.querySelector(`.mood-buttons button[onclick="selectMood('${mood}')"]`).classList.add('active'); |
|
} |
|
|
|
async function submitReflection() { |
|
const reflectionInput = document.getElementById('reflection-input').value.trim(); |
|
|
|
if (!reflectionInput) { |
|
showToast('error', 'Please enter a reflection before submitting.'); |
|
return; |
|
} |
|
|
|
if (!selectedMood) { |
|
showToast('error', 'Please select a mood before submitting.'); |
|
return; |
|
} |
|
|
|
try { |
|
const response = await fetch('/submit_reflection', { |
|
method: 'POST', |
|
headers: { 'Content-Type': 'application/json' }, |
|
body: JSON.stringify({ reflection: reflectionInput, mood: selectedMood }) |
|
}); |
|
const result = await response.json(); |
|
|
|
if (result.status === 'success') { |
|
supervisorData.reflection_log = reflectionInput; |
|
reflectionHistory.unshift({ |
|
date: new Date().toLocaleString(), |
|
mood: selectedMood, |
|
text: reflectionInput, |
|
learned: 'To be analyzed by AI...' |
|
}); |
|
updateReflectionHistory(); |
|
document.getElementById('reflection-input').value = ''; |
|
selectedMood = ''; |
|
document.querySelectorAll('.mood-buttons button').forEach(btn => btn.classList.remove('active')); |
|
showToast('success', 'Reflection submitted successfully.'); |
|
} else { |
|
showToast('error', result.message); |
|
} |
|
} catch (error) { |
|
showToast('error', 'Error submitting reflection: ' + error.message); |
|
} |
|
} |
|
|
|
function updateReflectionHistory() { |
|
const historyDiv = document.getElementById('reflection-history'); |
|
historyDiv.innerHTML = ''; |
|
if (reflectionHistory.length > 0) { |
|
reflectionHistory.forEach(ref => { |
|
const entryDiv = document.createElement('div'); |
|
entryDiv.className = 'entry'; |
|
entryDiv.innerHTML = ` |
|
<span class="date">${ref.date}</span><span class="mood ${ref.mood.toLowerCase()}">${ref.mood}</span> |
|
<p>${ref.text}</p> |
|
<p><strong>Learned:</strong> ${ref.learned}</p> |
|
`; |
|
historyDiv.appendChild(entryDiv); |
|
}); |
|
} else { |
|
historyDiv.innerHTML = '<p>No reflections yet. Start logging your thoughts!</p>'; |
|
} |
|
} |
|
|
|
|
|
async function generateReport() { |
|
const title = document.getElementById('report-title').value.trim(); |
|
const type = document.getElementById('report-type').value; |
|
const startDate = document.getElementById('start-date').value; |
|
const endDate = document.getElementById('end-date').value; |
|
const includeMetrics = document.getElementById('include-metrics').checked; |
|
const includeReflections = document.getElementById('include-reflections').checked; |
|
|
|
if (!title) { |
|
showToast('error', 'Please enter a report title.'); |
|
return; |
|
} |
|
|
|
try { |
|
const response = await fetch('/generate_pdf', { |
|
method: 'POST', |
|
headers: { 'Content-Type': 'application/json' }, |
|
body: JSON.stringify({ |
|
title, |
|
type, |
|
startDate, |
|
endDate, |
|
includeMetrics, |
|
includeReflections, |
|
checklist: coachingOutput?.checklist || [], |
|
tips: coachingOutput?.tips || [], |
|
milestones: supervisorData?.milestones || [], |
|
reflections: reflectionHistory |
|
}) |
|
}); |
|
const result = await response.json(); |
|
if (result.status === 'success') { |
|
const reportList = document.getElementById('report-list'); |
|
const reportItem = document.createElement('div'); |
|
reportItem.className = 'report-item'; |
|
reportItem.innerHTML = ` |
|
<div> |
|
<p>${title}</p> |
|
<p>${new Date().toLocaleDateString()} • ${type}</p> |
|
<p>Completion: ${supervisorData.completion_rate}% • Milestones: ${supervisorData.milestones.length} • Improvements: ${reflectionHistory.length}</p> |
|
</div> |
|
<div> |
|
<span class="status">Generated</span> |
|
<button onclick="downloadReport('${title}')">Download</button> |
|
</div> |
|
`; |
|
reportList.prepend(reportItem); |
|
showToast('success', 'Report generated successfully.'); |
|
} else { |
|
showToast('error', result.message || 'Failed to generate report.'); |
|
} |
|
} catch (error) { |
|
showToast('error', 'Error generating report: ' + error.message); |
|
} |
|
} |
|
|
|
async function downloadReport(title) { |
|
showToast('success', `Downloading report: ${title}`); |
|
} |
|
|
|
|
|
async function syncSalesforce() { |
|
try { |
|
const response = await fetch('/sync_salesforce', { |
|
method: 'POST', |
|
headers: { 'Content-Type': 'application/json' } |
|
}); |
|
const result = await response.json(); |
|
if (result.status === 'success') { |
|
supervisorData.milestones = result.data.milestones; |
|
updateMilestones(); |
|
showToast('success', 'Milestones synced with Salesforce.'); |
|
} else { |
|
showToast('error', result.message); |
|
} |
|
} catch (error) { |
|
showToast('error', 'Error syncing with Salesforce: ' + error.message); |
|
} |
|
} |
|
|
|
async function addMilestone() { |
|
const name = prompt('Enter milestone name:'); |
|
const due = prompt('Enter due date (YYYY-MM-DD):'); |
|
if (name && due) { |
|
supervisorData.milestones.push({ |
|
name, |
|
status: 'Not Started', |
|
progress: 0, |
|
due |
|
}); |
|
updateMilestones(); |
|
showToast('success', 'Milestone added successfully.'); |
|
} else { |
|
showToast('error', 'Please provide both name and due date.'); |
|
} |
|
} |
|
|
|
function updateMilestones() { |
|
const milestonesDiv = document.getElementById('milestones-list'); |
|
milestonesDiv.innerHTML = ''; |
|
if (supervisorData.milestones?.length > 0) { |
|
supervisorData.milestones.forEach(milestone => { |
|
const milestoneDiv = document.createElement('div'); |
|
milestoneDiv.className = `milestone-item ${milestone.status.toLowerCase().replace(' ', '-')}`; |
|
milestoneDiv.innerHTML = ` |
|
<div> |
|
<p><strong>${milestone.name}</strong></p> |
|
<p>Due: ${milestone.due}</p> |
|
<p>${milestone.description || ''}</p> |
|
<div class="progress-bar"> |
|
<div class="progress-fill" style="width: ${milestone.progress}%"></div> |
|
</div> |
|
</div> |
|
<span class="status ${milestone.status.toLowerCase().replace(' ', '-')}">${milestone.status}</span> |
|
`; |
|
milestonesDiv.appendChild(milestoneDiv); |
|
}); |
|
} else { |
|
milestonesDiv.innerHTML = '<p>No milestones available.</p>'; |
|
} |
|
} |
|
|
|
|
|
async function savePreferences() { |
|
const notifications = document.getElementById('notifications-toggle').checked; |
|
const frequency = document.getElementById('coaching-frequency').value; |
|
const time = document.getElementById('preferred-time').value; |
|
|
|
try { |
|
const response = await fetch('/save_preferences', { |
|
method: 'POST', |
|
headers: { 'Content-Type': 'application/json' }, |
|
body: JSON.stringify({ notifications, frequency, time }) |
|
}); |
|
const result = await response.json(); |
|
if (result.status === 'success') { |
|
showToast('success', 'Preferences saved successfully.'); |
|
} else { |
|
showToast('error', result.message); |
|
} |
|
} catch (error) { |
|
showToast('error', 'Error saving preferences: ' + error.message); |
|
} |
|
} |
|
|
|
|
|
window.onload = () => { |
|
updateChecklistProgress(); |
|
updateReflectionHistory(); |
|
updateMilestones(); |
|
}; |
|
</script> |
|
</body> |
|
</html> |