197 lines
8.6 KiB
PHP
197 lines
8.6 KiB
PHP
<?php
|
|
require_once __DIR__ . '/db/config.php';
|
|
require_once __DIR__ . '/mail/MailService.php';
|
|
require_once __DIR__ . '/ai/LocalAIApi.php';
|
|
session_start();
|
|
|
|
// Auth Check
|
|
if (!isset($_SESSION['user_id']) || $_SESSION['role'] !== 'Admin') {
|
|
header('Location: login.php');
|
|
exit;
|
|
}
|
|
|
|
$db = db();
|
|
$school_id = $_SESSION['school_id'];
|
|
$pageTitle = 'Automated Notifications | SOMS';
|
|
$message = '';
|
|
$error = '';
|
|
|
|
// Default threshold
|
|
$threshold = isset($_GET['threshold']) ? (int)$_GET['threshold'] : 50;
|
|
|
|
// Fetch learners with their averages
|
|
$query = "
|
|
SELECT
|
|
l.id,
|
|
l.full_name,
|
|
l.student_id,
|
|
l.parent_email,
|
|
l.grade,
|
|
AVG((m.marks_obtained / a.total_marks) * 100) as average_percent
|
|
FROM learners l
|
|
JOIN marks m ON l.id = m.learner_id
|
|
JOIN assessments a ON m.assessment_id = a.id
|
|
WHERE l.school_id = ?
|
|
GROUP BY l.id
|
|
HAVING average_percent < ?
|
|
";
|
|
$stmt = $db->prepare($query);
|
|
$stmt->execute([$school_id, $threshold]);
|
|
$low_performers = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
if (isset($_POST['send_notifications'])) {
|
|
$sent_count = 0;
|
|
$fail_count = 0;
|
|
$use_ai = isset($_POST['use_ai']);
|
|
|
|
foreach ($low_performers as $learner) {
|
|
if (empty($learner['parent_email'])) {
|
|
$fail_count++;
|
|
continue;
|
|
}
|
|
|
|
$avg = round($learner['average_percent'], 1);
|
|
$subject = "Urgent: Academic Progress Report for " . $learner['full_name'];
|
|
$htmlBody = "
|
|
<h3>Academic Progress Alert</h3>
|
|
<p>Dear Parent,</p>
|
|
<p>This is an automated notification regarding the academic performance of <strong>{$learner['full_name']}</strong> (ID: {$learner['student_id']}).</p>
|
|
<p>The current academic average is <strong>{$avg}%</strong>, which is below the school's monitoring threshold of {$threshold}%.</p>
|
|
<p>We encourage you to log into the Parent Portal using the Student ID to view detailed assessment marks and discuss this with the class teacher.</p>
|
|
<p>Best Regards,<br>School Administration</p>
|
|
";
|
|
|
|
if ($use_ai) {
|
|
$ai_prompt = "Generate a short, encouraging, and supportive email to a parent whose child, {$learner['full_name']}, is currently averaging {$avg}% in school (threshold is {$threshold}%). The tone should be professional yet empathetic. Mention that they can check the portal with ID {$learner['student_id']}. Keep it under 150 words.";
|
|
|
|
$ai_resp = LocalAIApi::createResponse([
|
|
'input' => [
|
|
['role' => 'system', 'content' => 'You are an educational assistant helping schools communicate with parents.'],
|
|
['role' => 'user', 'content' => $ai_prompt],
|
|
],
|
|
]);
|
|
|
|
if (!empty($ai_resp['success'])) {
|
|
$ai_text = LocalAIApi::extractText($ai_resp);
|
|
if ($ai_text) {
|
|
$htmlBody = nl2br(htmlspecialchars($ai_text));
|
|
}
|
|
}
|
|
}
|
|
|
|
$res = MailService::sendMail($learner['parent_email'], $subject, $htmlBody);
|
|
if (!empty($res['success'])) {
|
|
$sent_count++;
|
|
} else {
|
|
$fail_count++;
|
|
}
|
|
}
|
|
|
|
$message = "Successfully sent $sent_count notifications. (Failed/Missing Email: $fail_count)";
|
|
// Refresh list
|
|
$stmt->execute([$school_id, $threshold]);
|
|
$low_performers = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
}
|
|
|
|
include 'includes/header.php';
|
|
?>
|
|
|
|
<div class="container pb-5">
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<nav aria-label="breadcrumb">
|
|
<ol class="breadcrumb">
|
|
<li class="breadcrumb-item"><a href="admin.php">Dashboard</a></li>
|
|
<li class="breadcrumb-item active" aria-current="page">Notifications</li>
|
|
</ol>
|
|
</nav>
|
|
<h2 class="h4 mb-1">Automated Performance Notifications</h2>
|
|
<p class="text-muted small">Notify parents of learners performing below a specific threshold.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row g-4">
|
|
<div class="col-md-4">
|
|
<div class="card shadow-sm border-0 mb-4">
|
|
<div class="card-body">
|
|
<h5 class="fw-bold mb-3">Settings</h5>
|
|
<form action="notifications.php" method="GET" class="mb-4">
|
|
<label class="form-label small fw-bold">Performance Threshold (%)</label>
|
|
<div class="input-group">
|
|
<input type="number" name="threshold" class="form-control" value="<?= $threshold ?>" min="1" max="100">
|
|
<button class="btn btn-outline-primary" type="submit">Update List</button>
|
|
</div>
|
|
<div class="form-text small">Currently showing learners with average < <?= $threshold ?>%</div>
|
|
</form>
|
|
|
|
<form action="notifications.php?threshold=<?= $threshold ?>" method="POST">
|
|
<div class="form-check form-switch mb-3">
|
|
<input class="form-check-input" type="checkbox" name="use_ai" id="useAi" checked>
|
|
<label class="form-check-label small" for="useAi">Use AI to personalize messages</label>
|
|
</div>
|
|
<div class="d-grid">
|
|
<button type="submit" name="send_notifications" class="btn btn-primary" <?= empty($low_performers) ? 'disabled' : '' ?>>
|
|
<i class="bi bi-send me-2"></i> Send to <?= count($low_performers) ?> Parents
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="alert alert-info small border-0 shadow-sm">
|
|
<i class="bi bi-info-circle me-2"></i> Only learners with a <strong>Parent Email</strong> defined will receive notifications.
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-8">
|
|
<div class="card shadow-sm border-0">
|
|
<div class="card-header bg-white py-3">
|
|
<h5 class="mb-0 fw-bold">Learners Below Threshold (<?= $threshold ?>%)</h5>
|
|
</div>
|
|
<div class="card-body p-0">
|
|
<?php if ($message): ?>
|
|
<div class="alert alert-success m-3 small"><?= $message ?></div>
|
|
<?php endif; ?>
|
|
|
|
<div class="table-responsive">
|
|
<table class="table table-hover align-middle mb-0">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th class="ps-3">Learner</th>
|
|
<th>Grade</th>
|
|
<th>Average</th>
|
|
<th>Parent Email</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php if (empty($low_performers)): ?>
|
|
<tr>
|
|
<td colspan="4" class="text-center py-4 text-muted small">No learners found below this threshold.</td>
|
|
</tr>
|
|
<?php endif; ?>
|
|
<?php foreach ($low_performers as $learner): ?>
|
|
<tr>
|
|
<td class="ps-3">
|
|
<div class="fw-bold"><?= htmlspecialchars($learner['full_name']) ?></div>
|
|
<div class="text-muted small">ID: <?= htmlspecialchars($learner['student_id']) ?></div>
|
|
</td>
|
|
<td>Grade <?= htmlspecialchars($learner['grade']) ?></td>
|
|
<td>
|
|
<span class="badge bg-danger"><?= round($learner['average_percent'], 1) ?>%</span>
|
|
</td>
|
|
<td class="small">
|
|
<?= $learner['parent_email'] ? htmlspecialchars($learner['parent_email']) : '<span class="text-danger italic">Missing</span>' ?>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<?php include 'includes/footer.php'; ?>
|