fix decisions and rank
This commit is contained in:
@@ -1,25 +1,37 @@
|
||||
<?= $this->extend('layout/management_layout') ?>
|
||||
<?= $this->section('content') ?>
|
||||
|
||||
<?php
|
||||
// This page is Whole Year only.
|
||||
// Do not expose semester filter here.
|
||||
$semester = 'year';
|
||||
?>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="wrapper below-sixty-decisions-wrapper">
|
||||
<h2 class="text-center mt-4 mb-4">Below 60 — Decisions</h2>
|
||||
|
||||
<?= $this->include('partials/academic_filter') ?>
|
||||
<h2 class="text-center mt-4 mb-4">Below 60 — Whole Year Decisions</h2>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mb-3 flex-wrap gap-2">
|
||||
<div class="text-muted">
|
||||
<?= esc(ucfirst($semester ?? '')) ?> • <?= esc($schoolYear ?? '') ?>
|
||||
Whole Year • <?= esc($schoolYear ?? '') ?>
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
|
||||
<div class="d-flex gap-2 flex-wrap">
|
||||
<a class="btn btn-outline-secondary btn-sm"
|
||||
href="<?= site_url('grading/below-60?' . http_build_query(['semester' => $semester, 'school_year' => $schoolYear])) ?>">
|
||||
href="<?= site_url('grading/below-60?' . http_build_query([
|
||||
'semester' => 'year',
|
||||
'school_year' => $schoolYear ?? '',
|
||||
])) ?>">
|
||||
← Back to Below 60
|
||||
</a>
|
||||
|
||||
<a class="btn btn-outline-primary btn-sm"
|
||||
href="<?= site_url('grading/decisions?' . http_build_query(['semester' => $semester, 'school_year' => $schoolYear])) ?>">
|
||||
href="<?= site_url('grading/decisions?' . http_build_query([
|
||||
'school_year' => $schoolYear ?? '',
|
||||
])) ?>">
|
||||
All Decisions
|
||||
</a>
|
||||
|
||||
<?php if (!empty($canViewGrading)): ?>
|
||||
<a class="btn btn-outline-secondary btn-sm" href="<?= base_url('grading') ?>">
|
||||
Grading
|
||||
@@ -34,6 +46,7 @@
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty(session()->getFlashdata('error'))): ?>
|
||||
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
||||
<?= esc(session()->getFlashdata('error')) ?>
|
||||
@@ -47,7 +60,7 @@
|
||||
'Pass' => 'Pass',
|
||||
'Repeat Class' => 'Repeat Class',
|
||||
'Make-up exam in fall' => 'Make-up exam in fall',
|
||||
'Deferred decision' => 'Deferred decision',
|
||||
'Deferred decision' => 'Deferred decision',
|
||||
'Expel' => 'Expel',
|
||||
'Withdrawn' => 'Withdrawn',
|
||||
];
|
||||
@@ -56,93 +69,136 @@
|
||||
'Pass' => 'success',
|
||||
'Repeat Class' => 'danger',
|
||||
'Make-up exam in fall' => 'info',
|
||||
'Deferred decision' => 'info',
|
||||
'Deferred decision' => 'info',
|
||||
'Expel' => 'danger',
|
||||
'Withdrawn' => 'secondary',
|
||||
];
|
||||
|
||||
$displayScore = function ($value) {
|
||||
if ($value === null || $value === '') return '—';
|
||||
if (is_numeric($value)) return esc(number_format((float)$value, 2, '.', ''));
|
||||
if ($value === null || $value === '') {
|
||||
return '—';
|
||||
}
|
||||
|
||||
if (is_numeric($value)) {
|
||||
return esc(number_format((float)$value, 2, '.', ''));
|
||||
}
|
||||
|
||||
return esc($value);
|
||||
};
|
||||
?>
|
||||
|
||||
<?php if (empty($rows)): ?>
|
||||
<div class="alert alert-success text-center d-inline-block">
|
||||
No students below 60 for this selection.
|
||||
No students below 60 for the whole year.
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered table-striped align-middle w-100 decisions-dt" data-no-mgmt-sticky data-no-dt-fixedheader>
|
||||
<table class="table table-bordered table-striped align-middle w-100 decisions-dt"
|
||||
data-no-mgmt-sticky
|
||||
data-no-dt-fixedheader>
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th style="min-width:160px">Student Name</th>
|
||||
<th>Section</th>
|
||||
<th class="text-center">Score</th>
|
||||
<th class="text-center">Year Score</th>
|
||||
<th style="min-width:300px">Comments / Rationale & Decision</th>
|
||||
<th style="min-width:150px" class="text-center">Below-60 Decision</th>
|
||||
<th style="min-width:130px" class="text-center">Final Decision</th>
|
||||
<th style="min-width:130px" class="text-center">Certificate</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<?php foreach ($rows as $row): ?>
|
||||
<?php
|
||||
$scoreRaw = $row['semester_score'] ?? null;
|
||||
$scoreVal = is_numeric($scoreRaw) ? (float)$scoreRaw : null;
|
||||
$rowClass = '';
|
||||
// Whole-year score. Prefer year_score if the controller provides it.
|
||||
// Fall/Spring details remain available through the Details modal.
|
||||
$scoreRaw = $row['year_score'] ?? $row['semester_score'] ?? null;
|
||||
$scoreVal = is_numeric($scoreRaw) ? (float)$scoreRaw : null;
|
||||
|
||||
$rowClass = '';
|
||||
if ($scoreVal !== null) {
|
||||
$rowClass = $scoreVal < 50 ? 'grade-red' : 'grade-orange';
|
||||
}
|
||||
|
||||
$studentName = trim((string)($row['firstname'] ?? '') . ' ' . (string)($row['lastname'] ?? ''));
|
||||
$studentLabel = $studentName !== '' ? $studentName : 'N/A';
|
||||
$currentDecision = (string)($row['decision'] ?? '');
|
||||
$currentNotes = (string)($row['decision_notes'] ?? '');
|
||||
$badge = $decisionBadge[$currentDecision] ?? null;
|
||||
|
||||
$finalDecision = $row['consolidated_decision'] ?? null;
|
||||
$finalBadge = $finalDecision !== null ? ($decisionBadge[$finalDecision] ?? 'secondary') : null;
|
||||
|
||||
$certNumber = (string)($row['certificate_number'] ?? '');
|
||||
?>
|
||||
|
||||
<tr class="<?= esc($rowClass) ?>">
|
||||
<td><?= esc($studentName !== '' ? $studentName : 'N/A') ?></td>
|
||||
<td><?= esc($studentLabel) ?></td>
|
||||
|
||||
<td><?= esc($row['class_section_name'] ?? '—') ?></td>
|
||||
|
||||
<td class="text-center">
|
||||
<div class="fw-semibold"><?= $displayScore($scoreRaw) ?></div>
|
||||
|
||||
<button type="button"
|
||||
class="btn btn-outline-secondary btn-xs mt-1 btn-show-details"
|
||||
style="font-size:0.72rem;padding:1px 7px;"
|
||||
data-student-id="<?= (int)($row['student_id'] ?? 0) ?>"
|
||||
data-student-name="<?= esc($studentName !== '' ? $studentName : 'N/A') ?>"
|
||||
data-student-name="<?= esc($studentLabel) ?>"
|
||||
data-school-year="<?= esc((string)($schoolYear ?? '')) ?>">
|
||||
Details
|
||||
</button>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<form method="post" action="<?= site_url('grading/below-60/decisions/save') ?>">
|
||||
<?= csrf_field() ?>
|
||||
<input type="hidden" name="student_id" value="<?= esc((string)($row['student_id'] ?? '')) ?>">
|
||||
<input type="hidden" name="semester" value="<?= esc((string)($semester ?? '')) ?>">
|
||||
<input type="hidden" name="school_year" value="<?= esc((string)($schoolYear ?? '')) ?>">
|
||||
|
||||
<input type="hidden"
|
||||
name="student_id"
|
||||
value="<?= esc((string)($row['student_id'] ?? '')) ?>">
|
||||
|
||||
<input type="hidden"
|
||||
name="semester"
|
||||
value="year">
|
||||
|
||||
<input type="hidden"
|
||||
name="school_year"
|
||||
value="<?= esc((string)($schoolYear ?? '')) ?>">
|
||||
|
||||
<textarea name="notes"
|
||||
class="form-control form-control-sm decision-notes"
|
||||
rows="3"
|
||||
placeholder="Add comments or rationale…"><?= esc($currentNotes) ?></textarea>
|
||||
|
||||
<div class="d-flex gap-2 mt-2 align-items-center">
|
||||
<select name="decision" class="form-select form-select-sm decision-select flex-grow-1">
|
||||
<select name="decision"
|
||||
class="form-select form-select-sm decision-select flex-grow-1">
|
||||
<?php foreach ($decisionOptions as $val => $label): ?>
|
||||
<option value="<?= esc($val) ?>" <?= $currentDecision === $val ? 'selected' : '' ?>>
|
||||
<?= esc($label) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<button type="submit" class="btn btn-sm btn-primary">Save</button>
|
||||
|
||||
<button type="submit" class="btn btn-sm btn-primary">
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</td>
|
||||
|
||||
<td class="text-center align-middle">
|
||||
<?php if ($currentDecision !== '' && $badge): ?>
|
||||
<span class="badge bg-<?= esc($badge) ?> fs-6 px-3 py-2 d-block mb-2"><?= esc($currentDecision) ?></span>
|
||||
<span class="badge bg-<?= esc($badge) ?> fs-6 px-3 py-2 d-block mb-2">
|
||||
<?= esc($currentDecision) ?>
|
||||
</span>
|
||||
|
||||
<button type="button"
|
||||
class="btn btn-sm btn-outline-primary btn-send-email"
|
||||
data-student-id="<?= (int)($row['student_id'] ?? 0) ?>"
|
||||
data-semester="<?= esc((string)($semester ?? '')) ?>"
|
||||
data-semester="year"
|
||||
data-school-year="<?= esc((string)($schoolYear ?? '')) ?>">
|
||||
Send Email
|
||||
</button>
|
||||
@@ -151,21 +207,21 @@
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
|
||||
<?php
|
||||
// Final (consolidated) decision from student_decisions table
|
||||
$finalDecision = $row['consolidated_decision'] ?? null;
|
||||
$finalBadge = $finalDecision !== null ? ($decisionBadge[$finalDecision] ?? 'secondary') : null;
|
||||
?>
|
||||
<td class="text-center align-middle">
|
||||
<?php if ($finalDecision !== null && $finalDecision !== ''): ?>
|
||||
<span class="badge bg-<?= esc($finalBadge) ?> px-2 py-1"><?= esc($finalDecision) ?></span>
|
||||
<span class="badge bg-<?= esc($finalBadge) ?> px-2 py-1">
|
||||
<?= esc($finalDecision) ?>
|
||||
</span>
|
||||
<?php else: ?>
|
||||
<a href="<?= site_url('grading/decisions?' . http_build_query(['semester' => $semester ?? '', 'school_year' => $schoolYear ?? ''])) ?>"
|
||||
class="text-muted small">Generate</a>
|
||||
<a href="<?= site_url('grading/decisions?' . http_build_query([
|
||||
'school_year' => $schoolYear ?? '',
|
||||
])) ?>"
|
||||
class="text-muted small">
|
||||
Generate
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
|
||||
<?php $certNumber = (string)($row['certificate_number'] ?? ''); ?>
|
||||
<td class="text-center align-middle">
|
||||
<?php if ($certNumber !== ''): ?>
|
||||
<a href="<?= site_url('administrator/certificates/reprint/' . rawurlencode($certNumber)) ?>"
|
||||
@@ -186,9 +242,14 @@
|
||||
|
||||
<div class="mt-3 mb-4 d-flex gap-2 flex-wrap">
|
||||
<?php foreach ($decisionBadge as $label => $color): ?>
|
||||
<span class="badge bg-<?= esc($color) ?> px-3 py-2"><?= esc($label) ?></span>
|
||||
<span class="badge bg-<?= esc($color) ?> px-3 py-2">
|
||||
<?= esc($label) ?>
|
||||
</span>
|
||||
<?php endforeach; ?>
|
||||
<span class="text-muted small align-self-center ms-1">— decision colour key</span>
|
||||
|
||||
<span class="text-muted small align-self-center ms-1">
|
||||
— decision colour key
|
||||
</span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
@@ -202,13 +263,19 @@
|
||||
<h5 class="modal-title" id="detailsModalLabel">Score Details</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body" id="detailsModalBody">
|
||||
<div class="text-center py-4">
|
||||
<div class="spinner-border text-primary" role="status"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Close</button>
|
||||
<button type="button"
|
||||
class="btn btn-outline-secondary"
|
||||
data-bs-dismiss="modal">
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -232,29 +299,46 @@
|
||||
<div class="alert alert-danger mb-0" id="emailModalErrorMsg"></div>
|
||||
</div>
|
||||
|
||||
<form id="decisionEmailForm" method="post"
|
||||
<form id="decisionEmailForm"
|
||||
method="post"
|
||||
action="<?= site_url('grading/below-60/decisions/email') ?>"
|
||||
style="display:none;">
|
||||
<?= csrf_field() ?>
|
||||
<input type="hidden" name="student_id" id="emailStudentId">
|
||||
<input type="hidden" name="semester" id="emailSemester">
|
||||
|
||||
<input type="hidden" name="student_id" id="emailStudentId">
|
||||
<input type="hidden" name="semester" id="emailSemester" value="year">
|
||||
<input type="hidden" name="school_year" id="emailSchoolYear">
|
||||
<input type="hidden" name="html" id="emailHtmlHidden">
|
||||
<input type="hidden" name="html" id="emailHtmlHidden">
|
||||
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-semibold" for="emailSubjectInput">Subject</label>
|
||||
<input type="text" class="form-control" id="emailSubjectInput" name="subject" required>
|
||||
<input type="text"
|
||||
class="form-control"
|
||||
id="emailSubjectInput"
|
||||
name="subject"
|
||||
required>
|
||||
</div>
|
||||
|
||||
<div class="mb-1">
|
||||
<label class="form-label fw-semibold">Body</label>
|
||||
</div>
|
||||
|
||||
<textarea id="decisionEmailEditor" rows="18"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary" id="emailSendBtn">Send Email</button>
|
||||
<button type="button"
|
||||
class="btn btn-outline-secondary"
|
||||
data-bs-dismiss="modal">
|
||||
Cancel
|
||||
</button>
|
||||
|
||||
<button type="submit"
|
||||
class="btn btn-primary"
|
||||
id="emailSendBtn">
|
||||
Send Email
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -265,34 +349,55 @@
|
||||
|
||||
<?= $this->section('scripts') ?>
|
||||
<style>
|
||||
.grade-orange td { background: #fff3cd !important; color: #8a5d00; }
|
||||
.grade-red td { background: #f8d7da !important; color: #842029; }
|
||||
.decision-notes { font-size: 0.85rem; resize: vertical; min-height: 60px; }
|
||||
.decisions-dt td { vertical-align: top; }
|
||||
.grade-orange td {
|
||||
background: #fff3cd !important;
|
||||
color: #8a5d00;
|
||||
}
|
||||
|
||||
.grade-red td {
|
||||
background: #f8d7da !important;
|
||||
color: #842029;
|
||||
}
|
||||
|
||||
.decision-notes {
|
||||
font-size: 0.85rem;
|
||||
resize: vertical;
|
||||
min-height: 60px;
|
||||
}
|
||||
|
||||
.decisions-dt td {
|
||||
vertical-align: top;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script src="<?= base_url('assets/tinymce/tinymce.min.js') ?>"></script>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
// DataTable
|
||||
if (window.$ && $.fn && $.fn.DataTable) {
|
||||
$(function () {
|
||||
const tbl = $('.decisions-dt');
|
||||
|
||||
if (!tbl.length) return;
|
||||
|
||||
try {
|
||||
tbl.DataTable({
|
||||
order: [[2, 'asc']],
|
||||
pageLength: 100,
|
||||
lengthMenu: [10, 25, 50, 100, 200],
|
||||
columnDefs: [{ orderable: false, targets: [3] }]
|
||||
columnDefs: [
|
||||
{ orderable: false, targets: [3] }
|
||||
]
|
||||
});
|
||||
} catch (_) {}
|
||||
});
|
||||
}
|
||||
|
||||
// ── Details modal ────────────────────────────────────────────
|
||||
const detailsModal = document.getElementById('detailsModal');
|
||||
const detailsModalBody = document.getElementById('detailsModalBody');
|
||||
const detailsModalTitle= document.getElementById('detailsModalLabel');
|
||||
const detailsModal = document.getElementById('detailsModal');
|
||||
const detailsModalBody = document.getElementById('detailsModalBody');
|
||||
const detailsModalTitle = document.getElementById('detailsModalLabel');
|
||||
|
||||
const SCORE_LABELS = {
|
||||
homework_avg: 'Homework Avg',
|
||||
@@ -303,7 +408,7 @@
|
||||
attendance_score: 'Attendance',
|
||||
midterm_exam_score: 'Midterm Score',
|
||||
final_exam_score: 'Final Exam',
|
||||
semester_score: 'Semester Score',
|
||||
semester_score: 'Semester Score'
|
||||
};
|
||||
|
||||
const COMMENT_TYPE_LABELS = {
|
||||
@@ -312,12 +417,14 @@
|
||||
attendance_comment: 'Attendance',
|
||||
midterm: 'Midterm',
|
||||
final: 'Final Exam',
|
||||
ptap: 'PTAP',
|
||||
ptap: 'PTAP'
|
||||
};
|
||||
|
||||
function fmtScore(v) {
|
||||
if (v === null || v === '' || v === undefined) return '—';
|
||||
|
||||
const n = parseFloat(v);
|
||||
|
||||
return isNaN(n) ? v : n.toFixed(2);
|
||||
}
|
||||
|
||||
@@ -333,78 +440,110 @@
|
||||
if (!semesters || semesters.length === 0) {
|
||||
return '<div class="alert alert-warning mb-0">No score data found.</div>';
|
||||
}
|
||||
|
||||
let html = '';
|
||||
|
||||
semesters.forEach(function (sem) {
|
||||
html += '<h6 class="fw-bold mt-3 mb-2">' + esc(sem.semester || '') + ' Semester';
|
||||
if (sem.class_section_name) html += ' <span class="text-muted fw-normal fs-6">— ' + esc(sem.class_section_name) + '</span>';
|
||||
|
||||
if (sem.class_section_name) {
|
||||
html += ' <span class="text-muted fw-normal fs-6">— ' + esc(sem.class_section_name) + '</span>';
|
||||
}
|
||||
|
||||
html += '</h6>';
|
||||
|
||||
// Scores table
|
||||
html += '<table class="table table-sm table-bordered mb-2">';
|
||||
html += '<thead class="table-light"><tr><th>Item</th><th class="text-center">Score</th></tr></thead><tbody>';
|
||||
|
||||
let hasRow = false;
|
||||
|
||||
Object.entries(SCORE_LABELS).forEach(function ([key, label]) {
|
||||
const v = sem[key];
|
||||
|
||||
if (v === null || v === '' || v === undefined) return;
|
||||
|
||||
const bold = key === 'semester_score' ? ' fw-bold' : '';
|
||||
html += '<tr><td>' + label + '</td><td class="text-center' + bold + '">' + fmtScore(v) + '</td></tr>';
|
||||
|
||||
html += '<tr><td>' + esc(label) + '</td><td class="text-center' + bold + '">' + esc(fmtScore(v)) + '</td></tr>';
|
||||
hasRow = true;
|
||||
});
|
||||
if (!hasRow) html += '<tr><td colspan="2" class="text-muted">No scores recorded.</td></tr>';
|
||||
|
||||
if (!hasRow) {
|
||||
html += '<tr><td colspan="2" class="text-muted">No scores recorded.</td></tr>';
|
||||
}
|
||||
|
||||
html += '</tbody></table>';
|
||||
|
||||
// Comments section
|
||||
const comments = sem.comments || {};
|
||||
const commentEntries = Object.entries(comments).filter(function ([, v]) { return v && v.trim(); });
|
||||
|
||||
// Deduplicate attendance + attendance_comment (show once)
|
||||
const commentEntries = Object.entries(comments).filter(function ([, v]) {
|
||||
return v && String(v).trim();
|
||||
});
|
||||
|
||||
const seen = {};
|
||||
const deduped = [];
|
||||
|
||||
commentEntries.forEach(function ([type, text]) {
|
||||
const label = COMMENT_TYPE_LABELS[type] || type;
|
||||
const key = label + '|' + text.trim();
|
||||
if (!seen[key]) { seen[key] = true; deduped.push([label, text]); }
|
||||
const key = label + '|' + String(text).trim();
|
||||
|
||||
if (!seen[key]) {
|
||||
seen[key] = true;
|
||||
deduped.push([label, String(text)]);
|
||||
}
|
||||
});
|
||||
|
||||
if (deduped.length > 0) {
|
||||
html += '<div class="mb-3">';
|
||||
html += '<p class="fw-semibold mb-1" style="font-size:0.9rem;">Comments</p>';
|
||||
|
||||
deduped.forEach(function ([label, text]) {
|
||||
html += '<div class="mb-2 p-2 bg-light rounded border-start border-3 border-secondary">';
|
||||
html += '<span class="badge bg-secondary me-1" style="font-size:0.7rem;">' + esc(label) + '</span>';
|
||||
html += '<span class="text-dark" style="font-size:0.9rem;">' + esc(text).replace(/\n/g, '<br>') + '</span>';
|
||||
html += '</div>';
|
||||
});
|
||||
|
||||
html += '</div>';
|
||||
}
|
||||
});
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
if (detailsModal) {
|
||||
document.addEventListener('click', function (e) {
|
||||
const btn = e.target.closest('.btn-show-details');
|
||||
|
||||
if (!btn) return;
|
||||
|
||||
const studentId = btn.dataset.studentId;
|
||||
const studentName= btn.dataset.studentName;
|
||||
const schoolYear = btn.dataset.schoolYear;
|
||||
const studentId = btn.dataset.studentId;
|
||||
const studentName = btn.dataset.studentName;
|
||||
const schoolYear = btn.dataset.schoolYear;
|
||||
|
||||
detailsModalTitle.textContent = studentName + ' — Score Details';
|
||||
detailsModalBody.innerHTML = '<div class="text-center py-4"><div class="spinner-border text-primary" role="status"></div></div>';
|
||||
|
||||
bootstrap.Modal.getOrCreateInstance(detailsModal).show();
|
||||
|
||||
const url = '<?= site_url('grading/below-60/decisions/student-details') ?>'
|
||||
+ '?student_id=' + encodeURIComponent(studentId)
|
||||
+ '&school_year=' + encodeURIComponent(schoolYear);
|
||||
|
||||
fetch(url, { headers: { 'X-Requested-With': 'XMLHttpRequest' } })
|
||||
.then(function (r) { return r.json(); })
|
||||
fetch(url, {
|
||||
headers: {
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
}
|
||||
})
|
||||
.then(function (r) {
|
||||
return r.json();
|
||||
})
|
||||
.then(function (data) {
|
||||
if (data.error) {
|
||||
detailsModalBody.innerHTML = '<div class="alert alert-danger">' + data.error + '</div>';
|
||||
detailsModalBody.innerHTML = '<div class="alert alert-danger">' + esc(data.error) + '</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
detailsModalBody.innerHTML = buildDetailsHtml(data.semesters);
|
||||
})
|
||||
.catch(function () {
|
||||
@@ -429,8 +568,8 @@
|
||||
|
||||
function showPane(which) {
|
||||
loadingPane.style.display = which === 'loading' ? '' : 'none';
|
||||
errorPane.style.display = which === 'error' ? '' : 'none';
|
||||
form.style.display = which === 'form' ? '' : 'none';
|
||||
errorPane.style.display = which === 'error' ? '' : 'none';
|
||||
form.style.display = which === 'form' ? '' : 'none';
|
||||
}
|
||||
|
||||
function destroyEditor() {
|
||||
@@ -441,6 +580,7 @@
|
||||
|
||||
function initEditor(html) {
|
||||
if (!window.tinymce) return;
|
||||
|
||||
tinymce.init({
|
||||
selector: '#decisionEmailEditor',
|
||||
base_url: '<?= base_url('assets/tinymce') ?>',
|
||||
@@ -462,65 +602,76 @@
|
||||
setup(editor) {
|
||||
editor.on('init', function () {
|
||||
editor.setContent(html);
|
||||
if (htmlHidden) htmlHidden.value = html;
|
||||
|
||||
if (htmlHidden) {
|
||||
htmlHidden.value = html;
|
||||
}
|
||||
});
|
||||
|
||||
editor.on('keyup change undo redo SetContent', function () {
|
||||
if (htmlHidden) htmlHidden.value = editor.getContent({ format: 'html' });
|
||||
if (htmlHidden) {
|
||||
htmlHidden.value = editor.getContent({ format: 'html' });
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Sync hidden field before form submit
|
||||
form.addEventListener('submit', function () {
|
||||
if (window.tinymce) {
|
||||
const ed = tinymce.get('decisionEmailEditor');
|
||||
if (ed && htmlHidden) htmlHidden.value = ed.getContent({ format: 'html' });
|
||||
|
||||
if (ed && htmlHidden) {
|
||||
htmlHidden.value = ed.getContent({ format: 'html' });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Destroy editor when modal closes
|
||||
modal.addEventListener('hidden.bs.modal', function () {
|
||||
destroyEditor();
|
||||
showPane('loading');
|
||||
});
|
||||
|
||||
// Open modal when "Send Email" is clicked
|
||||
document.addEventListener('click', function (e) {
|
||||
const btn = e.target.closest('.btn-send-email');
|
||||
|
||||
if (!btn) return;
|
||||
|
||||
const studentId = btn.dataset.studentId;
|
||||
const semester = btn.dataset.semester;
|
||||
const schoolYear = btn.dataset.schoolYear;
|
||||
|
||||
studentIdIn.value = studentId;
|
||||
semesterIn.value = semester;
|
||||
semesterIn.value = 'year';
|
||||
schoolYearIn.value = schoolYear;
|
||||
|
||||
showPane('loading');
|
||||
|
||||
// Open the modal immediately (shows spinner)
|
||||
const bsModal = bootstrap.Modal.getOrCreateInstance(modal);
|
||||
bsModal.show();
|
||||
|
||||
// Fetch the pre-rendered email
|
||||
const url = '<?= site_url('grading/below-60/decisions/email/preview') ?>'
|
||||
+ '?student_id=' + encodeURIComponent(studentId)
|
||||
+ '&semester=' + encodeURIComponent(semester)
|
||||
+ '&school_year='+ encodeURIComponent(schoolYear);
|
||||
+ '&semester=year'
|
||||
+ '&school_year=' + encodeURIComponent(schoolYear);
|
||||
|
||||
fetch(url, { headers: { 'X-Requested-With': 'XMLHttpRequest' } })
|
||||
.then(function (res) { return res.json(); })
|
||||
fetch(url, {
|
||||
headers: {
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
}
|
||||
})
|
||||
.then(function (res) {
|
||||
return res.json();
|
||||
})
|
||||
.then(function (data) {
|
||||
if (data.error) {
|
||||
errorMsg.textContent = data.error;
|
||||
showPane('error');
|
||||
return;
|
||||
}
|
||||
|
||||
subjectInput.value = data.subject || '';
|
||||
// Reset textarea content before init
|
||||
document.getElementById('decisionEmailEditor').value = data.html || '';
|
||||
|
||||
showPane('form');
|
||||
initEditor(data.html || '');
|
||||
})
|
||||
@@ -531,4 +682,4 @@
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
<?= $this->endSection() ?>
|
||||
<?= $this->endSection() ?>
|
||||
Reference in New Issue
Block a user