(() => { 'use strict'; // Get API URL from configuration const getAPIBaseUrl = () => { if (window.AIMHSA && window.AIMHSA.Config) { return window.AIMHSA.Config.getApiBaseUrl(); } // Fallback to auto-detection const loc = window.location; if (loc.port === '8000') { return `${loc.protocol}//${loc.hostname}:7860`; } else if (loc.port === '7860' || loc.port === '') { return loc.origin; } else { return 'https://prodevroger-ishingiro.hf.space'; } }; const API_BASE_URL = getAPIBaseUrl(); // Elements const professionalName = document.getElementById('professionalName'); const notificationsList = document.getElementById('notificationsList'); const upcomingSessions = document.getElementById('upcomingSessions'); const sessionHistory = document.getElementById('sessionHistory'); const markAllReadBtn = document.getElementById('markAllReadBtn'); const refreshSessionsBtn = document.getElementById('refreshSessionsBtn'); const refreshNotificationsBtn = document.getElementById('refreshNotificationsBtn'); const logoutBtn = document.getElementById('logoutBtn'); const sessionModal = document.getElementById('sessionModal'); const notesModal = document.getElementById('notesModal'); const reportsModal = document.getElementById('reportsModal'); const emergencyModal = document.getElementById('emergencyModal'); const notesForm = document.getElementById('notesForm'); const followUpRequired = document.getElementById('followUpRequired'); const followUpDateGroup = document.getElementById('followUpDateGroup'); // New elements const totalSessions = document.getElementById('totalSessions'); const unreadNotifications = document.getElementById('unreadNotifications'); const upcomingToday = document.getElementById('upcomingToday'); const highRiskSessions = document.getElementById('highRiskSessions'); const sessionFilter = document.getElementById('sessionFilter'); const historyFilter = document.getElementById('historyFilter'); const viewAllSessionsBtn = document.getElementById('viewAllSessionsBtn'); const viewBookedUsersBtn = document.getElementById('viewBookedUsersBtn'); const addSessionNotesBtn = document.getElementById('addSessionNotesBtn'); const viewReportsBtn = document.getElementById('viewReportsBtn'); const emergencyContactsBtn = document.getElementById('emergencyContactsBtn'); const generateReportBtn = document.getElementById('generateReportBtn'); const reportContent = document.getElementById('reportContent'); const openIntakeBtn = document.getElementById('openIntakeBtn'); const intakeModal = document.getElementById('intakeModal'); const intakeForm = document.getElementById('intakeForm'); // Booked users elements const bookedUsersList = document.getElementById('bookedUsersList'); const userFilter = document.getElementById('userFilter'); const refreshUsersBtn = document.getElementById('refreshUsersBtn'); const userProfileModal = document.getElementById('userProfileModal'); const userProfileContent = document.getElementById('userProfileContent'); // State let currentProfessional = null; let notifications = []; let sessions = []; let bookedUsers = []; let currentSessionId = null; // Initialize init(); async function init() { // Check if professional is logged in const professionalData = localStorage.getItem('aimhsa_professional'); if (!professionalData) { // Check if they're logged in as a different type of user const userData = localStorage.getItem('aimhsa_account'); const adminData = localStorage.getItem('aimhsa_admin'); if (userData && userData !== 'null') { alert('You are logged in as a regular user. Please logout and login as a professional.'); window.location.href = '/'; return; } if (adminData) { alert('You are logged in as an admin. Please logout and login as a professional.'); window.location.href = '/admin_dashboard.html'; return; } window.location.href = '/login'; return; } currentProfessional = JSON.parse(professionalData); professionalName.textContent = currentProfessional.name; // Load initial data await loadDashboardData(); await loadNotifications(); await loadSessions(); await loadBookedUsers(); // Set up auto-refresh setInterval(loadDashboardData, 30000); // Every 30 seconds setInterval(loadNotifications, 30000); // Every 30 seconds setInterval(loadSessions, 60000); // Every minute // Set up event listeners setupEventListeners(); } // API Helper async function api(path, opts = {}) { const url = API_BASE_URL + path; const headers = { 'Content-Type': 'application/json', ...opts.headers }; // Include professional id header if available if (currentProfessional?.professional_id) { headers['X-Professional-ID'] = String(currentProfessional.professional_id); } const res = await fetch(url, { headers, ...opts }); if (!res.ok) { const txt = await res.text(); throw new Error(txt || res.statusText); } return await res.json(); } function setupEventListeners() { // Logout logoutBtn.addEventListener('click', logout); // Notifications markAllReadBtn.addEventListener('click', markAllNotificationsRead); refreshNotificationsBtn.addEventListener('click', loadNotifications); // Sessions refreshSessionsBtn.addEventListener('click', loadSessions); sessionFilter.addEventListener('change', filterSessions); historyFilter.addEventListener('change', filterSessionHistory); // Quick actions viewAllSessionsBtn.addEventListener('click', () => { sessionFilter.value = 'all'; loadSessions(); }); viewBookedUsersBtn.addEventListener('click', () => { userFilter.value = 'all'; loadBookedUsers(); }); addSessionNotesBtn.addEventListener('click', openNotesModal); viewReportsBtn.addEventListener('click', openReportsModal); emergencyContactsBtn.addEventListener('click', openEmergencyModal); openIntakeBtn.addEventListener('click', openIntakeModal); // Booked users refreshUsersBtn.addEventListener('click', loadBookedUsers); userFilter.addEventListener('change', filterBookedUsers); // Modals document.querySelectorAll('.close').forEach(closeBtn => { closeBtn.addEventListener('click', closeModals); }); // Notes form notesForm.addEventListener('submit', saveSessionNotes); followUpRequired.addEventListener('change', toggleFollowUpDate); intakeForm.addEventListener('submit', submitIntakeForm); // Report generation generateReportBtn.addEventListener('click', generateReport); // Close modals when clicking outside window.addEventListener('click', (e) => { if (e.target.classList.contains('modal')) { closeModals(); } }); } async function loadDashboardData() { try { // Load dashboard stats const stats = await api('/professional/dashboard-stats'); updateDashboardStats(stats); } catch (error) { console.error('Error loading dashboard data:', error); } } async function loadNotifications() { try { const data = await api('/professional/notifications'); notifications = data; displayNotifications(notifications); } catch (error) { console.error('Error loading notifications:', error); notificationsList.innerHTML = '

Error loading notifications

'; } } async function loadSessions() { try { const data = await api('/professional/sessions'); sessions = data; displaySessions(sessions); } catch (error) { console.error('Error loading sessions:', error); upcomingSessions.innerHTML = '

Error loading sessions

'; } } async function loadBookedUsers() { try { const data = await api('/professional/booked-users'); bookedUsers = data.users || []; displayBookedUsers(bookedUsers); } catch (error) { console.error('Error loading booked users:', error); bookedUsersList.innerHTML = '

Error loading booked users

'; } } function updateDashboardStats(stats) { totalSessions.textContent = stats.totalSessions || 0; unreadNotifications.textContent = stats.unreadNotifications || 0; upcomingToday.textContent = stats.upcomingToday || 0; highRiskSessions.textContent = stats.highRiskCases || 0; } function displayNotifications(notificationsData) { if (!notificationsData || notificationsData.length === 0) { notificationsList.innerHTML = '

No notifications

'; return; } notificationsList.innerHTML = notificationsData.map(notification => `
${notification.title}
${notification.message}
${formatDateTime(notification.createdAt)}
`).join(''); } function displaySessions(sessionsData) { if (!sessionsData || sessionsData.length === 0) { upcomingSessions.innerHTML = '

No sessions found

'; return; } upcomingSessions.innerHTML = sessionsData.map(session => `
${session.userName ? session.userName.charAt(0).toUpperCase() : 'U'}
${session.bookingStatus}
Session Type: ${session.sessionType}
Scheduled: ${formatDateTime(session.scheduledDatetime)}
Risk Level: ${session.riskLevel}
Risk Score: ${session.riskScore}/100
${session.userPhone ? `
📞 Contact: ${session.userPhone}
` : ''} ${session.userEmail ? `
📧 Email: ${session.userEmail}
` : ''} ${session.userLocation ? `
📍 Location: ${session.userLocation}
` : ''}
${session.bookingStatus === 'pending' ? ` ` : ''}
`).join(''); } function filterSessions() { const filter = sessionFilter.value; let filteredSessions = sessions; switch(filter) { case 'today': filteredSessions = sessions.filter(session => isToday(new Date(session.scheduledDatetime * 1000))); break; case 'this_week': filteredSessions = sessions.filter(session => isThisWeek(new Date(session.scheduledDatetime * 1000))); break; case 'high_risk': filteredSessions = sessions.filter(session => session.riskLevel === 'high' || session.riskLevel === 'critical'); break; } displaySessions(filteredSessions); } function filterSessionHistory() { const filter = historyFilter.value; // Implementation for filtering session history console.log('Filtering session history by:', filter); } function displayBookedUsers(usersData) { if (!usersData || usersData.length === 0) { bookedUsersList.innerHTML = '

No booked users found

'; return; } bookedUsersList.innerHTML = usersData.map(user => `
${user.fullName.charAt(0).toUpperCase()}
Email: ${user.email}
Phone: ${user.telephone}
Location: ${user.district}, ${user.province}
Total Bookings: ${user.totalBookings}
Highest Risk Score: ${user.highestRiskScore}/100
Last Booking: ${formatDateTime(user.lastBookingTime)}
`).join(''); } function filterBookedUsers() { const filter = userFilter.value; let filteredUsers = bookedUsers; switch(filter) { case 'high_risk': filteredUsers = bookedUsers.filter(user => user.highestRiskLevel === 'high' || user.highestRiskLevel === 'critical' ); break; case 'recent': const oneWeekAgo = Date.now() - (7 * 24 * 60 * 60 * 1000); filteredUsers = bookedUsers.filter(user => user.lastBookingTime * 1000 > oneWeekAgo ); break; case 'multiple_sessions': filteredUsers = bookedUsers.filter(user => user.totalBookings > 1); break; } displayBookedUsers(filteredUsers); } async function markAllNotificationsRead() { try { await api('/professional/notifications/mark-all-read', { method: 'POST' }); await loadNotifications(); await loadDashboardData(); } catch (error) { console.error('Error marking notifications as read:', error); } } async function markNotificationRead(notificationId) { try { await api(`/professional/notifications/${notificationId}/read`, { method: 'POST' }); await loadNotifications(); await loadDashboardData(); } catch (error) { console.error('Error marking notification as read:', error); } } async function acceptSession(bookingId) { try { await api(`/professional/sessions/${bookingId}/accept`, { method: 'POST' }); await loadSessions(); await loadDashboardData(); alert('Session accepted successfully'); } catch (error) { console.error('Error accepting session:', error); alert('Failed to accept session'); } } async function declineSession(bookingId) { try { await api(`/professional/sessions/${bookingId}/decline`, { method: 'POST' }); await loadSessions(); await loadDashboardData(); alert('Session declined'); } catch (error) { console.error('Error declining session:', error); alert('Failed to decline session'); } } async function viewSessionDetails(bookingId) { try { currentSessionId = bookingId; const sessionDetails = await api(`/professional/sessions/${bookingId}`); // Convert the detailed session data to the format expected by displaySessionDetailsModal const session = { bookingId: sessionDetails.bookingId, convId: sessionDetails.convId, userAccount: sessionDetails.userAccount, userName: sessionDetails.userName, userIp: sessionDetails.userIp, riskLevel: sessionDetails.riskLevel, riskScore: sessionDetails.riskScore, detectedIndicators: sessionDetails.detectedIndicators, conversationSummary: sessionDetails.conversationSummary, bookingStatus: sessionDetails.bookingStatus, scheduledDatetime: sessionDetails.scheduledDatetime, sessionType: sessionDetails.sessionType, createdTs: sessionDetails.createdTs, updatedTs: sessionDetails.updatedTs, userPhone: sessionDetails.userPhone, userEmail: sessionDetails.userEmail, userLocation: sessionDetails.userLocation }; displaySessionDetailsModal(session, sessionDetails); } catch (error) { console.error('Error loading session details:', error); alert('Failed to load session details'); } } async function displaySessionDetailsModal(session, sessionDetails = null) { const modal = document.getElementById('sessionModal'); const content = document.getElementById('sessionDetails'); let userInfo = null; // If sessionDetails is provided, extract user information from it if (sessionDetails) { userInfo = { userAccount: sessionDetails.userAccount, fullName: sessionDetails.userFullName, email: sessionDetails.userEmail, telephone: sessionDetails.userPhone, province: sessionDetails.userProvince, district: sessionDetails.userDistrict, userCreatedAt: sessionDetails.userCreatedAt, totalBookings: sessionDetails.sessions ? sessionDetails.sessions.length : 0, highestRiskLevel: sessionDetails.riskAssessments && sessionDetails.riskAssessments.length > 0 ? sessionDetails.riskAssessments[0].riskLevel : 'unknown', highestRiskScore: sessionDetails.riskAssessments && sessionDetails.riskAssessments.length > 0 ? Math.max(...sessionDetails.riskAssessments.map(r => r.riskScore)) : 0, firstBookingTime: sessionDetails.sessions && sessionDetails.sessions.length > 0 ? Math.min(...sessionDetails.sessions.map(s => s.createdTs)) : null, lastBookingTime: sessionDetails.sessions && sessionDetails.sessions.length > 0 ? Math.max(...sessionDetails.sessions.map(s => s.createdTs)) : null, sessions: sessionDetails.sessions || [], riskAssessments: sessionDetails.riskAssessments || [], conversations: sessionDetails.conversationHistory || [] }; } else { // Fallback: try to get user info from booked users or API try { const user = bookedUsers.find(u => u.userAccount === session.userAccount); if (user) { userInfo = user; } else { // Try to get from individual user API userInfo = await api(`/professional/users/${session.userAccount}`); } } catch (fallbackError) { console.error('Error loading user info:', fallbackError); } } content.innerHTML = `
${session.userName ? session.userName.charAt(0).toUpperCase() : 'U'}

${session.userName || 'Anonymous User'}

Booking ID: ${session.bookingId} ${formatDateTime(session.scheduledDatetime)}
${session.bookingStatus.toUpperCase()}

📋 Session Details

Session Type: ${session.sessionType}
Scheduled Time: ${formatDateTime(session.scheduledDatetime)}
Created: ${formatDateTime(session.createdTs)}
Last Updated: ${formatDateTime(session.updatedTs)}

⚠️ Risk Assessment

${session.riskLevel.toUpperCase()}
${session.riskScore}/100
${session.detectedIndicators ? `

Detected Indicators:

${JSON.parse(session.detectedIndicators).slice(0, 5).map(indicator => ` ${indicator} `).join('')} ${JSON.parse(session.detectedIndicators).length > 5 ? ` +${JSON.parse(session.detectedIndicators).length - 5} more ` : ''}
` : ''}

📞 Contact Information

${session.userPhone ? ` ` : ''} ${session.userEmail ? ` ` : ''} ${session.userLocation ? `
📍
Location ${session.userLocation}
` : ''}
${userInfo ? `

👤 Complete User Profile

${userInfo.sessions && userInfo.sessions.length > 0 ? `

📅 Recent Sessions (Last 5)

${userInfo.sessions.slice(0, 5).map(s => `
${s.sessionType} ${s.bookingStatus}
Risk: ${s.riskLevel} (${s.riskScore}/100) ${formatDateTime(s.scheduledDatetime)}
${s.bookingId === session.bookingId ? '
Current Session
' : ''}
`).join('')}
` : ''} ${userInfo.riskAssessments && userInfo.riskAssessments.length > 0 ? `

📈 Risk Assessment History

${userInfo.riskAssessments.slice(0, 5).map(risk => `
${risk.riskLevel} ${risk.riskScore}/100
${formatDateTime(risk.timestamp)}
`).join('')}
` : ''} ${userInfo.conversations && userInfo.conversations.length > 0 ? `

💬 Recent Conversations

${userInfo.conversations.slice(0, 3).map(conv => `
${conv.preview}
${formatDateTime(conv.timestamp)}
`).join('')}
` : ''}
` : ''} ${session.conversationSummary ? `

💭 Conversation Summary

${session.conversationSummary}

` : ''} ${sessionDetails ? `

📋 Additional Session Information

${sessionDetails.conversationHistory && sessionDetails.conversationHistory.length > 0 ? `

💬 Full Conversation

${sessionDetails.conversationHistory.map(msg => `
${msg.content}
${formatDateTime(msg.timestamp)}
`).join('')}
` : ''} ${sessionDetails.sessionNotes && sessionDetails.sessionNotes.notes ? `

📝 Session Notes

${sessionDetails.sessionNotes.notes}

` : ''} ${sessionDetails.sessionNotes && sessionDetails.sessionNotes.treatmentPlan ? `

🎯 Treatment Plan

${sessionDetails.sessionNotes.treatmentPlan}

` : ''}
` : ''}
`; modal.style.display = 'block'; } function openNotesModal() { notesModal.style.display = 'block'; } function openReportsModal() { reportsModal.style.display = 'block'; } function openEmergencyModal() { emergencyModal.style.display = 'block'; } async function viewUserProfile(userAccount) { try { // Try to get user from booked users first let user = bookedUsers.find(u => u.userAccount === userAccount); if (!user) { // If not found, get from API user = await api(`/professional/users/${userAccount}`); } if (!user) { alert('User not found'); return; } displayUserProfileModal(user); } catch (error) { console.error('Error loading user profile:', error); alert('Failed to load user profile'); } } function displayUserProfileModal(user) { userProfileContent.innerHTML = `
${user.fullName.charAt(0).toUpperCase()}

${user.fullName}

@${user.userAccount}

${user.highestRiskLevel.toUpperCase()}

Contact Information

Email: ${user.email}
Phone: ${user.telephone}
Location: ${user.district}, ${user.province}
User Since: ${formatDateTime(user.userCreatedAt)}

Session Statistics

Total Bookings: ${user.totalBookings}
Highest Risk Level: ${user.highestRiskLevel}
Highest Risk Score: ${user.highestRiskScore}/100
First Booking: ${formatDateTime(user.firstBookingTime)}
Last Booking: ${formatDateTime(user.lastBookingTime)}

Recent Sessions

${user.sessions.slice(0, 5).map(session => `
${session.sessionType} ${session.bookingStatus}
Risk: ${session.riskLevel} (${session.riskScore}/100) Date: ${formatDateTime(session.scheduledDatetime)}
`).join('')}

Risk Assessment History

${user.riskAssessments.slice(0, 5).map(risk => `
${risk.riskLevel} ${risk.riskScore}/100
${formatDateTime(risk.timestamp)}
`).join('')}

Conversation History

${user.conversations.map(conv => `
${conv.preview}
${formatDateTime(conv.timestamp)}
`).join('')}
`; userProfileModal.style.display = 'block'; } function viewUserSessions(userAccount) { // Filter sessions to show only this user's sessions const userSessions = sessions.filter(session => session.userAccount === userAccount); displaySessions(userSessions); // Scroll to sessions section document.querySelector('.sessions-section').scrollIntoView({ behavior: 'smooth' }); } function closeModals() { document.querySelectorAll('.modal').forEach(modal => { modal.style.display = 'none'; }); } function openIntakeModal() { // Prefill from selected session when available const selected = sessions.find(s => s.bookingId === currentSessionId); if (selected) { document.getElementById('intakeUsername').value = selected.userAccount || ''; document.getElementById('intakeEmail').value = ''; document.getElementById('intakeFullName').value = selected.userName || ''; document.getElementById('intakePhone').value = ''; document.getElementById('intakeProvince').value = ''; document.getElementById('intakeDistrict').value = ''; } else { intakeForm.reset(); } intakeModal.style.display = 'block'; } async function submitIntakeForm(e) { e.preventDefault(); const payload = { username: document.getElementById('intakeUsername').value.trim(), email: document.getElementById('intakeEmail').value.trim(), full_name: document.getElementById('intakeFullName').value.trim(), phone: document.getElementById('intakePhone').value.trim(), province: document.getElementById('intakeProvince').value.trim(), district: document.getElementById('intakeDistrict').value.trim(), password: document.getElementById('intakePassword').value, confirm_password: document.getElementById('intakeConfirmPassword').value }; try { await api('/professional/users/intake', { method: 'POST', body: JSON.stringify(payload) }); alert('User profile saved'); closeModals(); } catch (err) { console.error('Intake save failed:', err); alert('Failed to save user'); } } function toggleFollowUpDate() { followUpDateGroup.style.display = followUpRequired.checked ? 'block' : 'none'; } async function saveSessionNotes(e) { e.preventDefault(); try { if (!currentSessionId) { alert('Open a session to add notes'); return; } const payload = { notes: document.getElementById('sessionNotes').value, treatmentPlan: document.getElementById('treatmentPlan').value, followUpRequired: followUpRequired.checked, followUpDate: document.getElementById('followUpDate').value || null, professional_id: currentProfessional?.professional_id }; await api(`/professional/sessions/${currentSessionId}/notes`, { method: 'POST', body: JSON.stringify(payload) }); alert('Session notes saved successfully'); closeModals(); } catch (err) { console.error('Error saving notes:', err); alert('Failed to save notes'); } } async function generateReport() { try { const report = await api('/professional/reports/generate', { method: 'POST', body: JSON.stringify({ period: document.getElementById('reportPeriod').value, type: document.getElementById('reportType').value }) }); displayReport(report); } catch (error) { console.error('Error generating report:', error); alert('Failed to generate report'); } } function displayReport(report) { reportContent.innerHTML = `

Report Summary

Total Sessions: ${report.totalSessions}
Unique Users: ${report.uniqueUsers}
High Risk Cases: ${report.highRiskCases}
`; } function logout() { localStorage.removeItem('aimhsa_professional'); window.location.href = '/login'; } // Utility functions function formatDateTime(timestamp) { if (!timestamp) return 'N/A'; const date = new Date(timestamp * 1000); return date.toLocaleString(); } function isToday(date) { const today = new Date(); return date.toDateString() === today.toDateString(); } function isThisWeek(date) { const today = new Date(); const weekAgo = new Date(today.getTime() - 7 * 24 * 60 * 60 * 1000); return date >= weekAgo && date <= today; } function getNotificationIcon(type) { const icons = { 'session': 'fa-calendar-check', 'risk': 'fa-exclamation-triangle', 'user': 'fa-user', 'system': 'fa-cog', 'emergency': 'fa-bell' }; return icons[type] || 'fa-bell'; } // Helper functions function formatLocation(district, province) { if (!district && !province) return 'Not provided'; if (district && province) return `${district}, ${province}`; if (district) return district; if (province) return province; return 'Not provided'; } function getRiskBadgeClass(riskLevel) { const riskClasses = { 'low': 'risk-low', 'medium': 'risk-medium', 'high': 'risk-high', 'critical': 'risk-critical', 'unknown': 'risk-unknown' }; return riskClasses[riskLevel] || 'risk-unknown'; } function formatMissingData(value, fallback = 'Not provided') { return value || fallback; } // Global functions for onclick handlers window.markNotificationRead = markNotificationRead; window.acceptSession = acceptSession; window.declineSession = declineSession; window.viewSessionDetails = viewSessionDetails; window.viewUserProfile = viewUserProfile; window.viewUserSessions = viewUserSessions; // AdminLTE 4 Enhancements document.addEventListener('DOMContentLoaded', function() { // Initialize AdminLTE components if (typeof $ !== 'undefined' && $.fn.DataTable) { // Initialize DataTables if available initializeDataTables(); } // Initialize mobile menu toggle initializeMobileMenu(); // Initialize tooltips initializeTooltips(); // Initialize loading states initializeLoadingStates(); // Initialize animations initializeAnimations(); // Initialize enhanced notifications initializeEnhancedNotifications(); }); function initializeDataTables() { // Enhanced table functionality with AdminLTE styling const tables = document.querySelectorAll('table'); tables.forEach(table => { if (typeof $ !== 'undefined' && $.fn.DataTable) { $(table).DataTable({ responsive: true, pageLength: 10, order: [[0, 'desc']], // Sort by first column descending columnDefs: [ { targets: [-1], orderable: false } // Actions column ], language: { search: "Search:", lengthMenu: "Show _MENU_ entries per page", info: "Showing _START_ to _END_ of _TOTAL_ entries", paginate: { first: "First", last: "Last", next: "Next", previous: "Previous" } } }); } }); } function initializeMobileMenu() { const mobileToggle = document.getElementById('mobileMenuToggle'); const professionalHeader = document.querySelector('.professional-header'); if (mobileToggle && professionalHeader) { mobileToggle.addEventListener('click', function() { professionalHeader.classList.toggle('mobile-open'); }); // Close mobile menu when clicking outside document.addEventListener('click', function(e) { if (!professionalHeader.contains(e.target) && !mobileToggle.contains(e.target)) { professionalHeader.classList.remove('mobile-open'); } }); } } function initializeTooltips() { // Initialize Bootstrap tooltips if available if (typeof $ !== 'undefined' && $.fn.tooltip) { $('[data-toggle="tooltip"]').tooltip(); } } function initializeLoadingStates() { // Add loading states to buttons and forms const forms = document.querySelectorAll('form'); forms.forEach(form => { form.addEventListener('submit', function() { const submitBtn = form.querySelector('button[type="submit"]'); if (submitBtn) { submitBtn.classList.add('loading'); submitBtn.disabled = true; // Remove loading state after 3 seconds (adjust as needed) setTimeout(() => { submitBtn.classList.remove('loading'); submitBtn.disabled = false; }, 3000); } }); }); // Add loading states to refresh buttons const refreshButtons = document.querySelectorAll('[id$="Btn"]'); refreshButtons.forEach(btn => { if (btn.id.includes('refresh') || btn.id.includes('Refresh')) { btn.addEventListener('click', function() { btn.classList.add('loading'); btn.disabled = true; setTimeout(() => { btn.classList.remove('loading'); btn.disabled = false; }, 2000); }); } }); } function initializeAnimations() { // Add fade-in animation to cards const cards = document.querySelectorAll('.stat-card, .action-btn, .user-card, .session-card, .notification-item'); cards.forEach((card, index) => { card.classList.add('fade-in'); card.style.animationDelay = `${index * 0.1}s`; }); // Add bounce-in animation to modals const modals = document.querySelectorAll('.modal'); modals.forEach(modal => { modal.addEventListener('show.bs.modal', function() { const modalContent = modal.querySelector('.modal-content'); if (modalContent) { modalContent.classList.add('bounce-in'); } }); }); } function initializeEnhancedNotifications() { // Enhanced notification system using AdminLTE toast window.showProfessionalMessage = function(text, type = 'info') { if (typeof $ !== 'undefined' && $.fn.toast) { // Use AdminLTE toast if available const toastHtml = ` `; // Create toast container if it doesn't exist let toastContainer = document.querySelector('.toast-container'); if (!toastContainer) { toastContainer = document.createElement('div'); toastContainer.className = 'toast-container position-fixed top-0 end-0 p-3'; toastContainer.style.zIndex = '9999'; document.body.appendChild(toastContainer); } // Add toast to container toastContainer.insertAdjacentHTML('beforeend', toastHtml); // Initialize and show toast const toastElement = toastContainer.lastElementChild; $(toastElement).toast({ autohide: true, delay: 4000 }); $(toastElement).toast('show'); // Remove toast after it's hidden $(toastElement).on('hidden.bs.toast', function() { $(this).remove(); }); } else { // Fallback to alert alert(text); } }; function getToastIcon(type) { const icons = { 'success': 'check-circle', 'error': 'exclamation-triangle', 'warning': 'exclamation-circle', 'info': 'info-circle', 'loading': 'spinner' }; return icons[type] || 'info-circle'; } } // Enhanced refresh functionality function refreshAllData() { const refreshButtons = document.querySelectorAll('[id$="Btn"]'); refreshButtons.forEach(btn => { if (btn.id.includes('refresh') || btn.id.includes('Refresh')) { btn.classList.add('loading'); btn.disabled = true; } }); // Refresh all data Promise.all([ loadNotifications(), loadUpcomingSessions(), loadSessionHistory(), loadBookedUsers(), loadDashboardStats() ]).finally(() => { refreshButtons.forEach(btn => { if (btn.id.includes('refresh') || btn.id.includes('Refresh')) { btn.classList.remove('loading'); btn.disabled = false; } }); if (window.showProfessionalMessage) { window.showProfessionalMessage('All data refreshed successfully', 'success'); } }); } // Add refresh functionality to all refresh buttons document.addEventListener('DOMContentLoaded', function() { const refreshButtons = document.querySelectorAll('[id$="Btn"]'); refreshButtons.forEach(btn => { if (btn.id.includes('refresh') || btn.id.includes('Refresh')) { btn.addEventListener('click', function() { refreshAllData(); }); } }); }); // Enhanced modal functionality function initializeEnhancedModals() { const modals = document.querySelectorAll('.modal'); modals.forEach(modal => { // Add AdminLTE modal functionality if (typeof $ !== 'undefined' && $.fn.modal) { $(modal).on('show.bs.modal', function() { const modalContent = $(this).find('.modal-content'); modalContent.addClass('bounce-in'); }); $(modal).on('hidden.bs.modal', function() { const modalContent = $(this).find('.modal-content'); modalContent.removeClass('bounce-in'); }); } }); } // Initialize enhanced modals document.addEventListener('DOMContentLoaded', function() { initializeEnhancedModals(); }); })();