lokeshloki143 commited on
Commit
13b8640
·
verified ·
1 Parent(s): b6ca777

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +89 -1144
templates/index.html CHANGED
@@ -5,1197 +5,142 @@
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>Construction Supervisor AI Coach</title>
7
  <style>
8
- :root {
9
- --primary-blue: #2563EB;
10
- --secondary-orange: #F97316;
11
- --accent-yellow: #FBBF24;
12
- --success-green: #48BB78;
13
- --error-red: #F56565;
14
- --warning-yellow: #ECC94B;
15
- --background-light: #F7FAFC;
16
- --card-bg: #FFFFFF;
17
- --text-dark: #1A202C;
18
- --text-muted: #718096;
19
- }
20
-
21
  body {
22
- font-family: 'Roboto', Arial, sans-serif;
23
- margin: 0;
24
- padding: 0;
25
- background-color: #F5F7FA;
26
- color: var(--text-dark);
27
- line-height: 1.6;
28
- display: flex;
29
- }
30
-
31
- /* Sidebar */
32
- .sidebar {
33
- width: 200px;
34
- background-color: var(--card-bg);
35
- height: 100vh;
36
- position: fixed;
37
- top: 0;
38
- left: 0;
39
- padding: 20px;
40
- box-shadow: 2px 0 5px rgba(0, 0, 0, 0.1);
41
- display: flex;
42
- flex-direction: column;
43
- gap: 10px;
44
- }
45
-
46
- .sidebar h1 {
47
- font-size: 18px;
48
- color: var(--primary-blue);
49
- margin: 0 0 20px 0;
50
- }
51
-
52
- .sidebar a {
53
- display: flex;
54
- align-items: center;
55
- gap: 10px;
56
- padding: 10px 15px;
57
- color: var(--text-muted);
58
- text-decoration: none;
59
- border-radius: 5px;
60
- transition: background 0.3s ease;
61
- }
62
-
63
- .sidebar a.active {
64
- background-color: #E6F0FA;
65
- color: var(--primary-blue);
66
- }
67
-
68
- .sidebar a:hover {
69
- background-color: #E6F0FA;
70
- }
71
-
72
- .sidebar img {
73
- width: 20px;
74
- height: 20px;
75
  }
76
-
77
- /* Main Content */
78
- .main-content {
79
- margin-left: 200px;
80
- padding: 20px;
81
- flex: 1;
82
- }
83
-
84
- .header {
85
- display: flex;
86
- justify-content: space-between;
87
- align-items: center;
88
- padding: 10px 20px;
89
- background-color: var(--card-bg);
90
- box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
91
- }
92
-
93
- .header .user-info {
94
- display: flex;
95
- align-items: center;
96
- gap: 10px;
97
- }
98
-
99
- .header .user-info img {
100
- width: 20px;
101
- height: 20px;
102
- }
103
-
104
- .header .user-info span {
105
- font-size: 14px;
106
- color: var(--text-muted);
107
- }
108
-
109
- .header .user-info .avatar {
110
- width: 30px;
111
- height: 30px;
112
- background-color: var(--primary-blue);
113
- color: #FFFFFF;
114
- border-radius: 50%;
115
- display: flex;
116
- align-items: center;
117
- justify-content: center;
118
- font-size: 16px;
119
  }
120
-
121
- /* Sections */
122
- .section {
123
- background-color: var(--card-bg);
124
  padding: 20px;
125
  border-radius: 8px;
126
- box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
127
- margin-bottom: 20px;
128
- }
129
-
130
- .section h2 {
131
- font-size: 24px;
132
- color: var(--text-dark);
133
- margin: 0 0 10px 0;
134
- }
135
-
136
- .section p {
137
- font-size: 14px;
138
- color: var(--text-muted);
139
- margin: 0 0 20px 0;
140
- }
141
-
142
- /* Dashboard Section */
143
- .dashboard-grid {
144
- display: grid;
145
- grid-template-columns: 1fr 1fr;
146
- gap: 20px;
147
- }
148
-
149
- .checklist-item {
150
- display: flex;
151
- align-items: center;
152
- gap: 10px;
153
- padding: 10px 0;
154
- font-size: 14px;
155
- }
156
-
157
- .checklist-item input {
158
- accent-color: var(--primary-blue);
159
- }
160
-
161
- .checklist-item label {
162
- flex: 1;
163
- color: var(--text-dark);
164
- }
165
-
166
- .checklist-item label.category-safety {
167
- color: var(--error-red);
168
- }
169
-
170
- .checklist-item label.category-materials {
171
- color: var(--primary-blue);
172
- }
173
-
174
- .checklist-item label.category-inspection {
175
- color: var(--warning-yellow);
176
- }
177
-
178
- .project-progress {
179
- display: flex;
180
- flex-direction: column;
181
- gap: 10px;
182
- }
183
-
184
- .project-progress .progress-bar {
185
- width: 100%;
186
- height: 10px;
187
- background-color: #E2E8F0;
188
- border-radius: 5px;
189
- overflow: hidden;
190
- }
191
-
192
- .project-progress .progress-fill {
193
- height: 100%;
194
- background-color: var(--primary-blue);
195
- transition: width 0.5s ease;
196
- }
197
-
198
- .metrics-grid {
199
- display: grid;
200
- grid-template-columns: repeat(3, 1fr);
201
- gap: 10px;
202
- }
203
-
204
- .metric-card {
205
- text-align: center;
206
- padding: 10px;
207
- border-radius: 5px;
208
- background-color: #F9FAFB;
209
- }
210
-
211
- .metric-card h4 {
212
- font-size: 14px;
213
- color: var(--text-muted);
214
- margin: 0 0 5px 0;
215
- }
216
-
217
- .metric-card .value {
218
- font-size: 24px;
219
- font-weight: 700;
220
- color: var(--primary-blue);
221
- }
222
-
223
- .metric-card .trend {
224
- font-size: 12px;
225
- color: var(--error-red);
226
- }
227
-
228
- .tips-card {
229
- padding: 15px;
230
- border-radius: 5px;
231
- margin-bottom: 10px;
232
- font-size: 14px;
233
- }
234
-
235
- .tips-card.warning {
236
- background-color: #FEF3C7;
237
- color: var(--warning-yellow);
238
- }
239
-
240
- .tips-card.info {
241
- background-color: #EBF5FF;
242
- color: var(--primary-blue);
243
  }
244
-
245
- .tips-card.medium {
246
- background-color: #F3F4F6;
247
- color: var(--text-muted);
248
- }
249
-
250
- /* Reflections Section */
251
- .mood-buttons {
252
- display: flex;
253
- gap: 10px;
254
- margin-bottom: 15px;
255
- }
256
-
257
- .mood-buttons button {
258
- padding: 8px 15px;
259
- border: 1px solid #E2E8F0;
260
- border-radius: 5px;
261
- background-color: var(--card-bg);
262
- color: var(--text-muted);
263
- cursor: pointer;
264
- transition: background 0.3s ease;
265
- }
266
-
267
- .mood-buttons button.active {
268
- background-color: var(--primary-blue);
269
- color: #FFFFFF;
270
- border-color: var(--primary-blue);
271
- }
272
-
273
- .reflection-input textarea {
274
- width: 100%;
275
- height: 100px;
276
- padding: 10px;
277
- border: 1px solid #E2E8F0;
278
- border-radius: 5px;
279
- resize: none;
280
- font-size: 14px;
281
- margin-bottom: 10px;
282
- }
283
-
284
- .reflection-history .entry {
285
- padding: 10px 0;
286
- border-bottom: 1px solid #E2E8F0;
287
- font-size: 14px;
288
- }
289
-
290
- .reflection-history .entry:last-child {
291
- border-bottom: none;
292
- }
293
-
294
- .reflection-history .entry .date {
295
- font-weight: 600;
296
- color: var(--text-dark);
297
- }
298
-
299
- .reflection-history .entry .mood {
300
- padding: 2px 8px;
301
- border-radius: 5px;
302
- font-size: 12px;
303
- margin-left: 10px;
304
- }
305
-
306
- .reflection-history .entry .mood.concerned {
307
- background-color: #FEF3C7;
308
- color: var(--warning-yellow);
309
- }
310
-
311
- .reflection-history .entry .mood.satisfied {
312
- background-color: #D1FAE5;
313
- color: var(--success-green);
314
- }
315
-
316
- .reflection-history .entry .mood.neutral {
317
- background-color: #F3F4F6;
318
- color: var(--text-muted);
319
- }
320
-
321
- /* Reports Section */
322
- .report-form {
323
- display: flex;
324
- flex-direction: column;
325
- gap: 15px;
326
- }
327
-
328
- .report-form input,
329
- .report-form select {
330
- padding: 10px;
331
- border: 1px solid #E2E8F0;
332
- border-radius: 5px;
333
- font-size: 14px;
334
- }
335
-
336
- .report-form .date-range {
337
- display: flex;
338
- gap: 10px;
339
- }
340
-
341
- .report-list .report-item {
342
  display: flex;
343
  justify-content: space-between;
344
- align-items: center;
345
- padding: 10px;
346
- border-bottom: 1px solid #E2E8F0;
347
- font-size: 14px;
348
- }
349
-
350
- .report-list .report-item:last-child {
351
- border-bottom: none;
352
- }
353
-
354
- .report-list .report-item .status {
355
- padding: 2px 8px;
356
- border-radius: 5px;
357
- font-size: 12px;
358
- background-color: #D1FAE5;
359
- color: var(--success-green);
360
- }
361
-
362
- /* Milestones Section */
363
- .milestones-header {
364
- display: flex;
365
- justify-content: space-between;
366
- align-items: center;
367
  margin-bottom: 15px;
368
  }
369
-
370
- .milestone-item {
371
- display: flex;
372
- justify-content: space-between;
373
- align-items: center;
374
- padding: 15px;
375
- border-radius: 5px;
376
- margin-bottom: 10px;
377
- font-size: 14px;
378
- }
379
-
380
- .milestone-item.completed {
381
- background-color: #D1FAE5;
382
  }
383
-
384
- .milestone-item.in-progress {
385
- background-color: #EBF5FF;
386
  }
387
-
388
- .milestone-item.not-started {
389
- background-color: #F3F4F6;
 
390
  }
391
-
392
- .milestone-item .progress-bar {
393
  width: 100%;
394
- height: 5px;
395
- background-color: #E2E8F0;
396
- border-radius: 5px;
397
- overflow: hidden;
398
- margin-top: 5px;
399
- }
400
-
401
- .milestone-item .progress-fill {
402
- height: 100%;
403
- background-color: var(--primary-blue);
404
- transition: width 0.5s ease;
405
- }
406
-
407
- .milestone-item .status {
408
- padding: 2px 8px;
409
- border-radius: 5px;
410
- font-size: 12px;
411
- }
412
-
413
- .milestone-item .status.completed {
414
- background-color: var(--success-green);
415
- color: #FFFFFF;
416
- }
417
-
418
- .milestone-item .status.in-progress {
419
- background-color: var(--primary-blue);
420
- color: #FFFFFF;
421
  }
422
-
423
- .milestone-item .status.not-started {
424
- background-color: var(--text-muted);
425
- color: #FFFFFF;
426
- }
427
-
428
- /* Profile Section */
429
- .profile-grid {
430
- display: grid;
431
- grid-template-columns: 1fr 2fr;
432
- gap: 20px;
433
- align-items: center;
434
- margin-bottom: 20px;
435
- }
436
-
437
- .profile-grid .avatar {
438
- width: 80px;
439
  height: 80px;
440
- background-color: var(--primary-blue);
441
- color: #FFFFFF;
442
- border-radius: 50%;
443
- display: flex;
444
- align-items: center;
445
- justify-content: center;
446
- font-size: 40px;
447
- }
448
-
449
- .profile-details p {
450
- margin: 5px 0;
451
- font-size: 14px;
452
  }
453
-
454
- .preferences-form {
455
  display: flex;
456
- flex-direction: column;
457
- gap: 15px;
458
- }
459
-
460
- .preferences-form .toggle {
461
- display: flex;
462
- align-items: center;
463
- gap: 10px;
464
- }
465
-
466
- .preferences-form .toggle input {
467
- width: 40px;
468
- height: 20px;
469
- appearance: none;
470
- background-color: #E2E8F0;
471
- border-radius: 20px;
472
- position: relative;
473
- cursor: pointer;
474
- outline: none;
475
- }
476
-
477
- .preferences-form .toggle input:checked {
478
- background-color: var(--primary-blue);
479
- }
480
-
481
- .preferences-form .toggle input::before {
482
- content: '';
483
- width: 16px;
484
- height: 16px;
485
- background-color: #FFFFFF;
486
- border-radius: 50%;
487
- position: absolute;
488
- top: 2px;
489
- left: 2px;
490
- transition: transform 0.3s ease;
491
- }
492
-
493
- .preferences-form .toggle input:checked::before {
494
- transform: translateX(20px);
495
- }
496
-
497
- .preferences-form select {
498
- padding: 10px;
499
- border: 1px solid #E2E8F0;
500
- border-radius: 5px;
501
- font-size: 14px;
502
  }
503
-
504
- /* Buttons */
505
  button {
506
  padding: 10px 20px;
507
- background-color: var(--primary-blue);
508
- color: #FFFFFF;
509
  border: none;
510
- border-radius: 5px;
511
  cursor: pointer;
512
- font-size: 14px;
513
- transition: background 0.3s ease;
514
  }
515
-
516
  button:hover {
517
- background-color: #1E4DB7;
518
- }
519
-
520
- button.secondary {
521
- background-color: #E2E8F0;
522
- color: var(--text-dark);
523
- }
524
-
525
- button.secondary:hover {
526
- background-color: #D1D5DB;
527
- }
528
-
529
- /* Toast Notifications */
530
- .toast {
531
- position: fixed;
532
- top: 20px;
533
- right: 20px;
534
- padding: 10px 20px;
535
- border-radius: 5px;
536
- z-index: 1000;
537
- display: none;
538
- font-size: 14px;
539
- box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
540
- }
541
-
542
- .toast.error {
543
- background-color: var(--error-red);
544
- color: #FFFFFF;
545
  }
546
-
547
- .toast.success {
548
- background-color: var(--success-green);
549
- color: #FFFFFF;
 
 
550
  }
551
-
552
- .toast.visible {
553
- display: block;
554
  }
555
-
556
- /* Responsive Design */
557
- @media (max-width: 768px) {
558
- .sidebar {
559
- width: 60px;
560
- padding: 10px;
561
- }
562
-
563
- .sidebar h1 {
564
- font-size: 14px;
565
- }
566
-
567
- .sidebar a {
568
- padding: 5px;
569
- justify-content: center;
570
- }
571
-
572
- .sidebar a span {
573
- display: none;
574
- }
575
-
576
- .main-content {
577
- margin-left: 60px;
578
- padding: 10px;
579
- }
580
-
581
- .dashboard-grid {
582
- grid-template-columns: 1fr;
583
- }
584
-
585
- .metrics-grid {
586
- grid-template-columns: 1fr;
587
- }
588
-
589
- .profile-grid {
590
- grid-template-columns: 1fr;
591
- text-align: center;
592
- }
593
-
594
- .profile-grid .avatar {
595
- margin: 0 auto;
596
- }
597
  }
598
  </style>
599
- <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap" rel="stylesheet">
600
  </head>
601
  <body>
602
- <!-- Sidebar -->
603
- <div class="sidebar">
604
- <h1>STPL Coach</h1>
605
- <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>
606
- <a href="#reflections" onclick="showSection('reflections')"><img src="https://img.icons8.com/ios-filled/50/book.png" alt="Reflections"> <span>Reflections</span></a>
607
- <a href="#reports" onclick="showSection('reports')"><img src="https://img.icons8.com/ios-filled/50/report-card.png" alt="Reports"> <span>Reports</span></a>
608
- <a href="#milestones" onclick="showSection('milestones')"><img src="https://img.icons8.com/ios-filled/50/milestone.png" alt="Milestones"> <span>Milestones</span></a>
609
- <a href="#profile" onclick="showSection('profile')"><img src="https://img.icons8.com/ios-filled/50/user.png" alt="Profile"> <span>Profile</span></a>
610
- </div>
611
-
612
- <!-- Main Content -->
613
- <div class="main-content">
614
- <div class="header">
615
- <div></div>
616
- <div class="user-info">
617
- <img src="https://img.icons8.com/ios-filled/50/bell.png" alt="Notifications">
618
- <span>Senior Construction Supervisor</span>
619
- <div class="avatar">A</div>
620
- </div>
621
- </div>
622
-
623
- <!-- Dashboard Section -->
624
- <div class="section dashboard-section" id="dashboard-section">
625
- <h2>Good morning, Alex</h2>
626
- <p>Here's your checklist summary for today</p>
627
- <div class="dashboard-grid">
628
  <div>
629
- <h3>Today's Checklist</h3>
630
- <p>1 of 5 complete</p>
631
- <div id="checklist-items">
632
- <div class="checklist-item">
633
- <input type="checkbox" id="checklist-0" onchange="markComplete(0, this)">
634
- <label for="checklist-0" class="category-safety">Review safety equipment status for concrete pouring team</label>
635
- </div>
636
- <div class="checklist-item">
637
- <input type="checkbox" id="checklist-1" onchange="markComplete(1, this)">
638
- <label for="checklist-1" class="category-materials">Verify delivery of steel reinforcement for floor 3</label>
639
- </div>
640
- <div class="checklist-item">
641
- <input type="checkbox" id="checklist-2" onchange="markComplete(2, this)">
642
- <label for="checklist-2">Coordinate with electrical contractor on conduit installation</label>
643
- </div>
644
- <div class="checklist-item">
645
- <input type="checkbox" id="checklist-3" onchange="markComplete(3, this)">
646
- <label for="checklist-3" class="category-inspection">Inspect temporary weather protection measures</label>
647
- </div>
648
- <div class="checklist-item">
649
- <input type="checkbox" id="checklist-4" onchange="markComplete(4, this)">
650
- <label for="checklist-4">Update project timeline based on foundation completion</label>
651
- </div>
652
- </div>
653
-
654
- <h3>Today's Coaching Tips</h3>
655
- <div class="tips-card warning">
656
- <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.
657
- </div>
658
- <div class="tips-card info">
659
- <strong>Team Motivation:</strong> The concrete team has been exceeding expectations. Consider acknowledging their performance in the next team meeting to boost morale.
660
- </div>
661
- <div class="tips-card medium">
662
- <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.
663
- </div>
664
  </div>
665
  <div>
666
- <h3>Project Progress</h3>
667
- <div class="project-progress">
668
- <p>Riverfront Commercial Complex<br>Aug 15, 2023 - Feb 28, 2025</p>
669
- <p><strong>Overall Progress:</strong> 35%</p>
670
- <div class="progress-bar">
671
- <div class="progress-fill" style="width: 35%"></div>
672
- </div>
673
- <p><strong>Current Milestone:</strong> Structural Steel Erection (65% Complete)<br>Due: Dec 15, 2023</p>
674
- </div>
675
-
676
- <h3>Performance Metrics</h3>
677
- <div class="metrics-grid">
678
- <div class="metric-card">
679
- <h4>Engagement</h4>
680
- <div class="value">87%</div>
681
- <p class="trend">Weekly Engagement Trend: High</p>
682
- </div>
683
- <div class="metric-card">
684
- <h4>Completion</h4>
685
- <div class="value">92%</div>
686
- </div>
687
- <div class="metric-card">
688
- <h4>Stress</h4>
689
- <div class="value">7 days</div>
690
- </div>
691
- </div>
692
- <p>2 KPI Flags</p>
693
- </div>
694
- </div>
695
- </div>
696
-
697
- <!-- Reflections Section -->
698
- <div class="section reflections-section" id="reflections-section" style="display: none;">
699
- <h2>Reflection Journal</h2>
700
- <p>Record daily reflections and insights to improve your leadership</p>
701
- <h3>Add Daily Reflection</h3>
702
- <div class="reflection-input">
703
- <p>How are you feeling today?</p>
704
- <div class="mood-buttons">
705
- <button onclick="selectMood('Satisfied')">Satisfied</button>
706
- <button onclick="selectMood('Motivated')">Motivated</button>
707
- <button onclick="selectMood('Neutral')">Neutral</button>
708
- <button onclick="selectMood('Concerned')">Concerned</button>
709
- <button onclick="selectMood('Frustrated')">Frustrated</button>
710
- </div>
711
- <textarea id="reflection-input" placeholder="Share your thoughts on today’s progress, challenges, or learnings..."></textarea>
712
- <button class="secondary" onclick="submitReflection()">Submit Reflection</button>
713
- </div>
714
- <h3>Reflection History</h3>
715
- <div class="reflection-history" id="reflection-history">
716
- <div class="entry">
717
- <span class="date">Nov 15, 2023</span><span class="mood concerned">Concerned</span>
718
- <p>Faced challenges with the concrete supplier today. Need to improve communication channels and possibly consider backup suppliers for critical phases.</p>
719
- <p><strong>Learned:</strong> Always have contingency plans for key materials.</p>
720
- </div>
721
- <div class="entry">
722
- <span class="date">Nov 14, 2023</span><span class="mood satisfied">Satisfied</span>
723
- <p>Team excelled during the steel installation. The morning huddle approach is working well, setting daily priorities.</p>
724
- <p><strong>Learned:</strong> Regular brief check-ins improve team alignment.</p>
725
- </div>
726
- <div class="entry">
727
- <span class="date">Nov 13, 2023</span><span class="mood neutral">Neutral</span>
728
- <p>Safety inspection identified several minor issues that were quickly addressed. Need to remind the team about proper ladder protocols.</p>
729
- <p><strong>Learned:</strong> Regular safety reminders are necessary even for experienced workers.</p>
730
  </div>
731
  </div>
732
- </div>
733
-
734
- <!-- Reports Section -->
735
- <div class="section reports-section" id="reports-section" style="display: none;">
736
- <h2>Reports & Analytics</h2>
737
- <p>Generate and download reports for your performance and project status</p>
738
- <h3>Generate New Report</h3>
739
- <div class="report-form">
740
- <input type="text" placeholder="Enter report title" id="report-title">
741
- <select id="report-type">
742
- <option value="Weekly Summary">Weekly Summary</option>
743
- <option value="Monthly Review">Monthly Review</option>
744
- </select>
745
- <div class="date-range">
746
- <input type="date" id="start-date" value="2025-04-30">
747
- <input type="date" id="end-date" value="2025-05-07">
748
- </div>
749
  <div>
750
- <input type="checkbox" id="include-metrics" checked>
751
- <label for="include-metrics">Performance metrics & KPIs</label>
752
  </div>
753
  <div>
754
- <input type="checkbox" id="include-reflections" checked>
755
- <label for="include-reflections">Daily reflections & learnings</label>
756
  </div>
757
- <button class="secondary" onclick="generateReport()">Generate Report</button>
758
  </div>
759
- <h3>Your Reports</h3>
760
- <div class="report-list" id="report-list">
761
- <div class="report-item">
762
- <div>
763
- <p>Weekly Performance Summary</p>
764
- <p>Nov 12, 2023 • Weekly Summary</p>
765
- <p>Completion: 92% • Milestones: 2 • Improvements: 3</p>
766
- </div>
767
- <div>
768
- <span class="status">Generated</span>
769
- <button onclick="downloadReport('weekly')">Download</button>
770
- </div>
771
- </div>
772
- <div class="report-item">
773
- <div>
774
- <p>October Monthly Review</p>
775
- <p>Nov 1, 2023 • Monthly Performance</p>
776
- <p>Completion: 88% • Milestones: 4 • Improvements: 5</p>
777
- </div>
778
- <div>
779
- <span class="status">Generated</span>
780
- <button onclick="downloadReport('monthly')">Download</button>
781
- </div>
782
- </div>
783
  </div>
784
- </div>
785
-
786
- <!-- Milestones Section -->
787
- <div class="section milestones-section" id="milestones-section" style="display: none;">
788
- <div class="milestones-header">
789
- <div>
790
- <h2>Project Milestones</h2>
791
- <p>Track and update project milestones for Riverfront Commercial Complex</p>
792
- </div>
793
- <div>
794
- <button class="secondary" onclick="syncSalesforce()">Sync with Salesforce</button>
795
- <button onclick="addMilestone()">Add Milestone</button>
796
- </div>
797
  </div>
798
- <div id="milestones-list">
799
- <div class="milestone-item completed">
800
- <div>
801
- <p><strong>Foundation Completion</strong></p>
802
- <p>Due: Oct 30, 2023</p>
803
- <p>Complete site foundation work including footings, piers, and foundation walls</p>
804
- <div class="progress-bar">
805
- <div class="progress-fill" style="width: 100%"></div>
806
- </div>
807
- </div>
808
- <span class="status completed">Completed</span>
809
- </div>
810
- <div class="milestone-item in-progress">
811
- <div>
812
- <p><strong>Structural Steel Erection</strong></p>
813
- <p>Due: Dec 15, 2023</p>
814
- <p>Erect the structural steel components for the main building frame</p>
815
- <div class="progress-bar">
816
- <div class="progress-fill" style="width: 65%"></div>
817
- </div>
818
- </div>
819
- <span class="status in-progress">In Progress</span>
820
- </div>
821
- <div class="milestone-item not-started">
822
- <div>
823
- <p><strong>Building Envelope</strong></p>
824
- <p>Due: Mar 1, 2024</p>
825
- <p>Complete exterior walls, roofing, and weatherproofing</p>
826
- <div class="progress-bar">
827
- <div class="progress-fill" style="width: 0%"></div>
828
- </div>
829
- </div>
830
- <span class="status not-started">Not Started</span>
831
- </div>
832
- <div class="milestone-item not-started">
833
- <div>
834
- <p><strong>MEP Rough-in</strong></p>
835
- <p>Due: May 15, 2024</p>
836
- <p>Complete mechanical, electrical, and plumbing rough-in work</p>
837
- <div class="progress-bar">
838
- <div class="progress-fill" style="width: 0%"></div>
839
- </div>
840
- </div>
841
- <span class="status not-started">Not Started</span>
842
- </div>
843
- <div class="milestone-item not-started">
844
- <div>
845
- <p><strong>Interior Finishing</strong></p>
846
- <p>Due: Oct 30, 2024</p>
847
- <p>Complete all interior finishes including drywall, flooring, and fixtures</p>
848
- <div class="progress-bar">
849
- <div class="progress-fill" style="width: 0%"></div>
850
- </div>
851
- </div>
852
- <span class="status not-started">Not Started</span>
853
- </div>
854
  </div>
855
- </div>
856
 
857
- <!-- Profile Section -->
858
- <div class="section profile-section" id="profile-section" style="display: none;">
859
- <h2>Profile & Settings</h2>
860
- <p>Manage your profile and AI coaching preferences</p>
861
- <h3>Supervisor Profile</h3>
862
- <div class="profile-grid">
863
- <div class="avatar">A</div>
864
- <div class="profile-details">
865
- <p><strong>Name:</strong> Alex Rivera</p>
866
- <p><strong>Email:</strong> [email protected]</p>
867
- <p><strong>Phone:</strong> (555) 123-4567</p>
868
- <p><strong>Role:</strong> Senior Construction Supervisor</p>
869
- <p><strong>Company:</strong> STPL Construction</p>
870
- <p><strong>Experience:</strong> 12 years</p>
871
- </div>
872
- </div>
873
- <h3>Coaching Preferences</h3>
874
- <div class="preferences-form">
875
- <div class="toggle">
876
- <label>AI Coaching Notifications</label>
877
- <input type="checkbox" id="notifications-toggle" checked>
878
- </div>
879
- <p>Receive push notifications for new coaching tips and checklist reminders</p>
880
- <div>
881
- <label>Coaching Frequency</label>
882
- <select id="coaching-frequency">
883
- <option value="Daily">Daily</option>
884
- <option value="Weekly">Weekly</option>
885
- </select>
886
- </div>
887
- <div>
888
- <label>Preferred Time</label>
889
- <select id="preferred-time">
890
- <option value="Morning 6:00 AM">Morning 6:00 AM</option>
891
- <option value="Evening 6:00 PM">Evening 6:00 PM</option>
892
- </select>
893
- </div>
894
- <button onclick="savePreferences()">Save Preferences</button>
895
- </div>
896
  </div>
897
  </div>
898
-
899
- <!-- Toast Notifications -->
900
- <div id="error" class="toast error"></div>
901
- <div id="success" class="toast success"></div>
902
-
903
- <script>
904
- let supervisorData = {
905
- supervisor_id: 'SUP_001',
906
- role: 'Senior Construction Supervisor',
907
- project_id: 'Riverfront_001',
908
- milestones: [
909
- { name: 'Foundation Completion', status: 'Completed', progress: 100, due: '2023-10-30' },
910
- { name: 'Structural Steel Erection', status: 'In Progress', progress: 65, due: '2023-12-15' },
911
- { name: 'Building Envelope', status: 'Not Started', progress: 0, due: '2024-03-01' },
912
- { name: 'MEP Rough-in', status: 'Not Started', progress: 0, due: '2024-05-15' },
913
- { name: 'Interior Finishing', status: 'Not Started', progress: 0, due: '2024-10-30' }
914
- ],
915
- reflection_log: '',
916
- engagement_score: 87,
917
- completion_rate: 92,
918
- stress_days: 7
919
- };
920
- let coachingOutput = {
921
- checklist: [
922
- 'Review safety equipment status for concrete pouring team',
923
- 'Verify delivery of steel reinforcement for floor 3',
924
- 'Coordinate with electrical contractor on conduit installation',
925
- 'Inspect temporary weather protection measures',
926
- 'Update project timeline based on foundation completion'
927
- ],
928
- tips: [
929
- '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.',
930
- 'Team Motivation: The concrete team has been exceeding expectations. Consider acknowledging their performance in the next team meeting to boost morale.',
931
- 'Schedule Optimization: Based on current pace, electrical work can begin 2 days earlier than planned. Consider adjusting the schedule to improve overall timeline.'
932
- ],
933
- quote: 'Success is the sum of small efforts, repeated day in and day out.'
934
- };
935
- let reflectionHistory = [
936
- { 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.' },
937
- { 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.' },
938
- { 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.' }
939
- ];
940
- let checklistProgress = 0;
941
- let totalChecklistItems = coachingOutput.checklist.length;
942
- let selectedMood = '';
943
-
944
- // Toast Notification Function
945
- function showToast(id, message) {
946
- const toast = document.getElementById(id);
947
- toast.textContent = message;
948
- toast.classList.add('visible');
949
- setTimeout(() => {
950
- toast.classList.remove('visible');
951
- }, 3000);
952
- }
953
-
954
- // Navigation
955
- function showSection(section) {
956
- document.querySelectorAll('.section').forEach(s => s.style.display = 'none');
957
- document.getElementById(`${section}-section`).style.display = 'block';
958
- document.querySelectorAll('.sidebar a').forEach(a => a.classList.remove('active'));
959
- document.querySelector(`.sidebar a[href="#${section}"]`).classList.add('active');
960
- }
961
-
962
- // Checklist
963
- function markComplete(index, checkbox) {
964
- const itemDiv = checkbox.parentElement;
965
- if (checkbox.checked) {
966
- itemDiv.classList.add('completed');
967
- } else {
968
- itemDiv.classList.remove('completed');
969
- }
970
- updateChecklistProgress();
971
- showToast('success', `Checklist item ${index + 1} marked as ${checkbox.checked ? 'complete' : 'incomplete'}.`);
972
- }
973
-
974
- function updateChecklistProgress() {
975
- const completedItems = document.querySelectorAll('#checklist-items input:checked').length;
976
- checklistProgress = totalChecklistItems > 0 ? (completedItems / totalChecklistItems) * 100 : 0;
977
- }
978
-
979
- // Reflections
980
- function selectMood(mood) {
981
- selectedMood = mood;
982
- document.querySelectorAll('.mood-buttons button').forEach(btn => btn.classList.remove('active'));
983
- document.querySelector(`.mood-buttons button[onclick="selectMood('${mood}')"]`).classList.add('active');
984
- }
985
-
986
- async function submitReflection() {
987
- const reflectionInput = document.getElementById('reflection-input').value.trim();
988
-
989
- if (!reflectionInput) {
990
- showToast('error', 'Please enter a reflection before submitting.');
991
- return;
992
- }
993
-
994
- if (!selectedMood) {
995
- showToast('error', 'Please select a mood before submitting.');
996
- return;
997
- }
998
-
999
- try {
1000
- const response = await fetch('/submit_reflection', {
1001
- method: 'POST',
1002
- headers: { 'Content-Type': 'application/json' },
1003
- body: JSON.stringify({ reflection: reflectionInput, mood: selectedMood })
1004
- });
1005
- const result = await response.json();
1006
-
1007
- if (result.status === 'success') {
1008
- supervisorData.reflection_log = reflectionInput;
1009
- reflectionHistory.unshift({
1010
- date: new Date().toLocaleString(),
1011
- mood: selectedMood,
1012
- text: reflectionInput,
1013
- learned: 'To be analyzed by AI...'
1014
- });
1015
- updateReflectionHistory();
1016
- document.getElementById('reflection-input').value = '';
1017
- selectedMood = '';
1018
- document.querySelectorAll('.mood-buttons button').forEach(btn => btn.classList.remove('active'));
1019
- showToast('success', 'Reflection submitted successfully.');
1020
- } else {
1021
- showToast('error', result.message);
1022
- }
1023
- } catch (error) {
1024
- showToast('error', 'Error submitting reflection: ' + error.message);
1025
- }
1026
- }
1027
-
1028
- function updateReflectionHistory() {
1029
- const historyDiv = document.getElementById('reflection-history');
1030
- historyDiv.innerHTML = '';
1031
- if (reflectionHistory.length > 0) {
1032
- reflectionHistory.forEach(ref => {
1033
- const entryDiv = document.createElement('div');
1034
- entryDiv.className = 'entry';
1035
- entryDiv.innerHTML = `
1036
- <span class="date">${ref.date}</span><span class="mood ${ref.mood.toLowerCase()}">${ref.mood}</span>
1037
- <p>${ref.text}</p>
1038
- <p><strong>Learned:</strong> ${ref.learned}</p>
1039
- `;
1040
- historyDiv.appendChild(entryDiv);
1041
- });
1042
- } else {
1043
- historyDiv.innerHTML = '<p>No reflections yet. Start logging your thoughts!</p>';
1044
- }
1045
- }
1046
-
1047
- // Reports
1048
- async function generateReport() {
1049
- const title = document.getElementById('report-title').value.trim();
1050
- const type = document.getElementById('report-type').value;
1051
- const startDate = document.getElementById('start-date').value;
1052
- const endDate = document.getElementById('end-date').value;
1053
- const includeMetrics = document.getElementById('include-metrics').checked;
1054
- const includeReflections = document.getElementById('include-reflections').checked;
1055
-
1056
- if (!title) {
1057
- showToast('error', 'Please enter a report title.');
1058
- return;
1059
- }
1060
-
1061
- try {
1062
- const response = await fetch('/generate_pdf', {
1063
- method: 'POST',
1064
- headers: { 'Content-Type': 'application/json' },
1065
- body: JSON.stringify({
1066
- title,
1067
- type,
1068
- startDate,
1069
- endDate,
1070
- includeMetrics,
1071
- includeReflections,
1072
- checklist: coachingOutput?.checklist || [],
1073
- tips: coachingOutput?.tips || [],
1074
- milestones: supervisorData?.milestones || [],
1075
- reflections: reflectionHistory
1076
- })
1077
- });
1078
- const result = await response.json();
1079
- if (result.status === 'success') {
1080
- const reportList = document.getElementById('report-list');
1081
- const reportItem = document.createElement('div');
1082
- reportItem.className = 'report-item';
1083
- reportItem.innerHTML = `
1084
- <div>
1085
- <p>${title}</p>
1086
- <p>${new Date().toLocaleDateString()} • ${type}</p>
1087
- <p>Completion: ${supervisorData.completion_rate}% • Milestones: ${supervisorData.milestones.length} • Improvements: ${reflectionHistory.length}</p>
1088
- </div>
1089
- <div>
1090
- <span class="status">Generated</span>
1091
- <button onclick="downloadReport('${title}')">Download</button>
1092
- </div>
1093
- `;
1094
- reportList.prepend(reportItem);
1095
- showToast('success', 'Report generated successfully.');
1096
- } else {
1097
- showToast('error', result.message || 'Failed to generate report.');
1098
- }
1099
- } catch (error) {
1100
- showToast('error', 'Error generating report: ' + error.message);
1101
- }
1102
- }
1103
-
1104
- async function downloadReport(title) {
1105
- showToast('success', `Downloading report: ${title}`);
1106
- }
1107
-
1108
- // Milestones
1109
- async function syncSalesforce() {
1110
- try {
1111
- const response = await fetch('/sync_salesforce', {
1112
- method: 'POST',
1113
- headers: { 'Content-Type': 'application/json' }
1114
- });
1115
- const result = await response.json();
1116
- if (result.status === 'success') {
1117
- supervisorData.milestones = result.data.milestones;
1118
- updateMilestones();
1119
- showToast('success', 'Milestones synced with Salesforce.');
1120
- } else {
1121
- showToast('error', result.message);
1122
- }
1123
- } catch (error) {
1124
- showToast('error', 'Error syncing with Salesforce: ' + error.message);
1125
- }
1126
- }
1127
-
1128
- async function addMilestone() {
1129
- const name = prompt('Enter milestone name:');
1130
- const due = prompt('Enter due date (YYYY-MM-DD):');
1131
- if (name && due) {
1132
- supervisorData.milestones.push({
1133
- name,
1134
- status: 'Not Started',
1135
- progress: 0,
1136
- due
1137
- });
1138
- updateMilestones();
1139
- showToast('success', 'Milestone added successfully.');
1140
- } else {
1141
- showToast('error', 'Please provide both name and due date.');
1142
- }
1143
- }
1144
-
1145
- function updateMilestones() {
1146
- const milestonesDiv = document.getElementById('milestones-list');
1147
- milestonesDiv.innerHTML = '';
1148
- if (supervisorData.milestones?.length > 0) {
1149
- supervisorData.milestones.forEach(milestone => {
1150
- const milestoneDiv = document.createElement('div');
1151
- milestoneDiv.className = `milestone-item ${milestone.status.toLowerCase().replace(' ', '-')}`;
1152
- milestoneDiv.innerHTML = `
1153
- <div>
1154
- <p><strong>${milestone.name}</strong></p>
1155
- <p>Due: ${milestone.due}</p>
1156
- <p>${milestone.description || ''}</p>
1157
- <div class="progress-bar">
1158
- <div class="progress-fill" style="width: ${milestone.progress}%"></div>
1159
- </div>
1160
- </div>
1161
- <span class="status ${milestone.status.toLowerCase().replace(' ', '-')}">${milestone.status}</span>
1162
- `;
1163
- milestonesDiv.appendChild(milestoneDiv);
1164
- });
1165
- } else {
1166
- milestonesDiv.innerHTML = '<p>No milestones available.</p>';
1167
- }
1168
- }
1169
-
1170
- // Profile
1171
- async function savePreferences() {
1172
- const notifications = document.getElementById('notifications-toggle').checked;
1173
- const frequency = document.getElementById('coaching-frequency').value;
1174
- const time = document.getElementById('preferred-time').value;
1175
-
1176
- try {
1177
- const response = await fetch('/save_preferences', {
1178
- method: 'POST',
1179
- headers: { 'Content-Type': 'application/json' },
1180
- body: JSON.stringify({ notifications, frequency, time })
1181
- });
1182
- const result = await response.json();
1183
- if (result.status === 'success') {
1184
- showToast('success', 'Preferences saved successfully.');
1185
- } else {
1186
- showToast('error', result.message);
1187
- }
1188
- } catch (error) {
1189
- showToast('error', 'Error saving preferences: ' + error.message);
1190
- }
1191
- }
1192
-
1193
- // Initialize
1194
- window.onload = () => {
1195
- updateChecklistProgress();
1196
- updateReflectionHistory();
1197
- updateMilestones();
1198
- };
1199
- </script>
1200
  </body>
1201
  </html>
 
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>Construction Supervisor AI Coach</title>
7
  <style>
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  body {
9
+ font-family: Arial, sans-serif;
10
+ margin: 20px;
11
+ background-color: #f4f4f4;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  }
13
+ h1 {
14
+ text-align: center;
15
+ color: #333;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  }
17
+ .container {
18
+ max-width: 800px;
19
+ margin: 0 auto;
20
+ background: #fff;
21
  padding: 20px;
22
  border-radius: 8px;
23
+ box-shadow: 0 0 10px rgba(0,0,0,0.1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  }
25
+ .row {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  display: flex;
27
  justify-content: space-between;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  margin-bottom: 15px;
29
  }
30
+ .row div {
31
+ flex: 1;
32
+ margin-right: 10px;
 
 
 
 
 
 
 
 
 
 
33
  }
34
+ .row div:last-child {
35
+ margin-right: 0;
 
36
  }
37
+ label {
38
+ display: block;
39
+ margin-bottom: 5px;
40
+ font-weight: bold;
41
  }
42
+ select, input[type="text"], textarea {
 
43
  width: 100%;
44
+ padding: 8px;
45
+ border: 1px solid #ccc;
46
+ border-radius: 4px;
47
+ box-sizing: border-box;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  }
49
+ textarea {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  height: 80px;
51
+ resize: vertical;
 
 
 
 
 
 
 
 
 
 
 
52
  }
53
+ .button-row {
 
54
  display: flex;
55
+ justify-content: center;
56
+ margin-top: 10px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  }
 
 
58
  button {
59
  padding: 10px 20px;
60
+ background-color: #555;
61
+ color: white;
62
  border: none;
63
+ border-radius: 4px;
64
  cursor: pointer;
 
 
65
  }
 
66
  button:hover {
67
+ background-color: #666;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  }
69
+ .output {
70
+ margin-top: 20px;
71
+ padding: 10px;
72
+ border: 1px solid #ccc;
73
+ border-radius: 4px;
74
+ background-color: #f9f9f9;
75
  }
76
+ .output p:empty::before {
77
+ content: "No data available";
78
+ color: #888;
79
  }
80
+ .error {
81
+ color: red;
82
+ margin-top: 10px;
83
+ text-align: center;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  }
85
  </style>
 
86
  </head>
87
  <body>
88
+ <div class="container">
89
+ <h1>Construction Supervisor AI Coach</h1>
90
+ <form method="POST" action="{{ url_for('ui') }}">
91
+ <div class="row">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  <div>
93
+ <label for="supervisor_id">Supervisor ID</label>
94
+ <input type="text" name="supervisor_id" id="supervisor_id" value="{{ form_data.supervisor_id | default('') }}" placeholder="e.g., SUP-001">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  </div>
96
  <div>
97
+ <label for="role">Role</label>
98
+ <select name="role" id="role">
99
+ <option value="Supervisor" {% if form_data.role == 'Supervisor' %}selected{% endif %}>Supervisor</option>
100
+ <option value="Foreman" {% if form_data.role == 'Foreman' %}selected{% endif %}>Foreman</option>
101
+ <option value="Project Manager" {% if form_data.role == 'Project Manager' %}selected{% endif %}>Project Manager</option>
102
+ </select>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  </div>
104
  </div>
105
+ <div class="row">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  <div>
107
+ <label for="project_id">Project ID</label>
108
+ <input type="text" name="project_id" id="project_id" value="{{ form_data.project_id | default('') }}" placeholder="e.g., PROJ-123">
109
  </div>
110
  <div>
111
+ <label for="weather">Weather</label>
112
+ <input type="text" name="weather" id="weather" value="{{ form_data.weather | default('') }}" placeholder="e.g., Sunny, 25°C">
113
  </div>
 
114
  </div>
115
+ <div>
116
+ <label for="milestones">Milestones (comma-separated)</label>
117
+ <input type="text" name="milestones" id="milestones" value="{{ form_data.milestones | default('') }}" placeholder="e.g., Foundation complete, Framing started, Roof installed">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  </div>
119
+ <div>
120
+ <label for="reflection">Reflection</label>
121
+ <textarea name="reflection" id="reflection" placeholder="e.g., Facing delays due to weather and equipment issues.">{{ form_data.reflection | default('') }}</textarea>
 
 
 
 
 
 
 
 
 
 
122
  </div>
123
+ <div class="button-row">
124
+ <button type="submit" name="action" value="generate">Generate</button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
  </div>
126
+ </form>
127
 
128
+ {% if error %}
129
+ <div class="error">{{ error }}</div>
130
+ {% endif %}
131
+
132
+ <div class="output">
133
+ <h3>Checklist</h3>
134
+ <p>{{ output.checklist | join('<br>') | default('') | safe }}</p>
135
+ </div>
136
+ <div class="output">
137
+ <h3>Suggestions</h3>
138
+ <p>{{ output.tips | join('<br>') | default('') | safe }}</p>
139
+ </div>
140
+ <div class="output">
141
+ <h3>Quote</h3>
142
+ <p>{{ output.quote | default('') }}</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  </div>
144
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
  </body>
146
  </html>