init_hooks(); } /** * Initialize hooks. */ private function init_hooks() { add_action( 'admin_menu', array( $this, 'add_admin_menu' ) ); add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) ); } /** * Add admin menu. */ public function add_admin_menu() { // Only show if WooCommerce is active. if ( ! class_exists( 'WooCommerce' ) ) { return; } $menu_manager = AfriDirect_Payment_Admin_Menu::instance(); $parent_slug = $menu_manager->get_menu_slug(); $this->hook_suffix = add_submenu_page( $parent_slug, __( 'WooCommerce Payments', 'afridirect-payment' ), __( 'WooCommerce Payments', 'afridirect-payment' ), $menu_manager->get_capability(), 'afridirect-woo-payments', array( $this, 'render_payments_page' ) ); } /** * Enqueue scripts. */ public function enqueue_scripts( $hook ) { if ( $this->hook_suffix !== $hook ) { return; } wp_enqueue_style( 'afridirect-admin-woo-payments', AFRIDIRECT_PAYMENT_PLUGIN_URL . 'admin/css/admin.css', array(), afridirect_payment_asset_ver( 'admin/css/admin.css' ) ); wp_enqueue_script( 'afridirect-admin-woo-payments', AFRIDIRECT_PAYMENT_PLUGIN_URL . 'admin/js/admin.js', array( 'jquery' ), afridirect_payment_asset_ver( 'admin/js/admin.js' ), true ); wp_localize_script( 'afridirect-admin-woo-payments', 'afridirectPaymentAdmin', array( 'ajaxUrl' => admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'afridirect-payment-admin-nonce' ), 'i18n' => array( 'confirmApprove' => __( 'Are you sure you want to approve this order?', 'afridirect-payment' ), 'confirmReject' => __( 'Are you sure you want to reject this order?', 'afridirect-payment' ), 'provideReason' => __( 'Please provide a rejection reason.', 'afridirect-payment' ), 'errorOccurred' => __( 'An error occurred. Please try again.', 'afridirect-payment' ), ), ) ); wp_localize_script( 'afridirect-admin-woo-payments', 'afridirectPaymentAdmin', array( 'ajaxUrl' => admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'afridirect-payment-admin-nonce' ), 'i18n' => array( 'confirmApprove' => __( 'Are you sure you want to approve this order?', 'afridirect-payment' ), 'confirmReject' => __( 'Are you sure you want to reject this order?', 'afridirect-payment' ), 'provideReason' => __( 'Please provide a rejection reason.', 'afridirect-payment' ), 'errorOccurred' => __( 'An error occurred. Please try again.', 'afridirect-payment' ), ), ) ); // Built as a nowdoc (no PHP variable interpolation) so JS variables like // $form / $submitBtn are never mistaken for PHP variables. $afridirect_reject_modal_js = <<<'JS' (function($) { 'use strict'; $(document).ready(function() { // Reject modal functionality. var rejectModal = $('#afridirect-reject-order-modal'); var rejectForm = $('#afridirect-reject-order-form'); // Open reject modal. $(document).on('click', '.afridirect-reject-btn', function(e) { e.preventDefault(); var orderId = $(this).data('order-id'); $('#afridirect-reject-order-id').val(orderId); rejectModal.fadeIn(); }); // Close modal. $(document).on('click', '.afridirect-modal-cancel, .afridirect-modal-close', function() { rejectModal.fadeOut(); rejectForm[0].reset(); }); // Submit reject form (use event delegation to avoid conflicts). $(document).on('submit', '#afridirect-reject-order-form', function(e) { e.preventDefault(); e.stopImmediatePropagation(); // Prevent other handlers from running var $form = $(this); // Check if already processing if ($form.data('processing')) { return false; } var reason = $('#afridirect-reject-reason').val(); if (!reason || !reason.trim()) { alert(afridirectPaymentAdmin.i18n.provideReason); $('#afridirect-reject-reason').focus(); return false; } var $submitBtn = $form.find('button[type="submit"]'); var originalText = $submitBtn.text(); $submitBtn.prop('disabled', true).text('Processing...'); $form.data('processing', true); var formData = new FormData(this); formData.append('action', 'afridirect_reject_order'); // Ensure order_id and reason are included. if (!formData.has('order_id')) { formData.append('order_id', $('#afridirect-reject-order-id').val()); } if (!formData.has('reason')) { formData.append('reason', reason); } if (!formData.has('nonce')) { formData.append('nonce', afridirectPaymentAdmin.nonce); } $.ajax({ url: afridirectPaymentAdmin.ajaxUrl, type: 'POST', data: formData, processData: false, contentType: false, timeout: 30000, // 30 second timeout success: function(response) { $form.data('processing', false); console.log('Reject order response:', response); if (response && response.success) { var message = (response.data && response.data.message) ? response.data.message : 'Order rejected successfully.'; alert(message); // Small delay before reload to ensure user sees the message setTimeout(function() { location.reload(); }, 100); } else { var errorMsg = (response && response.data && response.data.message) ? response.data.message : (afridirectPaymentAdmin.i18n.errorOccurred || 'An error occurred. Please try again.'); alert(errorMsg); $submitBtn.prop('disabled', false).text(originalText); } }, error: function(xhr, status, error) { $form.data('processing', false); console.error('Reject order AJAX error:', { status: status, error: error, statusCode: xhr.status, responseText: xhr.responseText, responseJSON: xhr.responseJSON }); var errorMsg = afridirectPaymentAdmin.i18n.errorOccurred || 'An error occurred. Please try again.'; if (xhr.responseJSON) { if (xhr.responseJSON.data && xhr.responseJSON.data.message) { errorMsg = xhr.responseJSON.data.message; } else if (xhr.responseJSON.message) { errorMsg = xhr.responseJSON.message; } } else if (xhr.responseText) { // Try to parse response text try { var parsed = JSON.parse(xhr.responseText); if (parsed.data && parsed.data.message) { errorMsg = parsed.data.message; } } catch(e) { // Not JSON, use default message } } alert(errorMsg); $submitBtn.prop('disabled', false).text(originalText); } }); return false; }); }); // End document ready })(jQuery); JS; wp_add_inline_script( 'afridirect-admin-woo-payments', $afridirect_reject_modal_js, 'after' ); } /** * Render payments list page. */ public function render_payments_page() { $menu_manager = AfriDirect_Payment_Admin_Menu::instance(); if ( ! current_user_can( $menu_manager->get_capability() ) ) { wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'afridirect-payment' ) ); } // Get orders that need review. // Criteria: payment method = afridirect_payment, status in (on-hold, pending) AND has proof uploaded. // Also include afridirect-pending and afridirect-proof statuses as they are part of the workflow. $orders = wc_get_orders( array( 'payment_method' => 'afridirect_payment', 'status' => array( 'on-hold', 'pending', 'adp-pending', 'adp-proof' ), 'limit' => 100, 'orderby' => 'date', 'order' => 'DESC', ) ); // Filter to only show orders that have proof uploaded (proof_url or proof_attachment_id exists). // Also exclude orders that have already been reviewed (approved/declined). $orders_with_proof = array(); foreach ( $orders as $order ) { $proof_url = $order->get_meta( '_afridirect_proof_url' ); $proof_attachment_id = $order->get_meta( '_afridirect_proof_attachment_id' ); $review_status = $order->get_meta( '_afridirect_review_status' ); // Only show orders with proof that haven't been reviewed yet. if ( ( $proof_url || $proof_attachment_id ) && ! in_array( $review_status, array( 'approved', 'declined' ), true ) ) { $orders_with_proof[] = $order; } } include AFRIDIRECT_PAYMENT_PLUGIN_DIR . 'admin/views/woo-payments.php'; } }