/** * Care Book Ultimate - Admin Interface JavaScript * * Modern admin interface with exceptional UX * - Real-time interactions * - <30 second learning curve * - Accessibility support * - Performance optimized * * @package CareBook\Ultimate * @since 1.0.0 */ (function($, wp, careBookUltimate) { 'use strict'; if (typeof careBookUltimate === 'undefined') { console.error('Care Book Ultimate: Configuration not loaded'); return; } /** * Admin Interface Controller * Manages all admin interface functionality */ const AdminInterface = { // State management state: { currentTab: 'doctors', loading: false, selectedItems: new Set(), searchTimeout: null, autoRefreshInterval: null, cache: new Map(), pagination: { doctors: { page: 1, total: 0, perPage: 20 }, services: { page: 1, total: 0, perPage: 20 } }, sortOrder: { doctors: { column: 'name', direction: 'asc' }, services: { column: 'name', direction: 'asc' } } }, // Configuration config: careBookUltimate.config || {}, strings: careBookUltimate.strings || {}, /** * Initialize the admin interface */ init() { this.bindEvents(); this.initTabs(); this.initTheme(); this.initHelp(); this.initTooltips(); this.loadInitialData(); if (this.config.autoRefresh) { this.startAutoRefresh(); } // Keyboard shortcuts this.initKeyboardShortcuts(); console.log('Care Book Ultimate Admin Interface initialized'); }, /** * Bind all event handlers */ bindEvents() { // Tab navigation $('.cbu-nav-tab').on('click', this.handleTabClick.bind(this)); // Search functionality $('#cbu-doctors-search, #cbu-services-search').on('input', this.handleSearch.bind(this)); $('.cbu-search-clear').on('click', this.clearSearch.bind(this)); // Filter controls $('#cbu-doctors-filter, #cbu-services-status-filter, #cbu-services-doctor-filter').on('change', this.handleFilter.bind(this)); // Refresh buttons $('#cbu-refresh-doctors, #cbu-refresh-services').on('click', this.handleRefresh.bind(this)); // Selection handlers $(document).on('change', '.cbu-select-all', this.handleSelectAll.bind(this)); $(document).on('change', '.cbu-doctor-checkbox, .cbu-service-checkbox', this.handleItemSelection.bind(this)); // Toggle buttons $(document).on('click', '.cbu-toggle-button', this.handleToggle.bind(this)); // Bulk actions $('#cbu-bulk-block-doctors, #cbu-bulk-block-services').on('click', this.handleBulkBlock.bind(this)); $('#cbu-bulk-unblock-doctors, #cbu-bulk-unblock-services').on('click', this.handleBulkUnblock.bind(this)); // Pagination $(document).on('click', '.cbu-pagination-btn', this.handlePagination.bind(this)); // Table sorting $(document).on('click', '.cbu-table th[data-sort]', this.handleSort.bind(this)); // Modal and overlay handlers $(document).on('click', '.cbu-modal-close, .cbu-modal-backdrop', this.closeModal.bind(this)); $(document).on('click', '.cbu-toast-close', this.closeToast.bind(this)); // Help toggle $('.cbu-help-toggle').on('click', this.toggleHelp.bind(this)); // Theme toggle $('#cbu-dark-mode').on('change', this.handleThemeToggle.bind(this)); // Window events $(window).on('beforeunload', this.handleBeforeUnload.bind(this)); $(window).on('resize', this.debounce(this.handleResize.bind(this), 250)); }, /** * Initialize tab functionality */ initTabs() { const urlHash = window.location.hash.slice(1); if (urlHash && $('.cbu-nav-tab[data-tab="' + urlHash + '"]').length) { this.switchTab(urlHash); } else { this.switchTab(this.state.currentTab); } }, /** * Initialize theme functionality */ initTheme() { const savedTheme = localStorage.getItem('cbu_dark_mode'); const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; if (savedTheme === 'true' || (savedTheme === null && prefersDark)) { this.enableDarkMode(); $('#cbu-dark-mode').prop('checked', true); } // Listen for system theme changes window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => { if (localStorage.getItem('cbu_dark_mode') === null) { if (e.matches) { this.enableDarkMode(); } else { this.disableDarkMode(); } } }); }, /** * Initialize help system */ initHelp() { // Close help panel when clicking outside $(document).on('click', (e) => { const helpPanel = $('.cbu-help-panel'); const helpToggle = $('.cbu-help-toggle'); if (!helpPanel.is(e.target) && !helpPanel.has(e.target).length && !helpToggle.is(e.target) && !helpToggle.has(e.target).length) { this.hideHelp(); } }); }, /** * Initialize tooltips for better UX */ initTooltips() { // Add tooltips to buttons and controls $('[data-tooltip]').each(function() { const $this = $(this); const title = $this.data('tooltip'); $this.attr('title', title).removeAttr('data-tooltip'); }); }, /** * Initialize keyboard shortcuts */ initKeyboardShortcuts() { $(document).on('keydown', (e) => { // Don't trigger shortcuts when typing in inputs if ($(e.target).is('input, textarea, select')) { return; } switch (e.key) { case '/': e.preventDefault(); this.focusSearch(); break; case 'Escape': this.closeModal(); this.hideHelp(); break; case '?': if (e.shiftKey) { e.preventDefault(); this.toggleHelp(); } break; } // Tab shortcuts (1-4) if (e.key >= '1' && e.key <= '4' && (e.ctrlKey || e.metaKey)) { e.preventDefault(); const tabs = ['doctors', 'services', 'bulk', 'settings']; const tabIndex = parseInt(e.key) - 1; if (tabs[tabIndex]) { this.switchTab(tabs[tabIndex]); } } // Ctrl+A for select all if (e.key === 'a' && (e.ctrlKey || e.metaKey)) { e.preventDefault(); this.selectAllVisible(); } }); }, /** * Load initial data */ loadInitialData() { this.loadDoctors(); this.loadSystemStatus(); }, /** * Start auto-refresh if enabled */ startAutoRefresh() { if (this.state.autoRefreshInterval) { clearInterval(this.state.autoRefreshInterval); } this.state.autoRefreshInterval = setInterval(() => { if (!this.state.loading && document.visibilityState === 'visible') { this.refreshCurrentTab(); } }, this.config.refreshInterval || 30000); }, /** * Stop auto-refresh */ stopAutoRefresh() { if (this.state.autoRefreshInterval) { clearInterval(this.state.autoRefreshInterval); this.state.autoRefreshInterval = null; } }, /** * Handle tab clicks */ handleTabClick(e) { e.preventDefault(); const tab = $(e.currentTarget).data('tab'); this.switchTab(tab); }, /** * Switch to a specific tab */ switchTab(tab) { // Update navigation $('.cbu-nav-tab').removeClass('cbu-nav-tab-active').attr('aria-selected', 'false'); $('.cbu-nav-tab[data-tab="' + tab + '"]').addClass('cbu-nav-tab-active').attr('aria-selected', 'true'); // Update panels $('.cbu-tab-panel').removeClass('cbu-tab-panel-active').attr('aria-hidden', 'true'); $('#cbu-' + tab + '-panel').addClass('cbu-tab-panel-active').attr('aria-hidden', 'false'); // Update state this.state.currentTab = tab; // Update URL without page reload if (history.pushState) { history.pushState(null, null, '#' + tab); } // Load tab data if needed switch (tab) { case 'doctors': this.loadDoctors(); break; case 'services': this.loadServices(); break; case 'bulk': this.updateBulkStats(); break; case 'settings': this.loadSettings(); break; } // Focus management for accessibility $('#cbu-tab-' + tab).focus(); }, /** * Handle search input */ handleSearch(e) { const searchTerm = $(e.target).val(); const searchType = e.target.id.includes('doctors') ? 'doctors' : 'services'; // Clear existing timeout if (this.state.searchTimeout) { clearTimeout(this.state.searchTimeout); } // Debounce search this.state.searchTimeout = setTimeout(() => { this.performSearch(searchType, searchTerm); }, this.config.searchDelay || 300); // Show/hide clear button const clearBtn = $(e.target).siblings('.cbu-search-clear'); if (searchTerm) { clearBtn.show(); } else { clearBtn.hide(); } }, /** * Clear search */ clearSearch(e) { const searchInput = $(e.target).siblings('.cbu-search-input'); searchInput.val('').trigger('input').focus(); $(e.target).hide(); }, /** * Perform search */ performSearch(type, term) { if (type === 'doctors') { this.loadDoctors({ search: term, page: 1 }); } else { this.loadServices({ search: term, page: 1 }); } }, /** * Handle filter changes */ handleFilter(e) { const $filter = $(e.target); const filterType = $filter.attr('id'); if (filterType.includes('doctors')) { this.loadDoctors({ page: 1 }); } else { this.loadServices({ page: 1 }); } }, /** * Handle refresh buttons */ handleRefresh(e) { e.preventDefault(); const type = e.target.id.includes('doctors') ? 'doctors' : 'services'; // Clear cache this.clearCache(type); if (type === 'doctors') { this.loadDoctors({ page: 1 }); } else { this.loadServices({ page: 1 }); } this.showToast('success', this.strings.success, 'Data refreshed successfully'); }, /** * Handle select all checkbox */ handleSelectAll(e) { const isChecked = $(e.target).is(':checked'); const type = e.target.id.includes('doctors') ? 'doctor' : 'service'; $('.cbu-' + type + '-checkbox').prop('checked', isChecked).trigger('change'); }, /** * Handle individual item selection */ handleItemSelection(e) { const $checkbox = $(e.target); const itemId = $checkbox.val(); const isChecked = $checkbox.is(':checked'); const type = $checkbox.hasClass('cbu-doctor-checkbox') ? 'doctors' : 'services'; if (isChecked) { this.state.selectedItems.add(type + ':' + itemId); } else { this.state.selectedItems.delete(type + ':' + itemId); } this.updateBulkActionButtons(); this.updateSelectAllState(type); this.updateBulkStats(); }, /** * Update bulk action button states */ updateBulkActionButtons() { const hasSelection = this.state.selectedItems.size > 0; $('.cbu-button-bulk-block, .cbu-button-bulk-unblock').prop('disabled', !hasSelection); }, /** * Update select all checkbox state */ updateSelectAllState(type) { const checkboxes = $('.cbu-' + type.slice(0, -1) + '-checkbox'); const checkedCheckboxes = checkboxes.filter(':checked'); const selectAll = $('#cbu-select-all-' + type); if (checkedCheckboxes.length === 0) { selectAll.prop('indeterminate', false).prop('checked', false); } else if (checkedCheckboxes.length === checkboxes.length) { selectAll.prop('indeterminate', false).prop('checked', true); } else { selectAll.prop('indeterminate', true).prop('checked', false); } }, /** * Handle toggle buttons */ handleToggle(e) { e.preventDefault(); const $button = $(e.currentTarget); const doctorId = $button.data('doctor-id'); const serviceId = $button.data('service-id'); const currentlyBlocked = $button.data('blocked'); // Optimistic UI update this.updateToggleButton($button, !currentlyBlocked); const data = { action: 'care_book_toggle_restriction', nonce: careBookUltimate.nonce, restriction_type: doctorId ? 'doctor' : 'service', target_id: doctorId || serviceId, doctor_id: doctorId || $button.data('doctor-id'), is_blocked: !currentlyBlocked }; this.makeAjaxRequest(data) .done((response) => { if (response.success) { this.showToast('success', this.strings.success, response.data.message); this.updateRowState($button.closest('tr'), !currentlyBlocked); this.loadSystemStatus(); // Update dashboard } else { // Revert optimistic update this.updateToggleButton($button, currentlyBlocked); this.showToast('error', this.strings.error, response.data.message); } }) .fail(() => { // Revert optimistic update this.updateToggleButton($button, currentlyBlocked); this.showToast('error', this.strings.error, 'Request failed. Please try again.'); }); }, /** * Update toggle button state */ updateToggleButton($button, isBlocked) { $button.data('blocked', isBlocked); if (isBlocked) { $button.removeClass('cbu-toggle-block').addClass('cbu-toggle-unblock'); $button.find('.dashicons').removeClass('dashicons-hidden').addClass('dashicons-visibility'); $button.find('.cbu-toggle-text').text('Unblock'); } else { $button.removeClass('cbu-toggle-unblock').addClass('cbu-toggle-block'); $button.find('.dashicons').removeClass('dashicons-visibility').addClass('dashicons-hidden'); $button.find('.cbu-toggle-text').text('Block'); } }, /** * Update row visual state */ updateRowState($row, isBlocked) { const $statusBadge = $row.find('.cbu-status-badge'); if (isBlocked) { $row.addClass('cbu-row-blocked'); $statusBadge.removeClass('cbu-status-available').addClass('cbu-status-blocked').text('Blocked'); } else { $row.removeClass('cbu-row-blocked'); $statusBadge.removeClass('cbu-status-blocked').addClass('cbu-status-available').text('Available'); } }, /** * Handle bulk block action */ handleBulkBlock(e) { e.preventDefault(); this.performBulkAction('block'); }, /** * Handle bulk unblock action */ handleBulkUnblock(e) { e.preventDefault(); this.performBulkAction('unblock'); }, /** * Perform bulk action */ performBulkAction(action) { if (this.state.selectedItems.size === 0) { this.showToast('warning', 'Warning', this.strings.selectItems); return; } const confirmMessage = action === 'block' ? `Block ${this.state.selectedItems.size} selected items?` : `Unblock ${this.state.selectedItems.size} selected items?`; if (!confirm(confirmMessage)) { return; } const restrictions = Array.from(this.state.selectedItems).map(item => { const [type, id] = item.split(':'); return { restriction_type: type.slice(0, -1), // Remove 's' from 'doctors'/'services' target_id: id, is_blocked: action === 'block', doctor_id: type === 'services' ? this.getDoctorIdForService(id) : id }; }); const data = { action: 'care_book_bulk_update', nonce: careBookUltimate.nonce, restrictions: restrictions }; this.showLoadingOverlay(); this.makeAjaxRequest(data) .done((response) => { this.hideLoadingOverlay(); if (response.success) { this.showToast('success', this.strings.success, response.data.message); this.refreshCurrentTab(); this.clearSelection(); } else { this.showToast('error', this.strings.error, response.data.message); } }) .fail(() => { this.hideLoadingOverlay(); this.showToast('error', this.strings.error, 'Bulk action failed. Please try again.'); }); }, /** * Handle pagination */ handlePagination(e) { e.preventDefault(); const $button = $(e.currentTarget); const page = parseInt($button.data('page')); const type = this.state.currentTab; if (page && !$button.is('[disabled]')) { this.state.pagination[type].page = page; if (type === 'doctors') { this.loadDoctors({ page: page }); } else if (type === 'services') { this.loadServices({ page: page }); } } }, /** * Handle table sorting */ handleSort(e) { const $th = $(e.currentTarget); const column = $th.data('sort'); const type = this.state.currentTab; let direction = 'asc'; if (this.state.sortOrder[type].column === column && this.state.sortOrder[type].direction === 'asc') { direction = 'desc'; } this.state.sortOrder[type] = { column, direction }; // Update visual indicators $th.siblings().removeAttr('data-sort-direction'); $th.attr('data-sort-direction', direction); // Reload data with new sorting if (type === 'doctors') { this.loadDoctors({ page: 1 }); } else if (type === 'services') { this.loadServices({ page: 1 }); } }, /** * Load doctors data */ loadDoctors(options = {}) { const params = { action: 'care_book_get_restrictions', nonce: careBookUltimate.nonce, restriction_type: 'doctor', page: options.page || this.state.pagination.doctors.page, per_page: this.state.pagination.doctors.perPage, search: options.search || $('#cbu-doctors-search').val(), filter: $('#cbu-doctors-filter').val(), sort_by: this.state.sortOrder.doctors.column, sort_order: this.state.sortOrder.doctors.direction }; // Check cache first const cacheKey = JSON.stringify(params); if (this.state.cache.has(cacheKey)) { this.renderDoctors(this.state.cache.get(cacheKey)); return; } this.showLoading('doctors'); this.makeAjaxRequest(params) .done((response) => { if (response.success) { // Cache the response this.state.cache.set(cacheKey, response.data); this.renderDoctors(response.data); this.updatePagination('doctors', response.data); this.updateTabBadge('doctors', response.data.total || 0); } else { this.showError('doctors', response.data.message); } }) .fail(() => { this.showError('doctors', 'Failed to load doctors data'); }) .always(() => { this.hideLoading('doctors'); }); }, /** * Load services data */ loadServices(options = {}) { const params = { action: 'care_book_get_restrictions', nonce: careBookUltimate.nonce, restriction_type: 'service', page: options.page || this.state.pagination.services.page, per_page: this.state.pagination.services.perPage, search: options.search || $('#cbu-services-search').val(), doctor_id: $('#cbu-services-doctor-filter').val(), filter: $('#cbu-services-status-filter').val(), sort_by: this.state.sortOrder.services.column, sort_order: this.state.sortOrder.services.direction }; const cacheKey = JSON.stringify(params); if (this.state.cache.has(cacheKey)) { this.renderServices(this.state.cache.get(cacheKey)); return; } this.showLoading('services'); this.makeAjaxRequest(params) .done((response) => { if (response.success) { this.state.cache.set(cacheKey, response.data); this.renderServices(response.data); this.updatePagination('services', response.data); this.updateTabBadge('services', response.data.total || 0); } else { this.showError('services', response.data.message); } }) .fail(() => { this.showError('services', 'Failed to load services data'); }) .always(() => { this.hideLoading('services'); }); }, /** * Load system status */ loadSystemStatus() { this.makeAjaxRequest({ action: 'care_book_system_status', nonce: careBookUltimate.nonce }).done((response) => { if (response.success) { this.updateDashboard(response.data); } }); }, /** * Render doctors table */ renderDoctors(data) { const $tbody = $('#cbu-doctors-list'); const template = $('#cbu-doctor-row-template').html(); if (!data.restrictions || data.restrictions.length === 0) { $tbody.html(`

No doctors found

No doctors match your current search and filter criteria.

`); return; } let html = ''; data.restrictions.forEach(doctor => { html += this.compileMustache(template, { id: doctor.id, name: doctor.name, email: doctor.email || '', speciality: doctor.speciality || 'General', is_blocked: doctor.is_blocked }); }); $tbody.html(html); }, /** * Render services table */ renderServices(data) { const $tbody = $('#cbu-services-list'); const template = $('#cbu-service-row-template').html(); if (!data.restrictions || data.restrictions.length === 0) { $tbody.html(`

No services found

No services match your current search and filter criteria.

`); return; } let html = ''; data.restrictions.forEach(service => { html += this.compileMustache(template, { id: service.id, name: service.name, doctor_id: service.doctor_id, doctor_name: service.doctor_name || 'Unknown', duration: service.duration || '30 min', price: service.price || '$0', is_blocked: service.is_blocked }); }); $tbody.html(html); }, /** * Update pagination */ updatePagination(type, data) { const $pagination = $('#cbu-' + type + '-pagination'); if (!data.total_pages || data.total_pages <= 1) { $pagination.hide(); return; } const template = $('#cbu-pagination-template').html(); const currentPage = data.page || 1; const totalPages = data.total_pages; const paginationData = { start: ((currentPage - 1) * data.per_page) + 1, end: Math.min(currentPage * data.per_page, data.total), total: data.total, canGoPrev: currentPage > 1, canGoNext: currentPage < totalPages, prevPage: currentPage - 1, nextPage: currentPage + 1, totalPages: totalPages, pages: this.generatePageNumbers(currentPage, totalPages) }; $pagination.html(this.compileMustache(template, paginationData)).show(); }, /** * Generate page numbers for pagination */ generatePageNumbers(current, total) { const pages = []; const maxVisible = 5; let start = Math.max(1, current - Math.floor(maxVisible / 2)); let end = Math.min(total, start + maxVisible - 1); if (end - start < maxVisible - 1) { start = Math.max(1, end - maxVisible + 1); } for (let i = start; i <= end; i++) { pages.push({ page: i, current: i === current }); } return pages; }, /** * Update tab badge */ updateTabBadge(tab, count) { $('#cbu-' + tab + '-count').text(count); }, /** * Update dashboard */ updateDashboard(data) { $('#cbu-blocked-doctors').text(data.blocked_doctors || 0); $('#cbu-blocked-services').text(data.blocked_services || 0); $('#cbu-cache-status').text(data.cache_status || 'Unknown'); $('#cbu-performance-score').text((data.performance_score || 100) + '%'); }, /** * Show loading state */ showLoading(type) { if (type) { $('#cbu-' + type + '-list').html(`

${this.strings.loading}

`); } else { this.showLoadingOverlay(); } }, /** * Hide loading state */ hideLoading(type) { if (!type) { this.hideLoadingOverlay(); } }, /** * Show error state */ showError(type, message) { $('#cbu-' + type + '-list').html(`

Error Loading Data

${message}

`); }, /** * Show loading overlay */ showLoadingOverlay() { $('.cbu-loading-overlay').attr('aria-hidden', 'false'); this.state.loading = true; }, /** * Hide loading overlay */ hideLoadingOverlay() { $('.cbu-loading-overlay').attr('aria-hidden', 'true'); this.state.loading = false; }, /** * Show toast notification */ showToast(type, title, message) { const $container = $('.cbu-toast-container'); const toastId = 'toast-' + Date.now(); const toast = $(`
${title}
${message}
`); $container.append(toast); // Trigger show animation setTimeout(() => toast.addClass('cbu-toast-show'), 10); // Auto-hide after duration setTimeout(() => { this.closeToast({ target: toast.find('.cbu-toast-close')[0] }); }, this.config.toastDuration || 4000); }, /** * Get toast icon based on type */ getToastIcon(type) { const icons = { success: 'dashicons-yes-alt', error: 'dashicons-dismiss', warning: 'dashicons-warning', info: 'dashicons-info' }; return icons[type] || icons.info; }, /** * Close toast notification */ closeToast(e) { const $toast = $(e.target).closest('.cbu-toast'); $toast.removeClass('cbu-toast-show'); setTimeout(() => $toast.remove(), 300); }, /** * Show modal */ showModal(title, content, footer = '') { $('.cbu-modal-title').text(title); $('.cbu-modal-content').html(content); $('.cbu-modal-footer').html(footer); $('.cbu-modal-backdrop').attr('aria-hidden', 'false'); // Focus management setTimeout(() => { $('.cbu-modal').find('input, button, select, textarea').first().focus(); }, 100); }, /** * Close modal */ closeModal(e) { if (!e || $(e.target).hasClass('cbu-modal-backdrop') || $(e.target).hasClass('cbu-modal-close')) { $('.cbu-modal-backdrop').attr('aria-hidden', 'true'); } }, /** * Toggle help panel */ toggleHelp() { const $panel = $('.cbu-help-panel'); const isVisible = $panel.attr('aria-hidden') === 'false'; if (isVisible) { this.hideHelp(); } else { this.showHelp(); } }, /** * Show help panel */ showHelp() { $('.cbu-help-panel').attr('aria-hidden', 'false'); $('.cbu-help-toggle').attr('aria-expanded', 'true'); }, /** * Hide help panel */ hideHelp() { $('.cbu-help-panel').attr('aria-hidden', 'true'); $('.cbu-help-toggle').attr('aria-expanded', 'false'); }, /** * Handle theme toggle */ handleThemeToggle(e) { const isDark = $(e.target).is(':checked'); if (isDark) { this.enableDarkMode(); } else { this.disableDarkMode(); } localStorage.setItem('cbu_dark_mode', isDark.toString()); }, /** * Enable dark mode */ enableDarkMode() { $('body').attr('data-cbu-theme', 'dark'); }, /** * Disable dark mode */ disableDarkMode() { $('body').removeAttr('data-cbu-theme'); }, /** * Focus search input */ focusSearch() { const currentTab = this.state.currentTab; $('#cbu-' + currentTab + '-search').focus(); }, /** * Select all visible items */ selectAllVisible() { const currentTab = this.state.currentTab; $('#cbu-select-all-' + currentTab).prop('checked', true).trigger('change'); }, /** * Clear selection */ clearSelection() { this.state.selectedItems.clear(); $('.cbu-doctor-checkbox, .cbu-service-checkbox').prop('checked', false); $('.cbu-select-all').prop('checked', false).prop('indeterminate', false); this.updateBulkActionButtons(); }, /** * Refresh current tab */ refreshCurrentTab() { switch (this.state.currentTab) { case 'doctors': this.loadDoctors({ page: 1 }); break; case 'services': this.loadServices({ page: 1 }); break; default: this.loadSystemStatus(); } }, /** * Update bulk stats */ updateBulkStats() { const doctorCount = Array.from(this.state.selectedItems).filter(item => item.startsWith('doctors:')).length; const serviceCount = Array.from(this.state.selectedItems).filter(item => item.startsWith('services:')).length; $('#cbu-selected-doctors-count').text(doctorCount); $('#cbu-selected-services-count').text(serviceCount); $('#cbu-total-selected-count').text(this.state.selectedItems.size); }, /** * Clear cache */ clearCache(type = null) { if (type) { // Clear specific cache entries const keysToDelete = []; this.state.cache.forEach((value, key) => { if (key.includes(type)) { keysToDelete.push(key); } }); keysToDelete.forEach(key => this.state.cache.delete(key)); } else { // Clear all cache this.state.cache.clear(); } }, /** * Handle window resize */ handleResize() { // Adjust table responsiveness this.adjustTableResponsiveness(); }, /** * Adjust table responsiveness */ adjustTableResponsiveness() { const $tables = $('.cbu-table-container'); const isMobile = window.innerWidth < 768; $tables.each(function() { const $container = $(this); const $table = $container.find('.cbu-table'); if (isMobile) { $container.addClass('cbu-mobile-scroll'); } else { $container.removeClass('cbu-mobile-scroll'); } }); }, /** * Handle before unload */ handleBeforeUnload() { // Save any pending state this.stopAutoRefresh(); }, /** * Load settings */ loadSettings() { // Settings loading will be handled by settings-specific code }, /** * Get doctor ID for service (helper method) */ getDoctorIdForService(serviceId) { // This would typically come from the service data // For now, return null and let backend handle it return null; }, /** * Make AJAX request with error handling */ makeAjaxRequest(data) { return $.ajax({ url: careBookUltimate.ajaxUrl, type: 'POST', data: data, timeout: 30000 }); }, /** * Simple mustache-like template compilation */ compileMustache(template, data) { return template.replace(/\{\{#if\s+(\w+)\}\}(.*?)\{\{\/if\}\}/gs, (match, key, content) => { return data[key] ? content : ''; }).replace(/\{\{#unless\s+(\w+)\}\}(.*?)\{\{\/unless\}\}/gs, (match, key, content) => { return !data[key] ? content : ''; }).replace(/\{\{(\w+)\}\}/g, (match, key) => { return data[key] || ''; }); }, /** * Debounce function */ debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } }; // Initialize when DOM is ready $(document).ready(() => { AdminInterface.init(); }); // Expose to global scope for external access window.AdminInterface = AdminInterface; })(jQuery, wp, careBookUltimate);