452 lines
21 KiB
PHP
452 lines
21 KiB
PHP
<?= $this->extend('layout/management_layout') ?>
|
|
<?= $this->section('content') ?>
|
|
<div class="container-fluid px-4 py-4 teacher-submissions-page">
|
|
<div class="card shadow-sm">
|
|
<div class="card-header bg-light d-flex justify-content-between align-items-center">
|
|
<div>
|
|
<strong>Teacher Submission Dashboard</strong>
|
|
</div>
|
|
<?php if (!empty($semester) || !empty($schoolYear)): ?>
|
|
<span class="small text-muted">
|
|
<?= esc(ucfirst($semester)) ?> <?= esc($schoolYear) ?>
|
|
</span>
|
|
<?php endif; ?>
|
|
</div>
|
|
<?php
|
|
$notificationHistory = $notificationHistory ?? [];
|
|
$summary = $summary ?? [];
|
|
$completionPercent = max(0, min(100, (int)($summary['submission_percentage'] ?? 0)));
|
|
$missingItemsCount = max(0, (int)($summary['missing_items'] ?? 0));
|
|
$submittedItems = max(0, (int)($summary['submitted_items'] ?? 0));
|
|
$totalItems = max(0, (int)($summary['total_items'] ?? 0));
|
|
?>
|
|
<div class="card-body">
|
|
<?php
|
|
$termExamLabel = (isset($semester) && strtolower((string) $semester) === 'spring') ? 'Final' : 'Midterm';
|
|
$lowProgressSectionIds = $lowProgressSectionIds ?? [];
|
|
$flaggedClasses = count($lowProgressSectionIds);
|
|
$pageNotifications = [];
|
|
if ($missingItemsCount > 0) {
|
|
$pageNotifications[] = [
|
|
'level' => 'danger',
|
|
'message' => "{$missingItemsCount} missing item" . ($missingItemsCount === 1 ? '' : 's') . " awaiting teacher uploads.",
|
|
];
|
|
}
|
|
if ($completionPercent < 70) {
|
|
$pageNotifications[] = [
|
|
'level' => 'warning',
|
|
'message' => "Submission completion is below 70% — follow up with remaining teachers.",
|
|
];
|
|
}
|
|
if ($flaggedClasses > 0) {
|
|
$pageNotifications[] = [
|
|
'level' => 'warning',
|
|
'message' => "Progress is under 50% for {$flaggedClasses} class section" . ($flaggedClasses === 1 ? '' : 's') . ".",
|
|
];
|
|
}
|
|
if (empty($rows)) {
|
|
$pageNotifications[] = [
|
|
'level' => 'info',
|
|
'message' => 'No class-section assignments submitted yet; encourage teachers to upload drafts.',
|
|
];
|
|
}
|
|
if (empty($pageNotifications)) {
|
|
$pageNotifications[] = [
|
|
'level' => 'info',
|
|
'message' => 'All tracked classes are current. Use the controls below to send reminders.',
|
|
];
|
|
}
|
|
$examDraftDeadlineConfig = $examDraftDeadlineConfig ?? '';
|
|
$examDraftDeadlineFormatted = $examDraftDeadlineFormatted ?? '';
|
|
?>
|
|
<?php if (session()->getFlashdata('success')): ?>
|
|
<div class="alert alert-success">
|
|
<?= esc(session()->getFlashdata('success')) ?>
|
|
</div>
|
|
<?php elseif (session()->getFlashdata('warning')): ?>
|
|
<div class="alert alert-warning">
|
|
<?= esc(session()->getFlashdata('warning')) ?>
|
|
</div>
|
|
<?php elseif (session()->getFlashdata('info')): ?>
|
|
<div class="alert alert-info">
|
|
<?= esc(session()->getFlashdata('info')) ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
<?php
|
|
$groupedRows = [];
|
|
foreach ($rows as $idx => $row) {
|
|
$classKey = (string) ($row['class_section_id'] ?? $row['class_section'] ?? 'class_' . $idx);
|
|
$groupedRows[$classKey][] = $row;
|
|
}
|
|
?>
|
|
<div class="row g-3 mb-4 align-items-stretch">
|
|
<div class="col-lg-8">
|
|
<div class="row g-3 summary-row">
|
|
<div class="col-12 col-sm-6 col-xl-3">
|
|
<div class="summary-card h-100 shadow-sm border-0">
|
|
<div class="summary-card-body">
|
|
<div class="summary-label text-uppercase">Completion</div>
|
|
<div class="summary-value"><?= esc($completionPercent) ?>%</div>
|
|
<div class="progress summary-progress">
|
|
<div
|
|
class="progress-bar"
|
|
role="progressbar"
|
|
style="width: <?= esc($completionPercent) ?>%;"
|
|
aria-valuenow="<?= esc($completionPercent) ?>"
|
|
aria-valuemin="0"
|
|
aria-valuemax="100"
|
|
></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-12 col-sm-6 col-xl-3">
|
|
<div class="summary-card h-100 shadow-sm border-0">
|
|
<div class="summary-card-body">
|
|
<div class="summary-label text-uppercase">Missing items</div>
|
|
<div class="summary-value <?= $missingItemsCount > 0 ? 'text-danger' : '' ?>"><?= esc($missingItemsCount) ?></div>
|
|
<div class="summary-note"><?= esc($submittedItems) ?> submitted / <?= esc($totalItems) ?> total</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-12 col-sm-6 col-xl-3">
|
|
<div class="summary-card h-100 shadow-sm border-0">
|
|
<div class="summary-card-body">
|
|
<div class="summary-label text-uppercase">Submissions</div>
|
|
<div class="summary-value"><?= esc($submittedItems) ?></div>
|
|
<div class="summary-note"><?= esc($totalItems) ?> teachers tracked</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-12 col-sm-6 col-xl-3">
|
|
<div class="summary-card h-100 shadow-sm border-0">
|
|
<div class="summary-card-body">
|
|
<div class="summary-label text-uppercase">Flagged</div>
|
|
<div class="summary-value"><?= esc($flaggedClasses) ?></div>
|
|
<div class="summary-note">Sections under 50% complete</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-4">
|
|
<div class="card page-notifications-card h-100 shadow-sm">
|
|
<div class="card-header d-flex justify-content-between align-items-center">
|
|
<span>Page notifications</span>
|
|
<span class="badge bg-light text-dark"><?= count($pageNotifications) ?> alerts</span>
|
|
</div>
|
|
<div class="card-body">
|
|
<ul class="page-notifications-list mb-0">
|
|
<?php foreach ($pageNotifications as $notification): ?>
|
|
<li class="page-notification-item page-notification-<?= esc($notification['level']) ?>">
|
|
<span class="notification-indicator" aria-hidden="true"></span>
|
|
<span><?= esc($notification['message']) ?></span>
|
|
</li>
|
|
<?php endforeach; ?>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<form method="post" action="<?= site_url('administrator/teacher-submissions/notify') ?>">
|
|
<?= csrf_field() ?>
|
|
<?php if (empty($rows)): ?>
|
|
<p class="text-center text-muted mt-4">No teacher-class assignments found for this term.</p>
|
|
<?php else: ?>
|
|
<div class="table-control-bar mb-3 d-flex flex-wrap align-items-center gap-3">
|
|
<div class="d-flex flex-wrap align-items-center gap-3">
|
|
<label class="form-check form-check-inline mb-0">
|
|
<input class="form-check-input" type="checkbox" name="notify_midterm_score" value="1">
|
|
<span class="form-check-label small">Include <?= esc($termExamLabel) ?> score</span>
|
|
</label>
|
|
<label class="form-check form-check-inline mb-0">
|
|
<input class="form-check-input" type="checkbox" name="notify_midterm_comment" value="1">
|
|
<span class="form-check-label small">Include <?= esc($termExamLabel) ?> comment</span>
|
|
</label>
|
|
<label class="form-check form-check-inline mb-0">
|
|
<input class="form-check-input" type="checkbox" name="notify_participation" value="1">
|
|
<span class="form-check-label small">Include participation</span>
|
|
</label>
|
|
<label class="form-check form-check-inline mb-0">
|
|
<input class="form-check-input" type="checkbox" name="notify_ptap_comment" value="1">
|
|
<span class="form-check-label small">Include PTAP comment</span>
|
|
</label>
|
|
<label class="form-check form-check-inline mb-0">
|
|
<input class="form-check-input" type="checkbox" name="notify_class_progress" value="1">
|
|
<span class="form-check-label small">Include class progress</span>
|
|
</label>
|
|
<label class="form-check form-check-inline mb-0">
|
|
<input class="form-check-input" type="checkbox" name="notify_exam_draft" value="1">
|
|
<span class="form-check-label small">Include exam draft</span>
|
|
</label>
|
|
<label class="form-check form-check-inline mb-0">
|
|
<input class="form-check-input" type="checkbox" name="homework_notify_all" value="1">
|
|
<span class="form-check-label small">Include homework</span>
|
|
</label>
|
|
</div>
|
|
<div class="small text-muted">
|
|
<span class="text-uppercase" style="font-size:0.65rem;">Exam draft deadline</span><br>
|
|
<?php if ($examDraftDeadlineConfig !== ''): ?>
|
|
<?= esc($examDraftDeadlineConfig) ?>
|
|
<?php if ($examDraftDeadlineFormatted !== ''): ?>
|
|
<span class="text-muted"> → <?= esc($examDraftDeadlineFormatted) ?></span>
|
|
<?php endif; ?>
|
|
<?php else: ?>
|
|
<span class="text-warning">Not set</span>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
<div class="accordion" id="teacherSubmissionAccordion">
|
|
<?php foreach ($groupedRows as $sectionKey => $sectionRows): ?>
|
|
<?php
|
|
$firstRow = $sectionRows[0] ?? [];
|
|
$sectionLabel = esc($firstRow['class_section'] ?? 'Class section');
|
|
$collapseId = 'teacherSectionCollapse_' . md5($sectionKey);
|
|
$badgeStatus = count($sectionRows) === 1 ? 'submission' : 'submissions';
|
|
?>
|
|
<div class="accordion-item">
|
|
<h2 class="accordion-header" id="heading_<?= esc($collapseId) ?>">
|
|
<button
|
|
class="accordion-button collapsed d-flex justify-content-between align-items-center"
|
|
type="button"
|
|
data-bs-toggle="collapse"
|
|
data-bs-target="#<?= esc($collapseId) ?>"
|
|
aria-expanded="false"
|
|
aria-controls="<?= esc($collapseId) ?>"
|
|
>
|
|
<div>
|
|
<strong><?= $sectionLabel ?></strong>
|
|
<div class="small text-muted"><?= esc(count($sectionRows)) ?> <?= $badgeStatus ?></div>
|
|
</div>
|
|
<span class="badge bg-primary-subtle text-primary"><?= count($sectionRows) ?> rows</span>
|
|
</button>
|
|
</h2>
|
|
<div id="<?= esc($collapseId) ?>" class="accordion-collapse collapse" aria-labelledby="heading_<?= esc($collapseId) ?>">
|
|
<div class="accordion-body p-0">
|
|
<div class="table-responsive">
|
|
<table
|
|
class="table table-striped table-bordered m-0 align-middle teacher-submissions-table mb-0"
|
|
data-no-mgmt-sticky
|
|
data-no-dt-fixedheader
|
|
>
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th>Class-Section</th>
|
|
<th>Teachers Name</th>
|
|
<th class="text-center"><?= esc($termExamLabel) ?> Score</th>
|
|
<th class="text-center"><?= esc($termExamLabel) ?> Comment</th>
|
|
<th class="text-center">Participation</th>
|
|
<th class="text-center">PTAP Comment</th>
|
|
<th class="text-center">Class Progress</th>
|
|
<th class="text-center">Exam Draft</th>
|
|
<th class="text-center">Homework</th>
|
|
<th class="text-center">Notifications</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($sectionRows as $row): ?>
|
|
<tr>
|
|
<td><?= esc($row['class_section']) ?></td>
|
|
<td>
|
|
<?php if (!empty($row['teachers'])): ?>
|
|
<?php foreach ($row['teachers'] as $teacher): ?>
|
|
<div><?= esc($teacher['label'] ?? 'Teacher') ?></div>
|
|
<?php endforeach; ?>
|
|
<?php else: ?>
|
|
<span class="text-muted small">Unassigned</span>
|
|
<?php endif; ?>
|
|
</td>
|
|
<?php foreach ([
|
|
'midterm_score_status',
|
|
'midterm_comment_status',
|
|
'participation_status',
|
|
'ptap_comment_status',
|
|
'class_progress_status',
|
|
'exam_draft_status',
|
|
] as $statusKey): ?>
|
|
<?php $status = $row[$statusKey] ?? ['label' => 'N/A', 'badge' => 'bg-secondary']; ?>
|
|
<td class="text-center">
|
|
<span class="badge <?= esc($status['badge'] ?? 'bg-secondary') ?>">
|
|
<?= esc($status['label'] ?? 'N/A') ?>
|
|
</span>
|
|
<?php if (!empty($status['detail'])): ?>
|
|
<div class="small text-muted"><?= esc($status['detail']) ?></div>
|
|
<?php endif; ?>
|
|
</td>
|
|
<?php endforeach; ?>
|
|
<?php $homeworkStatus = $row['homework_status'] ?? ['label' => 'N/A', 'badge' => 'bg-secondary']; ?>
|
|
<td class="text-center">
|
|
<span class="badge <?= esc($homeworkStatus['badge'] ?? 'bg-secondary') ?>">
|
|
<?= esc($homeworkStatus['label'] ?? 'N/A') ?>
|
|
</span>
|
|
<?php if (!empty($homeworkStatus['detail'])): ?>
|
|
<div class="small text-muted"><?= esc($homeworkStatus['detail']) ?></div>
|
|
<?php endif; ?>
|
|
</td>
|
|
<td>
|
|
<?php if (!empty($row['teachers'])): ?>
|
|
<?php $missingPayload = base64_encode(json_encode($row['missing_items'] ?? [])); ?>
|
|
<?php foreach ($row['teachers'] as $teacher): ?>
|
|
<?php $history = $notificationHistory[$row['class_section_id']][$teacher['id']] ?? []; ?>
|
|
<?php $lastEntry = $history[0] ?? null; ?>
|
|
<div class="mb-2">
|
|
<label class="d-flex align-items-center gap-2 mb-1">
|
|
<input
|
|
type="checkbox"
|
|
class="form-check-input"
|
|
name="notify[<?= esc($row['class_section_id']) ?>][<?= esc($teacher['id']) ?>]"
|
|
value="1"
|
|
/>
|
|
<span class="fw-semibold"><?= esc($teacher['label'] ?? 'Teacher') ?></span>
|
|
</label>
|
|
<input
|
|
type="hidden"
|
|
name="missing_items[<?= esc($row['class_section_id']) ?>][<?= esc($teacher['id']) ?>]"
|
|
value="<?= esc($missingPayload) ?>"
|
|
/>
|
|
<div class="small text-muted">
|
|
<?php if ($lastEntry !== null): ?>
|
|
<span>
|
|
Last <?= esc($lastEntry['status'] === 'sent' ? 'sent' : 'attempted') ?> on <?= esc($lastEntry['sent_at_text'] ?: 'N/A') ?>
|
|
by <?= esc($lastEntry['admin_name'] ?? '') ?>
|
|
</span>
|
|
<?php if (count($history) > 1): ?>
|
|
<div>History: <?= count($history) ?> entries</div>
|
|
<?php endif; ?>
|
|
<?php else: ?>
|
|
<span>No notifications sent yet</span>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
<?php else: ?>
|
|
<span class="text-muted small">No teacher assigned</span>
|
|
<?php endif; ?>
|
|
<?php if (!empty($row['missing_items'])): ?>
|
|
<div class="small text-danger mt-1">
|
|
Outstanding: <?= esc(implode(', ', $row['missing_items'])) ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<div class="mt-3 text-end">
|
|
<button type="submit" class="btn btn-primary">
|
|
Send notifications to selected teachers
|
|
</button>
|
|
</div>
|
|
<?php endif; ?>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?= $this->endSection() ?>
|
|
|
|
<?= $this->section('styles') ?>
|
|
<style>
|
|
.teacher-submissions-page {
|
|
width: 100%;
|
|
max-width: 100%;
|
|
}
|
|
.teacher-submissions-page .card {
|
|
width: 100%;
|
|
}
|
|
.teacher-submissions-page .table-responsive {
|
|
max-width: none;
|
|
}
|
|
.card-body .table-responsive table thead th {
|
|
position: static !important;
|
|
top: auto !important;
|
|
}
|
|
.card-body .table-responsive .teacher-submissions-table {
|
|
width: 100% !important;
|
|
min-width: 100%;
|
|
table-layout: auto;
|
|
}
|
|
.card-body .table-responsive .teacher-submissions-table th,
|
|
.card-body .table-responsive .teacher-submissions-table td {
|
|
white-space: normal;
|
|
}
|
|
|
|
.summary-card {
|
|
background: var(--bs-white);
|
|
border-radius: 0.75rem;
|
|
}
|
|
.summary-card-body {
|
|
padding: 1.25rem;
|
|
}
|
|
.summary-label {
|
|
font-size: 0.7rem;
|
|
letter-spacing: 0.08em;
|
|
color: #6c757d;
|
|
}
|
|
.summary-value {
|
|
font-size: 1.75rem;
|
|
font-weight: 600;
|
|
margin-top: 0.35rem;
|
|
}
|
|
.summary-note {
|
|
font-size: 0.85rem;
|
|
color: #6c757d;
|
|
}
|
|
.summary-progress {
|
|
height: 6px;
|
|
margin-top: 0.65rem;
|
|
}
|
|
.summary-progress .progress-bar {
|
|
background: var(--bs-primary);
|
|
}
|
|
.page-notifications-card {
|
|
border-radius: 0.75rem;
|
|
}
|
|
.page-notifications-list {
|
|
list-style: none;
|
|
padding: 0;
|
|
margin: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.5rem;
|
|
}
|
|
.page-notification-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
font-size: 0.85rem;
|
|
}
|
|
.page-notification-info .notification-indicator {
|
|
background: #0dcaf0;
|
|
}
|
|
.page-notification-warning .notification-indicator {
|
|
background: #ffc107;
|
|
}
|
|
.page-notification-danger .notification-indicator {
|
|
background: #dc3545;
|
|
}
|
|
.notification-indicator {
|
|
width: 0.75rem;
|
|
height: 0.75rem;
|
|
border-radius: 50%;
|
|
display: inline-block;
|
|
}
|
|
.table-control-bar {
|
|
border: 1px solid rgba(0,0,0,0.08);
|
|
border-radius: 0.75rem;
|
|
padding: 0.75rem 1rem;
|
|
background: #f8f9fa;
|
|
}
|
|
.table-control-bar .form-check-label {
|
|
font-size: 0.8rem;
|
|
margin-left: 0.15rem;
|
|
text-transform: none;
|
|
}
|
|
</style>
|
|
<?= $this->endSection() ?>
|