// static/admin/js/vendors.js // ✅ Use centralized logger - ONE LINE! const vendorsLog = window.LogConfig.loggers.vendors; // ============================================ // VENDOR LIST FUNCTION // ============================================ function adminVendors() { return { // Inherit base layout functionality from init-alpine.js ...data(), // ✅ CRITICAL: Page identifier for sidebar active state currentPage: 'vendors', // Vendors page specific state vendors: [], stats: { total: 0, verified: 0, pending: 0, inactive: 0 }, loading: false, error: null, // Search and filters filters: { search: '', is_active: '', is_verified: '' }, // Pagination state (server-side) pagination: { page: 1, per_page: 10, total: 0, pages: 0 }, // Initialize async init() { vendorsLog.info('=== VENDORS PAGE INITIALIZING ==='); // Prevent multiple initializations if (window._vendorsInitialized) { vendorsLog.warn('Vendors page already initialized, skipping...'); return; } window._vendorsInitialized = true; vendorsLog.group('Loading vendors data'); await this.loadVendors(); await this.loadStats(); vendorsLog.groupEnd(); vendorsLog.info('=== VENDORS PAGE INITIALIZATION COMPLETE ==='); }, // Debounced search debouncedSearch() { if (this._searchTimeout) { clearTimeout(this._searchTimeout); } this._searchTimeout = setTimeout(() => { vendorsLog.info('Search triggered:', this.filters.search); this.pagination.page = 1; this.loadVendors(); }, 300); }, // Computed: Get vendors for current page (already paginated from server) get paginatedVendors() { return this.vendors; }, // Computed: Total number of pages get totalPages() { return this.pagination.pages; }, // Computed: Start index for pagination display get startIndex() { if (this.pagination.total === 0) return 0; return (this.pagination.page - 1) * this.pagination.per_page + 1; }, // Computed: End index for pagination display get endIndex() { const end = this.pagination.page * this.pagination.per_page; return end > this.pagination.total ? this.pagination.total : end; }, // Computed: Generate page numbers array with ellipsis get pageNumbers() { const pages = []; const totalPages = this.totalPages; const current = this.pagination.page; if (totalPages <= 7) { // Show all pages if 7 or fewer for (let i = 1; i <= totalPages; i++) { pages.push(i); } } else { // Always show first page pages.push(1); if (current > 3) { pages.push('...'); } // Show pages around current page const start = Math.max(2, current - 1); const end = Math.min(totalPages - 1, current + 1); for (let i = start; i <= end; i++) { pages.push(i); } if (current < totalPages - 2) { pages.push('...'); } // Always show last page pages.push(totalPages); } return pages; }, // Load vendors list with search and pagination async loadVendors() { vendorsLog.info('Loading vendors list...'); this.loading = true; this.error = null; try { // Build query parameters const params = new URLSearchParams(); params.append('skip', (this.pagination.page - 1) * this.pagination.per_page); params.append('limit', this.pagination.per_page); if (this.filters.search) { params.append('search', this.filters.search); } if (this.filters.is_active !== '') { params.append('is_active', this.filters.is_active); } if (this.filters.is_verified !== '') { params.append('is_verified', this.filters.is_verified); } const url = `/admin/vendors?${params}`; window.LogConfig.logApiCall('GET', url, null, 'request'); const startTime = performance.now(); const response = await apiClient.get(url); const duration = performance.now() - startTime; window.LogConfig.logApiCall('GET', url, response, 'response'); window.LogConfig.logPerformance('Load Vendors', duration); // Handle response with pagination info if (response.vendors) { this.vendors = response.vendors; this.pagination.total = response.total; this.pagination.pages = Math.ceil(response.total / this.pagination.per_page); vendorsLog.info(`Loaded ${this.vendors.length} vendors (total: ${response.total})`); } else { // Fallback for different response structures this.vendors = response.items || response || []; this.pagination.total = this.vendors.length; this.pagination.pages = Math.ceil(this.vendors.length / this.pagination.per_page); vendorsLog.info(`Vendors loaded in ${duration}ms`, { count: this.vendors.length, hasVendors: this.vendors.length > 0 }); } if (this.vendors.length > 0) { vendorsLog.debug('First vendor:', this.vendors[0]); } } catch (error) { window.LogConfig.logError(error, 'Load Vendors'); this.error = error.message || 'Failed to load vendors'; Utils.showToast('Failed to load vendors', 'error'); } finally { this.loading = false; } }, // Load statistics async loadStats() { vendorsLog.info('Loading vendor statistics...'); try { const url = '/admin/vendors/stats'; window.LogConfig.logApiCall('GET', url, null, 'request'); const startTime = performance.now(); const response = await apiClient.get(url); const duration = performance.now() - startTime; window.LogConfig.logApiCall('GET', url, response, 'response'); window.LogConfig.logPerformance('Load Vendor Stats', duration); this.stats = response; vendorsLog.info(`Stats loaded in ${duration}ms`, this.stats); } catch (error) { window.LogConfig.logError(error, 'Load Vendor Stats'); // Don't show error toast for stats, just log it } }, // Pagination: Go to specific page goToPage(pageNum) { if (pageNum === '...' || pageNum < 1 || pageNum > this.totalPages) { return; } vendorsLog.info('Going to page:', pageNum); this.pagination.page = pageNum; this.loadVendors(); }, // Pagination: Go to next page nextPage() { if (this.pagination.page < this.totalPages) { vendorsLog.info('Going to next page'); this.pagination.page++; this.loadVendors(); } }, // Pagination: Go to previous page previousPage() { if (this.pagination.page > 1) { vendorsLog.info('Going to previous page'); this.pagination.page--; this.loadVendors(); } }, // Format date (matches dashboard pattern) formatDate(dateString) { if (!dateString) { vendorsLog.debug('formatDate called with empty dateString'); return '-'; } const formatted = Utils.formatDate(dateString); vendorsLog.debug(`Date formatted: ${dateString} -> ${formatted}`); return formatted; }, // View vendor details viewVendor(vendorCode) { vendorsLog.info('Navigating to vendor details:', vendorCode); const url = `/admin/vendors/${vendorCode}`; vendorsLog.debug('Navigation URL:', url); window.location.href = url; }, // Edit vendor editVendor(vendorCode) { vendorsLog.info('Navigating to vendor edit:', vendorCode); const url = `/admin/vendors/${vendorCode}/edit`; vendorsLog.debug('Navigation URL:', url); window.location.href = url; }, // Delete vendor async deleteVendor(vendor) { vendorsLog.info('Delete vendor requested:', vendor.vendor_code); if (!confirm(`Are you sure you want to delete vendor "${vendor.name}"?\n\nThis action cannot be undone.`)) { vendorsLog.info('Delete cancelled by user'); return; } try { const url = `/admin/vendors/${vendor.vendor_code}`; window.LogConfig.logApiCall('DELETE', url, null, 'request'); vendorsLog.info('Deleting vendor:', vendor.vendor_code); await apiClient.delete(url); window.LogConfig.logApiCall('DELETE', url, null, 'response'); Utils.showToast('Vendor deleted successfully', 'success'); vendorsLog.info('Vendor deleted successfully'); // Reload data await this.loadVendors(); await this.loadStats(); } catch (error) { window.LogConfig.logError(error, 'Delete Vendor'); Utils.showToast(error.message || 'Failed to delete vendor', 'error'); } }, // Refresh vendors list async refresh() { vendorsLog.info('=== VENDORS REFRESH TRIGGERED ==='); vendorsLog.group('Refreshing vendors data'); await this.loadVendors(); await this.loadStats(); vendorsLog.groupEnd(); Utils.showToast('Vendors list refreshed', 'success'); vendorsLog.info('=== VENDORS REFRESH COMPLETE ==='); } }; } vendorsLog.info('Vendors module loaded');