209 lines
7.6 KiB
PHP
209 lines
7.6 KiB
PHP
<!-- app/Views/partials/attendance_notification_modal.php -->
|
|
<div class="modal fade" id="notificationModal" tabindex="-1" aria-hidden="true">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<form id="notificationForm">
|
|
<?= csrf_field() ?>
|
|
<input type="hidden" id="modalStudentId" name="student_id" value="">
|
|
<input type="hidden" id="modalDate" name="date" value="<?= esc(local_date(utc_now(), 'Y-m-d')) ?>">
|
|
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Notify Parent</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
|
|
<div class="modal-body">
|
|
<!-- Recipient (editable) -->
|
|
<div class="mb-3">
|
|
<label class="form-label">To (Parent Email)</label>
|
|
<input type="email"
|
|
class="form-control"
|
|
id="parentEmail"
|
|
name="to"
|
|
required
|
|
autocomplete="email"
|
|
placeholder="parent@example.com"
|
|
list="parentEmailOptions">
|
|
<datalist id="parentEmailOptions"></datalist>
|
|
<div class="form-text" id="parentNameHelp"></div>
|
|
</div>
|
|
|
|
<!-- Subject Type -->
|
|
<div class="row g-3">
|
|
<div class="col-md-5">
|
|
<label class="form-label">Subject Type</label>
|
|
<select class="form-select" id="subjectType" name="subject_type" required>
|
|
<option value="Absent">Absent Notice</option>
|
|
<option value="Late">Late/Tardy Notice</option>
|
|
<option value="General">General Attendance Message</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-7">
|
|
<label class="form-label">Subject</label>
|
|
<input type="text" class="form-control" id="notifySubject" name="subject" required>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Message -->
|
|
<div class="mt-3">
|
|
<label class="form-label">Message</label>
|
|
<textarea class="form-control" id="notifyMessage" name="message" rows="8" required></textarea>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
|
<button type="button" id="sendNotification" class="btn btn-primary">Send Notification</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// Templates in the partial for reuse
|
|
const formatNoticeDate = (value) => {
|
|
if (!value) return '';
|
|
const date = new Date(String(value).replace(' ', 'T'));
|
|
if (Number.isNaN(date.valueOf())) return String(value);
|
|
const pad = (num) => String(num).padStart(2, '0');
|
|
return `${pad(date.getMonth() + 1)}-${pad(date.getDate())}-${date.getFullYear()}`;
|
|
};
|
|
|
|
const SUBJECT_TEMPLATES = {
|
|
Absent: (p) => {
|
|
const name = p.student_name || 'your child';
|
|
const date = p.date_fmt || formatNoticeDate(p.date) || '';
|
|
const cls = p.class_section_name ? ` (${p.class_section_name})` : '';
|
|
const reason = p.reason ? ` Reason: ${p.reason}.` : '';
|
|
const teacher = p.teacher_name ? `\nTeacher: ${p.teacher_name}` : '';
|
|
const school = p.school_name || 'Our School';
|
|
return `Dear Parent/Guardian,
|
|
|
|
This is to inform you that ${name}${cls} was marked Absent on ${date}.${reason}
|
|
|
|
If this was an error or there is additional context you would like to share, please reply to this email.
|
|
|
|
Thank you,
|
|
${school}${teacher}
|
|
`;
|
|
},
|
|
Late: (p) => {
|
|
const name = p.student_name || 'your child';
|
|
const date = p.date_fmt || formatNoticeDate(p.date) || '';
|
|
const cls = p.class_section_name ? ` (${p.class_section_name})` : '';
|
|
const reason = p.reason ? ` Reason: ${p.reason}.` : '';
|
|
const teacher = p.teacher_name ? `\nTeacher: ${p.teacher_name}` : '';
|
|
const school = p.school_name || 'Our School';
|
|
return `Dear Parent/Guardian,
|
|
|
|
This is to notify you that ${name}${cls} was marked Late on ${date}.${reason}
|
|
|
|
Please help ensure timely arrival. If you have questions, reply to this email.
|
|
|
|
Thank you,
|
|
${school}${teacher}
|
|
`;
|
|
},
|
|
General: (p) => {
|
|
const name = p.student_name || 'your child';
|
|
const date = p.date_fmt || formatNoticeDate(p.date) || '';
|
|
const cls = p.class_section_name ? ` (${p.class_section_name})` : '';
|
|
const teacher = p.teacher_name ? `\nTeacher: ${p.teacher_name}` : '';
|
|
const school = p.school_name || 'Our School';
|
|
return `Dear Parent/Guardian,
|
|
|
|
We are reaching out regarding ${name}${cls} on ${date}. Please see attendance details in the subject line.
|
|
|
|
If you have any questions, reply to this email.
|
|
|
|
Thank you,
|
|
${school}${teacher}
|
|
`;
|
|
}
|
|
};
|
|
|
|
window.buildSubject = function(subjectType, p) {
|
|
const base = p.student_name ? ` — ${p.student_name}` : '';
|
|
const dateLabel = p.date_fmt || formatNoticeDate(p.date);
|
|
const date = dateLabel ? ` (${dateLabel})` : '';
|
|
if (subjectType === 'Absent') return `Attendance Notice: Absent${base}${date}`;
|
|
if (subjectType === 'Late') return `Attendance Notice: Late${base}${date}`;
|
|
return `Attendance Notice${base}${date}`;
|
|
};
|
|
window.buildMessage = function(subjectType, payload) {
|
|
const fn = SUBJECT_TEMPLATES[subjectType] || SUBJECT_TEMPLATES.General;
|
|
return fn(payload);
|
|
};
|
|
</script>
|
|
|
|
<script>
|
|
(function () {
|
|
// Delegate so it always works, even if the modal is re-rendered
|
|
document.addEventListener('click', async function (e) {
|
|
if (!e.target || e.target.id !== 'sendNotification') return;
|
|
|
|
const form = document.getElementById('notificationForm');
|
|
if (!form) { console.error('notificationForm not found'); return; }
|
|
|
|
const toEl = document.getElementById('parentEmail');
|
|
const subjEl = document.getElementById('notifySubject');
|
|
const msgEl = document.getElementById('notifyMessage');
|
|
|
|
if (!toEl || !subjEl || !msgEl) {
|
|
console.error('Missing email/subject/message fields in the modal.');
|
|
alert('Missing fields in the modal.');
|
|
return;
|
|
}
|
|
|
|
// Basic front-end validation
|
|
if (!toEl.value.trim()) { alert('Please enter parent email'); return; }
|
|
if (!subjEl.value.trim()) { alert('Please enter a subject'); return; }
|
|
if (!msgEl.value.trim()) { alert('Please enter a message'); return; }
|
|
|
|
const formData = new FormData(form);
|
|
|
|
try {
|
|
const resp = await fetch('<?= base_url('attendance/notify_parent') ?>', {
|
|
method: 'POST',
|
|
body: formData,
|
|
headers: { 'Accept': 'application/json' }
|
|
});
|
|
|
|
// If server crashed and returned HTML, this will throw:
|
|
let data;
|
|
try { data = await resp.json(); }
|
|
catch (jsonErr) {
|
|
const text = await resp.text();
|
|
console.error('Non-JSON response', text);
|
|
alert('Server error (non-JSON). Check logs.');
|
|
return;
|
|
}
|
|
|
|
if (!resp.ok || !data || !data.success) {
|
|
console.error('Notify failed', data);
|
|
alert('Failed to send: ' + (data && data.message ? data.message : 'Unknown error'));
|
|
return;
|
|
}
|
|
|
|
alert('Notification sent successfully');
|
|
const modalEl = document.getElementById('notificationModal');
|
|
if (modalEl) {
|
|
const inst = bootstrap.Modal.getInstance(modalEl) || new bootstrap.Modal(modalEl);
|
|
inst.hide();
|
|
}
|
|
|
|
// If CSRF rotates, update hidden input
|
|
if (data.csrf) {
|
|
const [name, value] = Object.entries(data.csrf)[0];
|
|
const tokenInput = form.querySelector('input[name="'+name+'"]');
|
|
if (tokenInput) tokenInput.value = value;
|
|
}
|
|
} catch (err) {
|
|
console.error('Fetch error', err);
|
|
alert('Network or server error. See console for details.');
|
|
}
|
|
});
|
|
})();
|
|
</script>
|