From 35b9cba8823089d14101f7eba919dcd392906acd Mon Sep 17 00:00:00 2001 From: root Date: Sun, 1 Mar 2026 17:24:20 -0500 Subject: [PATCH] AVP-85 Active link when clicking of Parent's email address --- app/Config/Routes.php | 2 + .../View/AdministratorController.php | 2 + .../View/FamilyAdminController.php | 78 ++++++++ .../administrator/administratordashboard.php | 21 +- .../daily_attendance_analysis.php | 17 +- app/Views/emails/custom_html.php | 4 + app/Views/family/card.php | 13 +- app/Views/family/compose_email.php | 87 ++++++++ app/Views/index.php | 187 ++++++++++++++++-- 9 files changed, 380 insertions(+), 31 deletions(-) create mode 100644 app/Views/emails/custom_html.php create mode 100644 app/Views/family/compose_email.php diff --git a/app/Config/Routes.php b/app/Config/Routes.php index fd3dcd0..113b887 100644 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -1003,6 +1003,8 @@ $routes->group('family', static function ($routes) { $routes->get('index', 'View\FamilyAdminController::index'); $routes->get('search', 'View\FamilyAdminController::search'); $routes->get('card', 'View\FamilyAdminController::card'); + $routes->get('compose-email', 'View\FamilyAdminController::composeEmail'); + $routes->post('compose-email/send', 'View\FamilyAdminController::sendComposeEmail'); }); // Convenience alias $routes->get('family', 'View\FamilyAdminController::index'); diff --git a/app/Controllers/View/AdministratorController.php b/app/Controllers/View/AdministratorController.php index 6f538ae..6991201 100644 --- a/app/Controllers/View/AdministratorController.php +++ b/app/Controllers/View/AdministratorController.php @@ -416,8 +416,10 @@ class AdministratorController extends BaseController $totalStudents = (int) ( $this->db->table('student_class') ->select('COUNT(DISTINCT student_class.student_id) AS cnt') + ->join('students', 'students.id = student_class.student_id', 'inner') ->where('student_class.school_year', $this->schoolYear) ->where('student_class.class_section_id IS NOT NULL', null, false) + ->where('students.is_active', 1) ->get() ->getRow('cnt') ?? 0 diff --git a/app/Controllers/View/FamilyAdminController.php b/app/Controllers/View/FamilyAdminController.php index c35046b..10c1288 100644 --- a/app/Controllers/View/FamilyAdminController.php +++ b/app/Controllers/View/FamilyAdminController.php @@ -406,4 +406,82 @@ class FamilyAdminController extends BaseController return service('response')->setBody(view('family/card', ['f' => $family])); } + + public function composeEmail() + { + $to = trim((string)$this->request->getGet('to')); + $name = trim((string)$this->request->getGet('name')); + $returnUrl = trim((string)$this->request->getGet('return_url')); + if ($returnUrl === '') { + $returnUrl = trim((string)$this->request->getServer('HTTP_REFERER')); + } + if ($returnUrl === '') { + $returnUrl = site_url('family'); + } + + return view('family/compose_email', [ + 'to' => $to, + 'name' => $name, + 'return_url' => $returnUrl, + ]); + } + + public function sendComposeEmail() + { + if (!$this->request->is('post')) { + return redirect()->to(site_url('family')); + } + + $to = trim((string)$this->request->getPost('to')); + $subject = trim((string)$this->request->getPost('subject')); + $html = (string)($this->request->getPost('html') ?? ''); + $returnUrl = trim((string)$this->request->getPost('return_url')); + + if ($returnUrl === '' || !$this->isLocalReturnUrl($returnUrl)) { + $returnUrl = site_url('family'); + } + + if ($to === '' || !filter_var($to, FILTER_VALIDATE_EMAIL)) { + return redirect()->back()->withInput()->with('error', 'Please enter a valid email address.'); + } + if ($subject === '') { + return redirect()->back()->withInput()->with('error', 'Subject is required.'); + } + if (trim($html) === '') { + return redirect()->back()->withInput()->with('error', 'Email body is required.'); + } + + $wrapped = view('emails/custom_html', [ + 'subject' => $subject, + 'body_html' => $html, + ]); + + $mailer = new \App\Controllers\View\EmailController(); + $ok = $mailer->sendEmail($to, $subject, $wrapped, 'communication'); + + if ($ok) { + return redirect()->to($returnUrl)->with('status', 'Email sent.'); + } + + return redirect()->to($returnUrl)->with('error', 'Unable to send email.'); + } + + private function isLocalReturnUrl(string $url): bool + { + $url = trim($url); + if ($url === '') return false; + + $parts = parse_url($url); + if ($parts === false) return false; + + if (!empty($parts['scheme']) || !empty($parts['host'])) { + $base = parse_url(site_url('/')); + if (!$base || empty($base['host'])) return false; + $hostMatch = strcasecmp((string)($parts['host'] ?? ''), (string)$base['host']) === 0; + return $hostMatch; + } + + // Relative URL (e.g., /family?x=1 or family?x=1) + return true; + } } diff --git a/app/Views/administrator/administratordashboard.php b/app/Views/administrator/administratordashboard.php index 4e01d3e..7d1f6e2 100644 --- a/app/Views/administrator/administratordashboard.php +++ b/app/Views/administrator/administratordashboard.php @@ -517,37 +517,28 @@

Statistics

-
-
+
Students
- -
-
+
Teachers
- -
-
+
-
Teachers' Assistants
+
TAs
- -
-
+
Admins
- -
-
+
Parents
diff --git a/app/Views/administrator/daily_attendance_analysis.php b/app/Views/administrator/daily_attendance_analysis.php index b657146..b0ca7a7 100644 --- a/app/Views/administrator/daily_attendance_analysis.php +++ b/app/Views/administrator/daily_attendance_analysis.php @@ -71,9 +71,20 @@ max-height: none; overflow: visible; } + .attn-pie-wrap { + width: 320px; + height: 320px; + margin: 0 auto; + } @media (max-width: 1200px) { .attn-analysis-half { grid-column: span 12; } } + @media (max-width: 576px) { + .attn-pie-wrap { + width: 180px; + height: 180px; + } + } endSection() ?> @@ -291,7 +302,9 @@
Overall Distribution
- +
+ +
@@ -415,6 +428,8 @@ }] }, options: { + responsive: true, + maintainAspectRatio: false, plugins: { tooltip: { callbacks: { diff --git a/app/Views/emails/custom_html.php b/app/Views/emails/custom_html.php new file mode 100644 index 0000000..f9105c1 --- /dev/null +++ b/app/Views/emails/custom_html.php @@ -0,0 +1,4 @@ +extend('layout/email_layout') ?> +section('content') ?> + +endSection() ?> diff --git a/app/Views/family/card.php b/app/Views/family/card.php index c8e278a..c325df5 100644 --- a/app/Views/family/card.php +++ b/app/Views/family/card.php @@ -22,6 +22,10 @@ if ($title === '' || preg_match('/^\s*Family\s+of\s+User\s*\d+\s*$/i', $title)) } $title = $lastName !== '' ? ('Family of ' . $lastName) : 'Family'; } +$returnUrl = trim((string)service('request')->getServer('HTTP_REFERER')); +if ($returnUrl === '') { + $returnUrl = site_url('family'); +} ?>
@@ -187,7 +191,14 @@ if ($title === '' || preg_match('/^\s*Family\s+of\s+User\s*\d+\s*$/i', $title))
+ + +
- '.esc($g['email']).'') : '' ?> + + ' . esc($gEmail) . '') : '' ?>
diff --git a/app/Views/family/compose_email.php b/app/Views/family/compose_email.php new file mode 100644 index 0000000..78af349 --- /dev/null +++ b/app/Views/family/compose_email.php @@ -0,0 +1,87 @@ +extend('layout/management_layout') ?> +section('content') ?> + +
+
+
+

Compose Email

+ +
+ +
+ Back +
+ +
+ + + + +
+
+ + +
+
+ + +
+
+ + +
Use the toolbar to format your message before sending.
+ +
+
+ +
+
+
+
+ +endSection() ?> + +section('scripts') ?> + + +endSection() ?> diff --git a/app/Views/index.php b/app/Views/index.php index ec6547d..430b25a 100644 --- a/app/Views/index.php +++ b/app/Views/index.php @@ -322,6 +322,72 @@ min-height: 400px; } + .home-stats { + background: #ffffff; + border-radius: 16px; + box-shadow: 0 10px 24px rgba(0, 0, 0, 0.08); + padding: 2.5rem 1.5rem; + } + + .home-stats .stats-row { + display: flex; + flex-wrap: wrap; + gap: 1.5rem; + justify-content: center; + } + + .home-stats .stat-circle { + width: 190px; + height: 190px; + border-radius: 50%; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + color: #ffffff; + font-weight: 700; + box-shadow: 0 8px 18px rgba(0, 0, 0, 0.12); + } + + .home-stats .stat-value { + font-size: 1.8rem; + line-height: 1; + } + + .home-stats .stat-icon { + font-size: 2rem; + margin-bottom: .2rem; + opacity: .9; + } + + .home-stats .stat-title { + font-size: 1.1rem; + margin-top: .25rem; + font-weight: 500; + text-align: center; + line-height: 1.2; + } + + .home-stats .circle-primary { + background: radial-gradient(circle at 30% 30%, #0d6efd, #0044aa); + } + + .home-stats .circle-success { + background: radial-gradient(circle at 30% 30%, #198754, #0c4f2c); + } + + .home-stats .circle-warning { + background: radial-gradient(circle at 30% 30%, #daa544ff, #a66f00); + } + + .home-stats .circle-info { + background: radial-gradient(circle at 30% 30%, #0dcaf0, #047e9c); + } + + .home-stats .circle-light { + background: radial-gradient(circle at 30% 30%, #63af4cff, #00eb7dff); + } + @media (max-width: 992px) { .image-column { min-height: 300px; @@ -332,6 +398,13 @@ border-radius: 0 0 10px 10px !important; } } + + @media (max-width: 768px) { + .home-stats .stat-circle { + width: 160px; + height: 160px; + } + } @@ -448,8 +521,43 @@

Join Al Rahma family today! Click here for a quick guide on how to create an account.

- - + +
+
+
+

Active Participants

+
+
+
+
+
+
Students
+
+
+
+
+
Teachers
+
+
+
+
+
TAs
+
+
+
+
+
Admins
+
+
+
+
+
Parents
+
+
+
+
+
+
@@ -461,18 +569,18 @@

Under the umbrella of ISGL, Al Rahma Sunday School has been serving the community for over thirty years. Throughout the decades, it has provided students with a strong foundation in Islamic Studies and Quran, fostering both knowledge and character. With its dedicated teachers and well-rounded academic program, the school continues to guide generations of Muslim youth in their faith, values and practice of Islam.

For more information, click below to visit ISGL official website.

- - - -
- - ISGL Official Website - -
-
+
+ + ISGL Official Website + +
+
@@ -677,6 +785,57 @@ } }); +