exam draft notification and submission
This commit is contained in:
@@ -11,9 +11,36 @@ $schoolYear = $schoolYear ?? '';
|
||||
$semester = $semester ?? '';
|
||||
$maxUploadBytes = $maxUploadBytes ?? (12 * 1024 * 1024);
|
||||
?>
|
||||
<div class="container-xxl py-5">
|
||||
<style>
|
||||
.teacher-drafts-page,
|
||||
.teacher-drafts-page * {
|
||||
font-family: Arial, sans-serif !important;
|
||||
}
|
||||
.teacher-drafts-table {
|
||||
table-layout: auto;
|
||||
width: max-content;
|
||||
}
|
||||
.teacher-drafts-table th {
|
||||
min-width: 0;
|
||||
}
|
||||
.teacher-drafts-table td {
|
||||
max-width: none;
|
||||
}
|
||||
.teacher-drafts-table th {
|
||||
white-space: nowrap;
|
||||
}
|
||||
.teacher-drafts-table td.title-cell {
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
<div class="container-xxl py-5 teacher-drafts-page">
|
||||
<div class="container">
|
||||
<h1 class="mb-4">Exam drafts</h1>
|
||||
<div class="d-flex flex-wrap justify-content-between align-items-center mb-4">
|
||||
<h1 class="mb-0">Exam drafts</h1>
|
||||
<?php if (!empty($legacyExams)): ?>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" id="legacyToggle">Legacy Exams</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if (session()->getFlashdata('success')): ?>
|
||||
<div class="alert alert-success"><?= esc(session()->getFlashdata('success')) ?></div>
|
||||
@@ -24,7 +51,7 @@ $maxUploadBytes = $maxUploadBytes ?? (12 * 1024 * 1024);
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<?= form_open_multipart(base_url('teacher/exam-drafts'), ['class' => 'row g-3']) ?>
|
||||
<?= form_open_multipart(base_url('teacher/exam-drafts'), ['class' => 'row g-3', 'id' => 'examDraftForm']) ?>
|
||||
<?= csrf_field() ?>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label" for="exam_type">Exam type <span class="text-danger">*</span></label>
|
||||
@@ -65,7 +92,7 @@ $maxUploadBytes = $maxUploadBytes ?? (12 * 1024 * 1024);
|
||||
<h2 class="h5 mb-3">Your submissions</h2>
|
||||
<?php if (!empty($drafts)): ?>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped align-middle">
|
||||
<table class="table table-striped align-middle teacher-drafts-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Class</th>
|
||||
@@ -85,7 +112,7 @@ $maxUploadBytes = $maxUploadBytes ?? (12 * 1024 * 1024);
|
||||
?>
|
||||
<tr data-draft-id="<?= (int) ($d['id'] ?? 0) ?>">
|
||||
<td><?= esc($d['class_section_name'] ?? '') ?></td>
|
||||
<td><?= esc($d['draft_title'] ?? $d['exam_type'] ?? '') ?></td>
|
||||
<td class="title-cell"><?= esc($d['draft_title'] ?? $d['exam_type'] ?? '') ?></td>
|
||||
<td><?= esc((string) ($d['version'] ?? '')) ?></td>
|
||||
<td><?= $badgeHtml ?></td>
|
||||
<td>
|
||||
@@ -124,7 +151,7 @@ $maxUploadBytes = $maxUploadBytes ?? (12 * 1024 * 1024);
|
||||
—
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td class="text-nowrap"><?= esc($d['reviewer_comment'] ?? $d['admin_comments'] ?? '—') ?></td>
|
||||
<td><?= nl2br(esc($d['reviewer_comment'] ?? $d['reviewer_comments'] ?? $d['admin_comments'] ?? '—')) ?></td>
|
||||
<td><?= esc(!empty($d['updated_at']) ? local_datetime($d['updated_at'], 'm-d-Y H:i') : '') ?></td>
|
||||
|
||||
</tr>
|
||||
@@ -137,15 +164,18 @@ $maxUploadBytes = $maxUploadBytes ?? (12 * 1024 * 1024);
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($legacyExams)): ?>
|
||||
<h2 class="h5 mt-5 mb-3">Previous exams (legacy)</h2>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm table-striped align-middle">
|
||||
<div id="legacySection" class="table-responsive d-none mt-4">
|
||||
<table class="table table-sm table-striped align-middle teacher-drafts-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Class</th>
|
||||
<th>Title</th>
|
||||
<th>Ver.</th>
|
||||
<th>Status</th>
|
||||
<th>School year</th>
|
||||
<th>Semester</th>
|
||||
<th>Exam type</th>
|
||||
<th>Updated</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -154,12 +184,16 @@ $maxUploadBytes = $maxUploadBytes ?? (12 * 1024 * 1024);
|
||||
<?php $st = strtolower((string) ($d['status'] ?? '')); ?>
|
||||
<tr>
|
||||
<td><?= esc($d['class_section_name'] ?? '') ?></td>
|
||||
<td><?= esc($d['draft_title'] ?? $d['exam_type'] ?? '') ?></td>
|
||||
<td class="title-cell"><?= esc($d['draft_title'] ?? $d['exam_type'] ?? '') ?></td>
|
||||
<td><?= esc((string) ($d['version'] ?? '')) ?></td>
|
||||
<td><?= $renderBadge($st, $statusBadges) ?></td>
|
||||
<td><?= esc($d['school_year'] ?? '') ?></td>
|
||||
<td><?= esc($d['semester'] ?? '') ?></td>
|
||||
<td><?= esc($d['exam_type'] ?? '') ?></td>
|
||||
<td><?= esc(!empty($d['updated_at']) ? local_datetime($d['updated_at'], 'm-d-Y H:i') : '') ?></td>
|
||||
<td>
|
||||
<?php if (!empty($d['is_printable'])): ?>
|
||||
<a class="btn btn-sm btn-outline-primary" href="<?= base_url('teacher/exam-drafts/print/' . (int) ($d['id'] ?? 0)) ?>" target="_blank" rel="noopener">Print</a>
|
||||
<?php if (!empty($d['final_file'])): ?>
|
||||
<a class="btn btn-sm btn-outline-primary" href="<?= base_url('exam-drafts/files/final/' . $d['final_file']) ?>" target="_blank" rel="noopener">View</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -172,8 +206,41 @@ $maxUploadBytes = $maxUploadBytes ?? (12 * 1024 * 1024);
|
||||
</div>
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
<?= $this->section('scripts') ?>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const csrfTokenName = <?= json_encode(csrf_token(), JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT) ?>;
|
||||
const csrfCookieNames = <?= json_encode(array_values(array_filter([
|
||||
config('Security')->csrfCookieName ?? null,
|
||||
config('Security')->cookieName ?? null,
|
||||
'csrf_cookie_name',
|
||||
])), JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT) ?>;
|
||||
|
||||
const readCookie = (name) => {
|
||||
const match = document.cookie.match(new RegExp('(?:^|; )' + name.replace(/[$()*+.?[\\\]^{|}-]/g, '\\$&') + '=([^;]*)'));
|
||||
return match ? decodeURIComponent(match[1]) : '';
|
||||
};
|
||||
|
||||
const syncCsrfToken = (form) => {
|
||||
let tokenValue = '';
|
||||
csrfCookieNames.some((name) => {
|
||||
tokenValue = readCookie(name);
|
||||
return tokenValue !== '';
|
||||
});
|
||||
if (!tokenValue || !form) {
|
||||
return;
|
||||
}
|
||||
const tokenInput = form.querySelector(`input[name="${csrfTokenName}"]`);
|
||||
if (tokenInput) {
|
||||
tokenInput.value = tokenValue;
|
||||
}
|
||||
};
|
||||
|
||||
const draftForm = document.getElementById('examDraftForm');
|
||||
if (draftForm) {
|
||||
draftForm.addEventListener('submit', () => syncCsrfToken(draftForm));
|
||||
}
|
||||
|
||||
const statusBadges = <?= json_encode($statusBadges, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT) ?>;
|
||||
const rows = new Map();
|
||||
document.querySelectorAll('tr[data-draft-id]').forEach((row) => {
|
||||
@@ -227,5 +294,14 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
poll();
|
||||
setInterval(poll, 15000);
|
||||
}
|
||||
|
||||
const legacyToggle = document.getElementById('legacyToggle');
|
||||
const legacySection = document.getElementById('legacySection');
|
||||
if (legacyToggle && legacySection) {
|
||||
legacyToggle.addEventListener('click', () => {
|
||||
legacySection.classList.toggle('d-none');
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
Reference in New Issue
Block a user