diff --git a/assets/js/main.js b/assets/js/main.js
index 42ae33e..2bb0c77 100644
--- a/assets/js/main.js
+++ b/assets/js/main.js
@@ -41,4 +41,52 @@ document.addEventListener('DOMContentLoaded', () => {
searchInput.addEventListener('input', applyFilter);
}
-});
+
+ // Convert alerts to SweetAlert2 popups
+ (async function() {
+ if (typeof Swal === 'undefined') return;
+ const alerts = document.querySelectorAll('.alert');
+ for (const alertEl of alerts) {
+ // Don't convert if it contains interactive elements
+ if (alertEl.querySelector('form, ul, .btn, .alert-heading, a')) continue;
+
+ // Skip empty states / full page notices
+ const siblings = Array.from(alertEl.parentElement.children).filter(el => el !== alertEl && el.tagName !== 'SCRIPT' && el.tagName !== 'STYLE' && el.tagName !== 'BR');
+ if (siblings.length === 0 && (alertEl.parentElement.classList.contains('container') || alertEl.parentElement.tagName === 'MAIN' || alertEl.parentElement.classList.contains('col-12'))) {
+ continue;
+ }
+
+ // Skip heavily padded elements (likely structural empty states)
+ if (alertEl.classList.contains('py-4') || alertEl.classList.contains('py-5') || alertEl.classList.contains('py-3') || alertEl.classList.contains('alert-info')) {
+ continue; // Also explicitly skipping alert-info because they are usually informational structure blocks
+ }
+
+ let type = 'info';
+ let titleStr = document.documentElement.lang === 'ar' ? 'ملاحظة' : 'Note';
+
+ if (alertEl.classList.contains('alert-success')) {
+ type = 'success';
+ titleStr = document.documentElement.lang === 'ar' ? 'نجاح' : 'Success';
+ } else if (alertEl.classList.contains('alert-danger')) {
+ type = 'error';
+ titleStr = document.documentElement.lang === 'ar' ? 'خطأ' : 'Error';
+ } else if (alertEl.classList.contains('alert-warning')) {
+ type = 'warning';
+ titleStr = document.documentElement.lang === 'ar' ? 'تنبيه' : 'Warning';
+ }
+
+ const text = alertEl.innerText.trim();
+ if (!text) continue;
+
+ alertEl.style.display = 'none';
+
+ await Swal.fire({
+ icon: type,
+ title: titleStr,
+ text: text,
+ confirmButtonText: document.documentElement.lang === 'ar' ? 'حسنًا' : 'OK',
+ confirmButtonColor: '#0d6efd'
+ });
+ }
+ })();
+});
\ No newline at end of file
diff --git a/includes/app.php b/includes/app.php
index cdb44c9..f20cc43 100644
--- a/includes/app.php
+++ b/includes/app.php
@@ -712,6 +712,7 @@ function render_footer(): void
+