698 lines
39 KiB
PHP
Executable File
698 lines
39 KiB
PHP
Executable File
<?= $this->extend('layout/management_layout') ?>
|
|
<?= $this->section('content') ?>
|
|
|
|
<?php
|
|
helper('url');
|
|
$dashboardEndpoint = $dashboardEndpoint ?? site_url('api/administrator/dashboard');
|
|
?>
|
|
|
|
<style>
|
|
/* --- Circular Stats --- */
|
|
.stat-circle {
|
|
position: relative;
|
|
width: 320px;
|
|
height: 320px;
|
|
border-radius: 50%;
|
|
margin: 0 auto;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
align-items: center;
|
|
color: #dff0cfff;
|
|
font-weight: 700;
|
|
box-shadow: 0 6px 18px rgba(0, 0, 0, .15);
|
|
transition: transform .2s ease, box-shadow .2s ease;
|
|
}
|
|
|
|
.stat-circle:hover {
|
|
transform: scale(1.05);
|
|
box-shadow: 0 10px 28px rgba(0, 0, 0, .2);
|
|
}
|
|
|
|
.stat-value {
|
|
font-size: 2rem;
|
|
line-height: 1;
|
|
}
|
|
|
|
.stat-icon {
|
|
font-size: 2.5rem;
|
|
margin-bottom: .25rem;
|
|
opacity: .85;
|
|
}
|
|
|
|
.stat-title {
|
|
font-size: 1.6rem;
|
|
margin-top: .25rem;
|
|
font-weight: 500;
|
|
opacity: .9;
|
|
text-align: center;
|
|
line-height: 1.2;
|
|
word-break: break-word;
|
|
}
|
|
|
|
.circle-primary {
|
|
background: radial-gradient(circle at 30% 30%, #0d6efd, #0044aa);
|
|
}
|
|
|
|
.circle-success {
|
|
background: radial-gradient(circle at 30% 30%, #198754, #0c4f2c);
|
|
}
|
|
|
|
.circle-warning {
|
|
background: radial-gradient(circle at 30% 30%, #daa544ff, #a66f00);
|
|
}
|
|
|
|
.circle-info {
|
|
background: radial-gradient(circle at 30% 30%, #0dcaf0, #047e9c);
|
|
}
|
|
|
|
.circle-light {
|
|
background: radial-gradient(circle at 30% 30%, #63af4cff, #00eb7dff);
|
|
}
|
|
|
|
.stats-row {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 1.5rem;
|
|
justify-content: center;
|
|
}
|
|
|
|
/* Search results */
|
|
.sr-badge {
|
|
font-size: .825rem;
|
|
}
|
|
|
|
.small-muted {
|
|
font-size: .875rem;
|
|
color: #6c757d;
|
|
}
|
|
|
|
.admin-dashboard table.mgmt-sticky > thead > tr > th,
|
|
.admin-dashboard table.mgmt-sticky > thead > tr > td,
|
|
.admin-dashboard table thead th,
|
|
.admin-dashboard table thead td {
|
|
position: static !important;
|
|
top: auto !important;
|
|
z-index: auto !important;
|
|
box-shadow: none !important;
|
|
}
|
|
</style>
|
|
|
|
<div class="container-fluid admin-dashboard" data-dashboard-endpoint="<?= esc($dashboardEndpoint) ?>">
|
|
<div class="wrapper">
|
|
<div class="content"></div>
|
|
<main>
|
|
<!-- === Welcome Section === -->
|
|
<section class="mb-4">
|
|
<h2>Welcome, <?= esc((string)session()->get('firstname')) . ' ' . esc((string)session()->get('lastname')); ?></h2>
|
|
<p>Here is an overview of your site's activity.</p>
|
|
</section>
|
|
|
|
<!-- === Search Section === -->
|
|
<section class="mb-5">
|
|
<h2 class="mb-3">Search</h2>
|
|
|
|
<div id="dashboardAlert" class="alert alert-danger d-none" role="alert"></div>
|
|
|
|
<form action="<?= site_url('administrator/administratordashboard') ?>" method="get" class="mb-3">
|
|
<div class="input-group">
|
|
<input type="text"
|
|
class="form-control"
|
|
placeholder="Search name, email, phone, school ID, RFID…"
|
|
name="query"
|
|
value="<?= esc((string)($query ?? '')) ?>"
|
|
required>
|
|
<button class="btn btn-outline-secondary" type="submit">Search</button>
|
|
</div>
|
|
<div class="form-text">Supports Users, Parents, Staff, Students, and Emergency Contacts.</div>
|
|
</form>
|
|
|
|
<?php
|
|
// Convenience flags
|
|
$hasResults = !empty($results);
|
|
$isMerged = $hasResults && array_is_list($results); // new bundle format
|
|
$isLegacy = $hasResults && !$isMerged; // old flat arrays
|
|
?>
|
|
|
|
<?php if (!empty($query)): ?>
|
|
<div class="mb-2 small-muted">
|
|
Showing results for: <strong><?= esc($query) ?></strong>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($hasResults): ?>
|
|
<?php if ($isMerged): ?>
|
|
<!-- ===== New merged bundle format ===== -->
|
|
<div class="accordion" id="searchResultsAccordion">
|
|
<?php foreach ($results as $idx => $bundle): ?>
|
|
<?php
|
|
$u = $bundle['user'] ?? null;
|
|
$fullName = trim(($u['firstname'] ?? '') . ' ' . ($u['lastname'] ?? ''));
|
|
$title = $fullName !== '' ? $fullName : 'User ID ' . (int)($u['id'] ?? 0);
|
|
$badgeCount =
|
|
count($bundle['students'] ?? []) +
|
|
count($bundle['emergency_contacts'] ?? []) +
|
|
count($bundle['parents'] ?? []) +
|
|
count($bundle['staff'] ?? []);
|
|
$headerId = 'sr-head-' . $idx;
|
|
$bodyId = 'sr-body-' . $idx;
|
|
?>
|
|
<div class="accordion-item mb-2">
|
|
<h2 class="accordion-header" id="<?= esc($headerId) ?>">
|
|
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
|
|
data-bs-target="#<?= esc($bodyId) ?>" aria-expanded="false"
|
|
aria-controls="<?= esc($bodyId) ?>">
|
|
<div class="d-flex flex-column w-100">
|
|
<div class="d-flex align-items-center justify-content-between w-100">
|
|
<span>
|
|
<i class="bi bi-person-circle me-2"></i>
|
|
<?= esc($title) ?>
|
|
</span>
|
|
<span class="badge bg-primary sr-badge"><?= (int)$badgeCount ?></span>
|
|
</div>
|
|
<div class="small text-muted">
|
|
<?php if ($u): ?>
|
|
<?= esc($u['email'] ?? '') ?>
|
|
<?php if (!empty($u['cellphone'])): ?>
|
|
· <?= esc($u['cellphone']) ?>
|
|
<?php endif; ?>
|
|
<?php if (!empty($u['city']) || !empty($u['state'])): ?>
|
|
· <?= esc(trim(($u['city'] ?? '') . ', ' . ($u['state'] ?? ''), ', ')) ?>
|
|
<?php endif; ?>
|
|
<?php else: ?>
|
|
<em>No user profile row; matched via family/students.</em>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
</button>
|
|
</h2>
|
|
<div id="<?= esc($bodyId) ?>" class="accordion-collapse collapse" aria-labelledby="<?= esc($headerId) ?>" data-bs-parent="#searchResultsAccordion">
|
|
<div class="accordion-body">
|
|
<!-- Parents / Family -->
|
|
<?php if (!empty($bundle['parents'])): ?>
|
|
<h6 class="mb-2"><i class="bi bi-people me-1"></i> Family</h6>
|
|
<div class="table-responsive mb-3">
|
|
<table class="table table-sm align-middle">
|
|
<thead>
|
|
<tr>
|
|
<th>#</th>
|
|
<th>First Parent ID</th>
|
|
<th>Second Parent</th>
|
|
<th>Email</th>
|
|
<th>Phone</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($bundle['parents'] as $i => $p): ?>
|
|
<tr>
|
|
<td><?= $i + 1 ?></td>
|
|
<td><?= esc($p['firstparent_id']) ?></td>
|
|
<td><?= esc(trim(($p['secondparent_firstname'] ?? '') . ' ' . ($p['secondparent_lastname'] ?? ''))) ?></td>
|
|
<td><?= esc($p['secondparent_email'] ?? '') ?></td>
|
|
<td><?= esc($p['secondparent_phone'] ?? '') ?></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<!-- Students -->
|
|
<?php if (!empty($bundle['students'])): ?>
|
|
<h6 class="mb-2"><i class="bi bi-mortarboard me-1"></i> Students</h6>
|
|
<div class="table-responsive mb-3">
|
|
<table class="table table-sm align-middle">
|
|
<thead>
|
|
<tr>
|
|
<th>#</th>
|
|
<th>School ID</th>
|
|
<th>Name</th>
|
|
<th>Gender</th>
|
|
<th>DOB</th>
|
|
<th>RFID</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($bundle['students'] as $i => $s): ?>
|
|
<tr>
|
|
<td><?= $i + 1 ?></td>
|
|
<td><?= esc($s['school_id']) ?></td>
|
|
<td><?= esc(trim(($s['firstname'] ?? '') . ' ' . ($s['lastname'] ?? ''))) ?></td>
|
|
<td><?= esc($s['gender'] ?? '') ?></td>
|
|
<td><?= esc($s['dob'] ?? '') ?></td>
|
|
<td><?= esc($s['rfid_tag'] ?? '') ?></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<!-- Emergency Contacts -->
|
|
<?php if (!empty($bundle['emergency_contacts'])): ?>
|
|
<h6 class="mb-2"><i class="bi bi-telephone-outbound me-1"></i> Emergency Contacts</h6>
|
|
<div class="table-responsive mb-3">
|
|
<table class="table table-sm align-middle">
|
|
<thead>
|
|
<tr>
|
|
<th>#</th>
|
|
<th>Name</th>
|
|
<th>Relation</th>
|
|
<th>Phone</th>
|
|
<th>Email</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($bundle['emergency_contacts'] as $i => $e): ?>
|
|
<tr>
|
|
<td><?= $i + 1 ?></td>
|
|
<td><?= esc($e['emergency_contact_name'] ?? '') ?></td>
|
|
<td><?= esc($e['relation'] ?? '') ?></td>
|
|
<td><?= esc($e['cellphone'] ?? '') ?></td>
|
|
<td><?= esc($e['email'] ?? '') ?></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<!-- Staff roles -->
|
|
<?php if (!empty($bundle['staff'])): ?>
|
|
<h6 class="mb-2"><i class="bi bi-person-badge me-1"></i> Staff</h6>
|
|
<div class="table-responsive">
|
|
<table class="table table-sm align-middle">
|
|
<thead>
|
|
<tr>
|
|
<th>#</th>
|
|
<th>Role</th>
|
|
<th>Name</th>
|
|
<th>Email</th>
|
|
<th>Phone</th>
|
|
<th>Status</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($bundle['staff'] as $i => $st): ?>
|
|
<tr>
|
|
<td><?= $i + 1 ?></td>
|
|
<td><?= esc($st['role_name'] ?? '') ?></td>
|
|
<td><?= esc(trim(($st['firstname'] ?? '') . ' ' . ($st['lastname'] ?? ''))) ?></td>
|
|
<td><?= esc($st['email'] ?? '') ?></td>
|
|
<td><?= esc($st['phone'] ?? '') ?></td>
|
|
<td><?= esc($st['active_role'] ?? '') ?></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php if (empty($bundle['parents']) && empty($bundle['students']) && empty($bundle['emergency_contacts']) && empty($bundle['staff'])): ?>
|
|
<div class="text-muted">No related records.</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<?php elseif ($isLegacy): ?>
|
|
<!-- ===== Legacy flat format fallback ===== -->
|
|
<div class="row g-3">
|
|
<div class="col-12 col-lg-6">
|
|
<div class="card">
|
|
<div class="card-header"><i class="bi bi-people"></i> Users</div>
|
|
<div class="card-body p-0">
|
|
<div class="table-responsive">
|
|
<table class="table table-sm mb-0">
|
|
<thead>
|
|
<tr>
|
|
<th>#</th>
|
|
<th>Name</th>
|
|
<th>Email</th>
|
|
<th>Phone</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php if (!empty($results['users'])): ?>
|
|
<?php foreach ($results['users'] as $i => $r): ?>
|
|
<tr>
|
|
<td><?= $i + 1 ?></td>
|
|
<td><?= esc(trim(($r['firstname'] ?? '') . ' ' . ($r['lastname'] ?? ''))) ?></td>
|
|
<td><?= esc($r['email'] ?? '') ?></td>
|
|
<td><?= esc($r['cellphone'] ?? '') ?></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
<?php else: ?>
|
|
<tr>
|
|
<td colspan="4" class="text-muted">No users found.</td>
|
|
</tr>
|
|
<?php endif; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-12 col-lg-6">
|
|
<div class="card">
|
|
<div class="card-header"><i class="bi bi-mortarboard"></i> Students</div>
|
|
<div class="card-body p-0">
|
|
<div class="table-responsive">
|
|
<table class="table table-sm mb-0">
|
|
<thead>
|
|
<tr>
|
|
<th>#</th>
|
|
<th>School ID</th>
|
|
<th>Name</th>
|
|
<th>DOB</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php if (!empty($results['students'])): ?>
|
|
<?php foreach ($results['students'] as $i => $s): ?>
|
|
<tr>
|
|
<td><?= $i + 1 ?></td>
|
|
<td><?= esc($s['school_id'] ?? '') ?></td>
|
|
<td><?= esc(trim(($s['firstname'] ?? '') . ' ' . ($s['lastname'] ?? ''))) ?></td>
|
|
<td><?= esc($s['dob'] ?? '') ?></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
<?php else: ?>
|
|
<tr>
|
|
<td colspan="4" class="text-muted">No students found.</td>
|
|
</tr>
|
|
<?php endif; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-12 col-lg-6">
|
|
<div class="card">
|
|
<div class="card-header"><i class="bi bi-people"></i> Parents</div>
|
|
<div class="card-body p-0">
|
|
<div class="table-responsive">
|
|
<table class="table table-sm mb-0">
|
|
<thead>
|
|
<tr>
|
|
<th>#</th>
|
|
<th>First Parent ID</th>
|
|
<th>Second Parent</th>
|
|
<th>Email</th>
|
|
<th>Phone</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php if (!empty($results['parents'])): ?>
|
|
<?php foreach ($results['parents'] as $i => $p): ?>
|
|
<tr>
|
|
<td><?= $i + 1 ?></td>
|
|
<td><?= esc($p['firstparent_id'] ?? '') ?></td>
|
|
<td><?= esc(trim(($p['secondparent_firstname'] ?? '') . ' ' . ($p['secondparent_lastname'] ?? ''))) ?></td>
|
|
<td><?= esc($p['secondparent_email'] ?? '') ?></td>
|
|
<td><?= esc($p['secondparent_phone'] ?? '') ?></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
<?php else: ?>
|
|
<tr>
|
|
<td colspan="5" class="text-muted">No parents found.</td>
|
|
</tr>
|
|
<?php endif; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-12 col-lg-6">
|
|
<div class="card">
|
|
<div class="card-header"><i class="bi bi-person-badge"></i> Staff</div>
|
|
<div class="card-body p-0">
|
|
<div class="table-responsive">
|
|
<table class="table table-sm mb-0">
|
|
<thead>
|
|
<tr>
|
|
<th>#</th>
|
|
<th>Role</th>
|
|
<th>Name</th>
|
|
<th>Email</th>
|
|
<th>Phone</th>
|
|
<th>Status</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php if (!empty($results['staff'])): ?>
|
|
<?php foreach ($results['staff'] as $i => $st): ?>
|
|
<tr>
|
|
<td><?= $i + 1 ?></td>
|
|
<td><?= esc($st['role_name'] ?? '') ?></td>
|
|
<td><?= esc(trim(($st['firstname'] ?? '') . ' ' . ($st['lastname'] ?? ''))) ?></td>
|
|
<td><?= esc($st['email'] ?? '') ?></td>
|
|
<td><?= esc($st['phone'] ?? '') ?></td>
|
|
<td><?= esc($st['active_role'] ?? '') ?></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
<?php else: ?>
|
|
<tr>
|
|
<td colspan="6" class="text-muted">No staff found.</td>
|
|
</tr>
|
|
<?php endif; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header"><i class="bi bi-telephone-outbound"></i> Emergency Contacts</div>
|
|
<div class="card-body p-0">
|
|
<div class="table-responsive">
|
|
<table class="table table-sm mb-0">
|
|
<thead>
|
|
<tr>
|
|
<th>#</th>
|
|
<th>Name</th>
|
|
<th>Relation</th>
|
|
<th>Phone</th>
|
|
<th>Email</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php if (!empty($results['emergency_contacts'])): ?>
|
|
<?php foreach ($results['emergency_contacts'] as $i => $e): ?>
|
|
<tr>
|
|
<td><?= $i + 1 ?></td>
|
|
<td><?= esc($e['emergency_contact_name'] ?? '') ?></td>
|
|
<td><?= esc($e['relation'] ?? '') ?></td>
|
|
<td><?= esc($e['cellphone'] ?? '') ?></td>
|
|
<td><?= esc($e['email'] ?? '') ?></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
<?php else: ?>
|
|
<tr>
|
|
<td colspan="5" class="text-muted">No emergency contacts found.</td>
|
|
</tr>
|
|
<?php endif; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php endif; ?>
|
|
<?php elseif (!empty($query)): ?>
|
|
<div class="alert alert-warning mb-0">No matches found.</div>
|
|
<?php endif; ?>
|
|
</section>
|
|
|
|
<!-- === Statistics Section (circular design) === -->
|
|
<section class="mb-5">
|
|
<h2 class="mb-4 text-center">Statistics</h2>
|
|
<div class="stats-row">
|
|
<div class="stat-circle circle-primary">
|
|
<div class="stat-icon"><i class="fas fa-user-graduate"></i></div>
|
|
<div class="stat-value" data-stat="students">—</div>
|
|
<div class="stat-title">Students</div>
|
|
</div>
|
|
<div class="stat-circle circle-info">
|
|
<div class="stat-icon"><i class="fas fa-chalkboard-teacher"></i></div>
|
|
<div class="stat-value" data-stat="teachers">—</div>
|
|
<div class="stat-title">Teachers</div>
|
|
</div>
|
|
<div class="stat-circle circle-success">
|
|
<div class="stat-icon"><i class="fas fa-user-cog"></i></div>
|
|
<div class="stat-value" data-stat="teacherAssistants">—</div>
|
|
<div class="stat-title">TAs</div>
|
|
</div>
|
|
<div class="stat-circle circle-warning">
|
|
<div class="stat-icon"><i class="fas fa-user-shield"></i></div>
|
|
<div class="stat-value" data-stat="admins">—</div>
|
|
<div class="stat-title">Admins</div>
|
|
</div>
|
|
<div class="stat-circle circle-light">
|
|
<div class="stat-icon"><i class="fas fa-users"></i></div>
|
|
<div class="stat-value" data-stat="parents">—</div>
|
|
<div class="stat-title">Parents</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- === Recent Activities Section === -->
|
|
<section>
|
|
<h2 class="mb-3">Recent Activities</h2>
|
|
<table class="table mt-2" data-no-mgmt-sticky>
|
|
<thead>
|
|
<tr>
|
|
<th>Date</th>
|
|
<th>Activity</th>
|
|
<th>User</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody data-activities-body>
|
|
<tr data-activities-placeholder>
|
|
<td colspan="3" class="text-muted">Loading recent activity…</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</section>
|
|
</main>
|
|
</div>
|
|
</div>
|
|
<?= $this->endSection() ?>
|
|
|
|
<?= $this->section('scripts') ?>
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
const container = document.querySelector('[data-dashboard-endpoint]');
|
|
if (!container) {
|
|
return;
|
|
}
|
|
|
|
const endpoint = container.dataset.dashboardEndpoint;
|
|
const alertBox = document.getElementById('dashboardAlert');
|
|
const numberFormatter = new Intl.NumberFormat();
|
|
const statElements = container.querySelectorAll('[data-stat]');
|
|
const activitiesBody = container.querySelector('[data-activities-body]');
|
|
|
|
const showError = (message) => {
|
|
if (!alertBox) {
|
|
return;
|
|
}
|
|
alertBox.textContent = message;
|
|
alertBox.classList.remove('d-none');
|
|
};
|
|
|
|
fetch(endpoint, {
|
|
headers: {
|
|
'Accept': 'application/json',
|
|
},
|
|
credentials: 'same-origin',
|
|
})
|
|
.then((response) => {
|
|
if (!response.ok) {
|
|
throw new Error(`Request failed with status ${response.status}`);
|
|
}
|
|
return response.json();
|
|
})
|
|
.then((payload) => {
|
|
const counts = payload && typeof payload === 'object' && payload.counts
|
|
? payload.counts
|
|
: {};
|
|
statElements.forEach((element) => {
|
|
const key = element.dataset.stat;
|
|
if (!key) {
|
|
return;
|
|
}
|
|
const value = counts[key];
|
|
element.textContent = Number.isFinite(value)
|
|
? numberFormatter.format(value)
|
|
: '—';
|
|
});
|
|
|
|
if (!activitiesBody) {
|
|
return;
|
|
}
|
|
|
|
activitiesBody.innerHTML = '';
|
|
const activities = payload && Array.isArray(payload.recentActivities)
|
|
? payload.recentActivities
|
|
: [];
|
|
|
|
if (activities.length === 0) {
|
|
const row = document.createElement('tr');
|
|
const cell = document.createElement('td');
|
|
cell.colSpan = 3;
|
|
cell.classList.add('text-muted');
|
|
cell.textContent = 'No recent activities found.';
|
|
row.appendChild(cell);
|
|
activitiesBody.appendChild(row);
|
|
return;
|
|
}
|
|
|
|
const formatDateTime = (value) => {
|
|
if (!value) {
|
|
return '—';
|
|
}
|
|
const date = new Date(value);
|
|
if (Number.isNaN(date.valueOf())) {
|
|
return String(value);
|
|
}
|
|
const pad = (num) => String(num).padStart(2, '0');
|
|
const datePart = `${pad(date.getMonth() + 1)}-${pad(date.getDate())}-${date.getFullYear()}`;
|
|
const timePart = `${pad(date.getHours())}:${pad(date.getMinutes())}`;
|
|
return `${datePart} ${timePart}`;
|
|
};
|
|
|
|
activities.forEach((activity) => {
|
|
const row = document.createElement('tr');
|
|
|
|
const toDisplayString = (value) => {
|
|
if (value === null || value === undefined || value === '') {
|
|
return '—';
|
|
}
|
|
return String(value);
|
|
};
|
|
|
|
const formattedTime = formatDateTime(activity && activity.login_time);
|
|
|
|
const timeCell = document.createElement('td');
|
|
timeCell.textContent = formattedTime;
|
|
|
|
const activityCell = document.createElement('td');
|
|
activityCell.textContent = 'Logged in';
|
|
|
|
const userCell = document.createElement('td');
|
|
userCell.textContent = toDisplayString(activity && activity.email);
|
|
|
|
row.appendChild(timeCell);
|
|
row.appendChild(activityCell);
|
|
row.appendChild(userCell);
|
|
activitiesBody.appendChild(row);
|
|
});
|
|
})
|
|
.catch((error) => {
|
|
if (activitiesBody) {
|
|
activitiesBody.innerHTML = '';
|
|
const row = document.createElement('tr');
|
|
const cell = document.createElement('td');
|
|
cell.colSpan = 3;
|
|
cell.classList.add('text-danger');
|
|
cell.textContent = 'Failed to load recent activities.';
|
|
row.appendChild(cell);
|
|
activitiesBody.appendChild(row);
|
|
}
|
|
showError(error.message || 'Unable to load dashboard metrics.');
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<?= $this->endSection() ?>
|