recreate project
This commit is contained in:
@@ -0,0 +1,208 @@
|
||||
<!-- 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>
|
||||
Reference in New Issue
Block a user