// static/admin/js/merchant-edit.js // Create custom logger for merchant edit const merchantEditLog = window.LogConfig.createLogger('MERCHANT-EDIT'); function adminMerchantEdit() { return { // Inherit base layout functionality from init-alpine.js ...data(), // Merchant edit page specific state currentPage: 'merchant-edit', loading: false, merchant: null, formData: {}, errors: {}, loadingMerchant: false, saving: false, merchantId: null, // Modal state showToggleVerificationModal: false, showToggleActiveModal: false, showDeleteMerchantModal: false, showDeleteMerchantFinalModal: false, // Transfer ownership state showTransferOwnershipModal: false, transferring: false, transferData: { new_owner_user_id: null, confirm_transfer: false, transfer_reason: '' }, // User search state userSearchQuery: '', userSearchResults: [], selectedUser: null, showUserDropdown: false, searchingUsers: false, searchDebounceTimer: null, showConfirmError: false, showOwnerError: false, // Initialize async init() { // Load i18n translations await I18n.loadModule('tenancy'); merchantEditLog.info('=== MERCHANT EDIT PAGE INITIALIZING ==='); // Prevent multiple initializations if (window._merchantEditInitialized) { merchantEditLog.warn('Merchant edit page already initialized, skipping...'); return; } window._merchantEditInitialized = true; try { // Get merchant ID from URL const path = window.location.pathname; const match = path.match(/\/admin\/merchants\/(\d+)\/edit/); if (match) { this.merchantId = parseInt(match[1], 10); merchantEditLog.info('Editing merchant:', this.merchantId); await this.loadMerchant(); } else { merchantEditLog.error('No merchant ID in URL'); Utils.showToast(I18n.t('tenancy.messages.invalid_merchant_url'), 'error'); setTimeout(() => window.location.href = '/admin/merchants', 2000); } merchantEditLog.info('=== MERCHANT EDIT PAGE INITIALIZATION COMPLETE ==='); } catch (error) { window.LogConfig.logError(error, 'Merchant Edit Init'); Utils.showToast(I18n.t('tenancy.messages.failed_to_initialize_page'), 'error'); } }, // Load merchant data async loadMerchant() { merchantEditLog.info('Loading merchant data...'); this.loadingMerchant = true; 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', duration); this.merchant = response; // Initialize form data this.formData = { name: response.name || '', description: response.description || '', contact_email: response.contact_email || '', contact_phone: response.contact_phone || '', website: response.website || '', business_address: response.business_address || '', tax_number: response.tax_number || '' }; merchantEditLog.info(`Merchant loaded in ${duration}ms`, { merchant_id: this.merchant.id, name: this.merchant.name }); merchantEditLog.debug('Form data initialized:', this.formData); } catch (error) { window.LogConfig.logError(error, 'Load Merchant'); Utils.showToast(I18n.t('tenancy.messages.failed_to_load_merchant'), 'error'); setTimeout(() => window.location.href = '/admin/merchants', 2000); } finally { this.loadingMerchant = false; } }, // Submit form async handleSubmit() { merchantEditLog.info('=== SUBMITTING MERCHANT UPDATE ==='); merchantEditLog.debug('Form data:', this.formData); this.errors = {}; this.saving = true; try { const url = `/admin/merchants/${this.merchantId}`; window.LogConfig.logApiCall('PUT', url, this.formData, 'request'); const startTime = performance.now(); const response = await apiClient.put(url, this.formData); const duration = performance.now() - startTime; window.LogConfig.logApiCall('PUT', url, response, 'response'); window.LogConfig.logPerformance('Update Merchant', duration); this.merchant = response; Utils.showToast(I18n.t('tenancy.messages.merchant_updated_successfully'), 'success'); merchantEditLog.info(`Merchant updated successfully in ${duration}ms`, response); } catch (error) { window.LogConfig.logError(error, 'Update Merchant'); // Handle validation errors if (error.details && error.details.validation_errors) { error.details.validation_errors.forEach(err => { const field = err.loc?.[1] || err.loc?.[0]; if (field) { this.errors[field] = err.msg; } }); merchantEditLog.debug('Validation errors:', this.errors); } Utils.showToast(error.message || 'Failed to update merchant', 'error'); } finally { this.saving = false; merchantEditLog.info('=== MERCHANT UPDATE COMPLETE ==='); } }, // Toggle verification async toggleVerification() { const action = this.merchant.is_verified ? 'unverify' : 'verify'; merchantEditLog.info(`Toggle verification: ${action}`); this.saving = true; try { const url = `/admin/merchants/${this.merchantId}/verification`; const payload = { is_verified: !this.merchant.is_verified }; window.LogConfig.logApiCall('PUT', url, payload, 'request'); const response = await apiClient.put(url, payload); window.LogConfig.logApiCall('PUT', url, response, 'response'); this.merchant = response; Utils.showToast(`Merchant ${action}ed successfully`, 'success'); merchantEditLog.info(`Merchant ${action}ed successfully`); } catch (error) { window.LogConfig.logError(error, `Toggle Verification (${action})`); Utils.showToast(`Failed to ${action} merchant`, 'error'); } finally { this.saving = false; } }, // Toggle active status async toggleActive() { const action = this.merchant.is_active ? 'deactivate' : 'activate'; merchantEditLog.info(`Toggle active status: ${action}`); this.saving = true; try { const url = `/admin/merchants/${this.merchantId}/status`; const payload = { is_active: !this.merchant.is_active }; window.LogConfig.logApiCall('PUT', url, payload, 'request'); const response = await apiClient.put(url, payload); window.LogConfig.logApiCall('PUT', url, response, 'response'); this.merchant = response; Utils.showToast(`Merchant ${action}d successfully`, 'success'); merchantEditLog.info(`Merchant ${action}d successfully`); } catch (error) { window.LogConfig.logError(error, `Toggle Active Status (${action})`); Utils.showToast(`Failed to ${action} merchant`, 'error'); } finally { this.saving = false; } }, // Transfer merchant ownership async transferOwnership() { merchantEditLog.info('=== TRANSFERRING MERCHANT OWNERSHIP ==='); merchantEditLog.debug('Transfer data:', this.transferData); if (!this.transferData.new_owner_user_id) { this.showOwnerError = true; return; } if (!this.transferData.confirm_transfer) { this.showConfirmError = true; return; } // Clear errors this.showOwnerError = false; this.showConfirmError = false; this.transferring = true; try { const url = `/admin/merchants/${this.merchantId}/transfer-ownership`; const payload = { new_owner_user_id: parseInt(this.transferData.new_owner_user_id, 10), confirm_transfer: true, transfer_reason: this.transferData.transfer_reason || null }; window.LogConfig.logApiCall('POST', url, payload, 'request'); const response = await apiClient.post(url, payload); window.LogConfig.logApiCall('POST', url, response, 'response'); Utils.showToast(I18n.t('tenancy.messages.ownership_transferred_successfully'), 'success'); merchantEditLog.info('Ownership transferred successfully', response); // Close modal and reload merchant data this.showTransferOwnershipModal = false; this.resetTransferData(); await this.loadMerchant(); } catch (error) { window.LogConfig.logError(error, 'Transfer Ownership'); Utils.showToast(error.message || 'Failed to transfer ownership', 'error'); } finally { this.transferring = false; merchantEditLog.info('=== OWNERSHIP TRANSFER COMPLETE ==='); } }, // Reset transfer data resetTransferData() { this.transferData = { new_owner_user_id: null, confirm_transfer: false, transfer_reason: '' }; this.userSearchQuery = ''; this.userSearchResults = []; this.selectedUser = null; this.showUserDropdown = false; this.showConfirmError = false; this.showOwnerError = false; }, // Search users for transfer ownership searchUsers() { // Debounce search clearTimeout(this.searchDebounceTimer); if (this.userSearchQuery.length < 2) { this.userSearchResults = []; this.showUserDropdown = false; return; } this.searchDebounceTimer = setTimeout(async () => { merchantEditLog.info('Searching users:', this.userSearchQuery); this.searchingUsers = true; this.showUserDropdown = true; try { const url = `/admin/users/search?q=${encodeURIComponent(this.userSearchQuery)}&limit=10`; const response = await apiClient.get(url); this.userSearchResults = response.users || response || []; merchantEditLog.debug('User search results:', this.userSearchResults); } catch (error) { window.LogConfig.logError(error, 'Search Users'); this.userSearchResults = []; } finally { this.searchingUsers = false; } }, 300); }, // Select a user from search results selectUser(user) { merchantEditLog.info('Selected user:', user); this.selectedUser = user; this.transferData.new_owner_user_id = user.id; this.userSearchQuery = user.username; this.showUserDropdown = false; this.userSearchResults = []; }, // Clear selected user clearSelectedUser() { this.selectedUser = null; this.transferData.new_owner_user_id = null; this.userSearchQuery = ''; this.userSearchResults = []; }, // Prompt delete merchant (first step of double confirm) promptDeleteMerchant() { merchantEditLog.info('=== DELETING MERCHANT ==='); if (this.merchant.store_count > 0) { Utils.showToast(`Cannot delete merchant with ${this.merchant.store_count} stores. Remove stores first.`, 'error'); return; } this.showDeleteMerchantModal = true; }, // Confirm first step, show final confirmation confirmDeleteMerchantStep() { this.showDeleteMerchantFinalModal = true; }, // Delete merchant async deleteMerchant() { merchantEditLog.info('=== DELETING MERCHANT (confirmed) ==='); this.saving = true; try { const url = `/admin/merchants/${this.merchantId}?confirm=true`; window.LogConfig.logApiCall('DELETE', url, null, 'request'); const response = await apiClient.delete(url); window.LogConfig.logApiCall('DELETE', url, response, 'response'); Utils.showToast(I18n.t('tenancy.messages.merchant_deleted_successfully'), 'success'); merchantEditLog.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'); } finally { this.saving = false; merchantEditLog.info('=== MERCHANT DELETION COMPLETE ==='); } } }; } merchantEditLog.info('Merchant edit module loaded');