// noqa: js-006 - async init pattern is safe, loadData has try/catch // static/admin/js/merchant-detail.js // Create custom logger for merchant detail const merchantDetailLog = window.LogConfig.createLogger('MERCHANT-DETAIL'); function adminMerchantDetail() { return { // Inherit base layout functionality from init-alpine.js ...data(), // Merchant detail page specific state currentPage: 'merchant-detail', merchant: null, loading: false, error: null, merchantId: null, // Initialize async init() { // Load i18n translations await I18n.loadModule('tenancy'); merchantDetailLog.info('=== MERCHANT DETAIL PAGE INITIALIZING ==='); // Prevent multiple initializations if (window._merchantDetailInitialized) { merchantDetailLog.warn('Merchant detail page already initialized, skipping...'); return; } window._merchantDetailInitialized = true; // Get merchant ID from URL const path = window.location.pathname; const match = path.match(/\/admin\/merchants\/(\d+)$/); if (match) { this.merchantId = match[1]; merchantDetailLog.info('Viewing merchant:', this.merchantId); await this.loadMerchant(); } else { merchantDetailLog.error('No merchant ID in URL'); this.error = 'Invalid merchant URL'; Utils.showToast(I18n.t('tenancy.messages.invalid_merchant_url'), 'error'); } merchantDetailLog.info('=== MERCHANT DETAIL PAGE INITIALIZATION COMPLETE ==='); }, // Load merchant data async loadMerchant() { merchantDetailLog.info('Loading merchant details...'); this.loading = true; this.error = null; try { const url = `/admin/merchants/${this.merchantId}`; 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 Merchant Details', duration); this.merchant = response; merchantDetailLog.info(`Merchant loaded in ${duration}ms`, { id: this.merchant.id, name: this.merchant.name, is_verified: this.merchant.is_verified, is_active: this.merchant.is_active, store_count: this.merchant.store_count }); merchantDetailLog.debug('Full merchant data:', this.merchant); } catch (error) { window.LogConfig.logError(error, 'Load Merchant Details'); this.error = error.message || 'Failed to load merchant details'; Utils.showToast(I18n.t('tenancy.messages.failed_to_load_merchant_details'), 'error'); } finally { this.loading = false; } }, // Format date (matches dashboard pattern) formatDate(dateString) { if (!dateString) { merchantDetailLog.debug('formatDate called with empty dateString'); return '-'; } const formatted = Utils.formatDate(dateString); merchantDetailLog.debug(`Date formatted: ${dateString} -> ${formatted}`); return formatted; }, // Delete merchant async deleteMerchant() { merchantDetailLog.info('Delete merchant requested:', this.merchantId); if (this.merchant?.store_count > 0) { Utils.showToast(`Cannot delete merchant with ${this.merchant.store_count} store(s). Delete stores first.`, 'error'); return; } if (!confirm(`Are you sure you want to delete merchant "${this.merchant.name}"?\n\nThis action cannot be undone.`)) { merchantDetailLog.info('Delete cancelled by user'); return; } // Second confirmation for safety if (!confirm(`FINAL CONFIRMATION\n\nAre you absolutely sure you want to delete "${this.merchant.name}"?`)) { merchantDetailLog.info('Delete cancelled by user (second confirmation)'); return; } try { const url = `/admin/merchants/${this.merchantId}?confirm=true`; window.LogConfig.logApiCall('DELETE', url, null, 'request'); merchantDetailLog.info('Deleting merchant:', this.merchantId); await apiClient.delete(url); window.LogConfig.logApiCall('DELETE', url, null, 'response'); Utils.showToast(I18n.t('tenancy.messages.merchant_deleted_successfully'), 'success'); merchantDetailLog.info('Merchant deleted successfully'); // Redirect to merchants list setTimeout(() => window.location.href = '/admin/merchants', 1500); } catch (error) { window.LogConfig.logError(error, 'Delete Merchant'); Utils.showToast(error.message || 'Failed to delete merchant', 'error'); } }, // Refresh merchant data async refresh() { merchantDetailLog.info('=== MERCHANT REFRESH TRIGGERED ==='); await this.loadMerchant(); Utils.showToast(I18n.t('tenancy.messages.merchant_details_refreshed'), 'success'); merchantDetailLog.info('=== MERCHANT REFRESH COMPLETE ==='); } }; } merchantDetailLog.info('Merchant detail module loaded');