PluginProbe
Easy Invoice – Invoice Generator, PDF Quotes & Payments / 2.3.2
Easy Invoice – Invoice Generator, PDF Quotes & Payments v2.3.2
2.4.0 2.4.1 2.3.8 2.3.7 2.3.6 2.3.5 2.3.4 2.3.3 2.3.2 2.3.1 2.2.0 2.1.21 2.1.20 2.1.19 2.1.18 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.13 2.1.14 2.1.15 2.1.16 2.1.2 All 57 releases
easy-invoice / templates / payment-section.php

payment-section.php in Easy Invoice – Invoice Generator, PDF Quotes & Payments 2.3.2, at templates/payment-section.php

974 lines 26.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Payment Section Template
4 *
5 * Displays payment options and processing UI
6 *
7 * @package EasyInvoice
8 * @since 1.0.0
9 */
10
11 // Get invoice data
12 $invoice_id = get_the_ID();
13 $invoice = new \EasyInvoice\Models\Invoice(get_post($invoice_id));
14 $total_amount = $invoice->getTotal();
15 $currency_code = $invoice->getCurrencyCode() ?: 'USD';
16
17 // If currency is "global", use the global setting
18 if ($currency_code === 'global') {
19 $currency_code = get_option('easy_invoice_currency_code', 'USD');
20 }
21
22 $currency_symbol = \EasyInvoice\Helpers\CurrencyHelper::getCurrencySymbol($currency_code);
23
24 // Get available payment gateways
25 $payment_controller = new \EasyInvoice\Controllers\PaymentController();
26 $available_gateways = $payment_controller->getAvailableGateways($invoice_id);
27
28 // Get nonce for AJAX security
29 $payment_nonce = wp_create_nonce('easy_invoice_payment');
30
31
32 ?>
33
34 <div class="easy-invoice-payment-sidebar">
35 <div class="payment-header">
36 <div class="header-content">
37 <h2><?php _e('Payment', 'easy-invoice'); ?></h2>
38 <div class="invoice-summary">
39 <span class="invoice-number"><?php echo esc_html($invoice->getNumber()); ?></span>
40 <span class="invoice-date"><?php echo esc_html(date_i18n('M j, Y', strtotime($invoice->getIssueDate()))); ?></span>
41 </div>
42 </div>
43
44 <div class="amount-display">
45 <div class="amount-label"><?php _e('Total Amount', 'easy-invoice'); ?></div>
46 <div class="amount-value">
47 <?php echo esc_html($currency_symbol . number_format($total_amount, 2)); ?>
48 </div>
49 </div>
50 </div>
51
52 <?php if (empty($available_gateways)): ?>
53 <div class="no-payment-methods">
54 <div class="empty-state">
55 <div class="empty-icon">
56 <i class="fas fa-credit-card"></i>
57 </div>
58 <h3><?php _e('No Payment Methods', 'easy-invoice'); ?></h3>
59 <p><?php _e('Payment methods are not configured for this invoice.', 'easy-invoice'); ?></p>
60 </div>
61 </div>
62 <?php else: ?>
63 <form id="easy-invoice-payment-form" class="payment-form">
64 <input type="hidden" name="invoice_id" value="<?php echo esc_attr($invoice_id); ?>">
65 <input type="hidden" name="payment_nonce" value="<?php echo esc_attr($payment_nonce); ?>">
66 <input type="hidden" name="payment_amount" id="payment_amount" value="<?php echo esc_attr($total_amount); ?>">
67 <input type="hidden" name="payment_note" id="payment_note" value="">
68 <input type="hidden" name="action" value="easy_invoice_process_payment">
69 <input type="hidden" name="is_partial_payment" id="is_partial_payment" value="0">
70 <input type="hidden" name="payment_method" id="payment_method" value="">
71
72 <?php
73 // Add partial payments form before payment gateways (only if enabled)
74 do_action('easy_invoice_payment_gateways_before', $invoice);
75
76 ?>
77
78 <div class="payment-methods">
79 <label class="section-label"><?php _e('Payment Method', 'easy-invoice'); ?></label>
80
81 <div class="method-options">
82 <?php foreach ($available_gateways as $gateway): ?>
83 <div class="method-option" data-gateway="<?php echo esc_attr($gateway['id']); ?>">
84 <input type="radio"
85 name="payment_method_radio"
86 id="payment_method_<?php echo esc_attr($gateway['id']); ?>"
87 value="<?php echo esc_attr($gateway['id']); ?>"
88 class="method-radio">
89
90 <label for="payment_method_<?php echo esc_attr($gateway['id']); ?>" class="method-label">
91 <div class="method-content">
92 <div class="method-icon">
93 <?php if (!empty($gateway['icon'])): ?>
94 <i class="<?php echo esc_attr($gateway['icon']); ?>"></i>
95 <?php else: ?>
96 <i class="fas fa-credit-card"></i>
97 <?php endif; ?>
98 </div>
99
100 <div class="method-details">
101 <div class="method-name"><?php echo esc_html($gateway['title']); ?></div>
102 <?php if (!empty($gateway['description'])): ?>
103 <div class="method-description"><?php echo esc_html($gateway['description']); ?></div>
104 <?php endif; ?>
105 </div>
106
107 <div class="method-check">
108 <div class="checkmark"></div>
109 </div>
110 </div>
111 </label>
112
113 <div class="gateway-content" id="gateway-content-<?php echo esc_attr($gateway['id']); ?>" style="display: none;"></div>
114 </div>
115 <?php endforeach; ?>
116 </div>
117 </div>
118
119 <div class="message-area" id="payment-message-area"></div>
120
121 <div class="submit-section">
122 <button type="submit" id="pay-now-button" class="submit-button" disabled>
123 <span class="button-text"><?php _e('Pay', 'easy-invoice'); ?> <?php echo esc_html($currency_symbol . number_format($total_amount, 2)); ?></span>
124 <div class="button-loader hidden">
125 <div class="loader"></div>
126 <span><?php _e('Processing...', 'easy-invoice'); ?></span>
127 </div>
128 </button>
129
130 <div class="security-note">
131 <i class="fas fa-lock"></i>
132 <span><?php _e('Your payment is secure and encrypted', 'easy-invoice'); ?></span>
133 </div>
134 </div>
135 </form>
136 <?php endif; ?>
137 </div>
138
139 <style>
140 /* Clean SaaS Payment Sidebar */
141 .easy-invoice-payment-sidebar {
142 background: #ffffff;
143 height: 100vh;
144 display: flex;
145 flex-direction: column;
146 border-left: 1px solid #e5e7eb;
147 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
148 box-shadow: -4px 0 12px rgba(0, 0, 0, 0.05);
149 }
150
151 /* Header */
152 .payment-header {
153 padding: 32px 24px 24px;
154 border-bottom: 1px solid #f3f4f6;
155 background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
156 }
157
158 .header-content h2 {
159 margin: 0 0 8px 0;
160 font-size: 24px;
161 font-weight: 600;
162 color: #111827;
163 line-height: 1.2;
164 }
165
166 .invoice-summary {
167 display: flex;
168 align-items: center;
169 gap: 12px;
170 font-size: 14px;
171 color: #6b7280;
172 }
173
174 .invoice-number {
175 font-weight: 500;
176 color: #374151;
177 }
178
179 .invoice-date {
180 color: #9ca3af;
181 }
182
183 .amount-display {
184 margin-top: 20px;
185 padding: 20px;
186 background: #ffffff;
187 border: 1px solid #e5e7eb;
188 border-radius: 12px;
189 box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
190 }
191
192 .amount-label {
193 font-size: 12px;
194 font-weight: 500;
195 color: #6b7280;
196 text-transform: uppercase;
197 letter-spacing: 0.5px;
198 margin-bottom: 4px;
199 }
200
201 .amount-value {
202 font-size: 18px;
203 font-weight: 700;
204 color: #111827;
205 line-height: 1;
206 }
207
208 /* No Payment Methods */
209 .no-payment-methods {
210 flex: 1;
211 display: flex;
212 align-items: center;
213 justify-content: center;
214 padding: 40px 24px;
215 }
216
217 .empty-state {
218 text-align: center;
219 max-width: 280px;
220 }
221
222 .empty-icon {
223 width: 48px;
224 height: 48px;
225 background: #f3f4f6;
226 border-radius: 12px;
227 display: flex;
228 align-items: center;
229 justify-content: center;
230 margin: 0 auto 16px;
231 color: #9ca3af;
232 font-size: 20px;
233 }
234
235 .empty-state h3 {
236 margin: 0 0 8px 0;
237 font-size: 16px;
238 font-weight: 600;
239 color: #374151;
240 }
241
242 .empty-state p {
243 margin: 0;
244 font-size: 14px;
245 color: #6b7280;
246 line-height: 1.5;
247 }
248
249 /* Payment Form */
250 .payment-form {
251 flex: 1;
252 display: flex;
253 flex-direction: column;
254 padding: 24px;
255 overflow-y: auto;
256 }
257
258 /* Payment Methods */
259 .payment-methods {
260 margin-bottom: 24px;
261 }
262
263 .section-label {
264 display: block;
265 font-size: 14px;
266 font-weight: 600;
267 color: #374151;
268 margin-bottom: 16px;
269 }
270
271 .method-options {
272 display: flex;
273 flex-direction: column;
274 gap: 12px;
275 }
276
277 /* Gateway Content */
278 .gateway-content {
279 padding: 20px;
280 background: #ffffff;
281 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
282 border-top: 2px solid #10b981;
283 }
284
285 .gateway-content h4 {
286 margin: 0 0 16px 0;
287 font-size: 16px;
288 font-weight: 600;
289 color: #111827;
290 line-height: 1.4;
291 }
292
293 .gateway-content p {
294 margin: 0 0 12px 0;
295 font-size: 14px;
296 line-height: 1.5;
297 color: #374151;
298 }
299
300 .gateway-content .bank-details,
301 .gateway-content .payment-reference {
302 margin: 16px 0;
303 padding: 16px;
304 background: #f8fafc;
305 border-radius: 8px;
306 border: 1px solid #e5e7eb;
307 }
308
309 .gateway-content .payment-reference {
310 background: #f0f7ff;
311 border-left: 4px solid #0073aa;
312 }
313
314 .gateway-content .reference-note {
315 font-style: italic;
316 color: #6b7280;
317 margin-top: 8px;
318 font-size: 13px;
319 }
320
321 .gateway-content .payment-proof-form {
322 margin-top: 24px;
323 padding-top: 20px;
324 border-top: 1px solid #e5e7eb;
325 }
326
327
328
329 /* Gateway-specific instruction styles */
330 .gateway-content .bank-transfer-instructions,
331 .gateway-content .cheque-payment-instructions,
332 .gateway-content .cash-payment-instructions {
333 margin: 0;
334 padding: 0;
335 background: transparent;
336 border: none;
337 border-radius: 0;
338 border-left: none;
339 }
340
341 .gateway-content .bank-details-table {
342 width: 100%;
343 border-collapse: collapse;
344 margin-bottom: 16px;
345 }
346
347 .gateway-content .bank-details-table th,
348 .gateway-content .bank-details-table td {
349 padding: 8px 12px;
350 border-bottom: 1px solid #e5e7eb;
351 text-align: left;
352 }
353
354 .gateway-content .bank-details-table th {
355 width: 40%;
356 font-weight: 600;
357 color: #374151;
358 }
359
360 .gateway-content .cheque-details,
361 .gateway-content .cash-details {
362 margin-bottom: 16px;
363 }
364
365 .gateway-content .payable-to,
366 .gateway-content .invoice-number {
367 font-size: 16px;
368 margin: 8px 0 16px;
369 color: #0073aa;
370 font-weight: 600;
371 }
372
373 .gateway-content .mailing-address {
374 padding: 12px;
375 background: #f0f7ff;
376 border-left: 3px solid #0073aa;
377 margin-top: 8px;
378 border-radius: 6px;
379 }
380
381 .gateway-content .cheque-notification-form {
382 margin-top: 20px;
383 border-top: 1px solid #e5e7eb;
384 padding-top: 16px;
385 }
386
387 .gateway-content .submit-notification-btn {
388 background: #0073aa;
389 color: white;
390 padding: 10px 20px;
391 border: none;
392 border-radius: 6px;
393 cursor: pointer;
394 font-size: 14px;
395 font-weight: 500;
396 transition: background-color 0.2s ease;
397 }
398
399 .gateway-content .submit-notification-btn:hover {
400 background: #005d8c;
401 }
402
403 .gateway-content .submit-notification-btn:disabled {
404 background: #9ca3af;
405 cursor: not-allowed;
406 }
407
408
409
410 .method-option {
411 border: 2px solid #e5e7eb;
412 border-radius: 12px;
413 transition: all 0.2s ease;
414 background: #ffffff;
415 overflow: hidden;
416 }
417
418 .method-option:hover {
419 border-color: #d1d5db;
420 box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
421 transform: translateY(-1px);
422 }
423
424 .method-option.selected {
425 border-color: #10b981;
426 box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.1);
427 background: #f0fdf4;
428 }
429
430 .method-radio {
431 display: none;
432 }
433
434 .method-label {
435 display: block;
436 padding: 20px;
437 cursor: pointer;
438 margin: 0;
439 }
440
441 .method-content {
442 display: flex;
443 align-items: center;
444 gap: 16px;
445 }
446
447 .method-icon {
448 width: 40px;
449 height: 40px;
450 background: #f9fafb;
451 border-radius: 10px;
452 display: flex;
453 align-items: center;
454 justify-content: center;
455 color: #6b7280;
456 font-size: 18px;
457 flex-shrink: 0;
458 transition: all 0.2s ease;
459 }
460
461 .method-option.selected .method-icon {
462 background: #10b981;
463 color: #ffffff;
464 }
465
466 .method-details {
467 flex: 1;
468 min-width: 0;
469 }
470
471 .method-name {
472 font-weight: 600;
473 font-size: 15px;
474 color: #111827;
475 margin-bottom: 4px;
476 }
477
478 .method-description {
479 font-size: 13px;
480 color: #6b7280;
481 line-height: 1.4;
482 }
483
484 .method-check {
485 flex-shrink: 0;
486 }
487
488 .checkmark {
489 width: 24px;
490 height: 24px;
491 border: 2px solid #d1d5db;
492 border-radius: 50%;
493 position: relative;
494 transition: all 0.2s ease;
495 }
496
497 .checkmark::after {
498 content: '';
499 position: absolute;
500 top: 50%;
501 left: 50%;
502 transform: translate(-50%, -50%);
503 width: 10px;
504 height: 10px;
505 background: #ffffff;
506 border-radius: 50%;
507 opacity: 0;
508 transition: opacity 0.2s ease;
509 }
510
511 .method-option.selected .checkmark {
512 background: #10b981;
513 border-color: #10b981;
514 }
515
516 .method-option.selected .checkmark::after {
517 opacity: 1;
518 }
519
520
521
522 /* Message Area */
523 .message-area {
524 margin-bottom: 24px;
525 min-height: 20px;
526 }
527
528 .payment-message {
529 padding: 16px 20px;
530 border-radius: 8px;
531 font-size: 14px;
532 display: flex;
533 align-items: center;
534 gap: 12px;
535 border: 1px solid;
536 box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04);
537 }
538
539 .payment-message.success {
540 background: #f0fdf4;
541 color: #166534;
542 border-color: #bbf7d0;
543 }
544
545 .payment-message.error {
546 background: #fef2f2;
547 color: #dc2626;
548 border-color: #fecaca;
549 }
550
551 .payment-message.warning {
552 background: #fffbeb;
553 color: #d97706;
554 border-color: #fed7aa;
555 }
556
557 .payment-message.info {
558 background: #eff6ff;
559 color: #1d4ed8;
560 border-color: #bfdbfe;
561 }
562
563
564
565 /* Submit Section */
566 .submit-section {
567 margin-top: auto;
568 padding-top: 24px;
569 border-top: 1px solid #f3f4f6;
570 }
571
572 .submit-button {
573 width: 100%;
574 padding: 18px 24px;
575 background: linear-gradient(135deg, #10b981 0%, #059669 100%);
576 color: #ffffff;
577 border: none;
578 border-radius: 12px;
579 font-size: 16px;
580 font-weight: 600;
581 cursor: pointer;
582 transition: all 0.3s ease;
583 display: flex;
584 align-items: center;
585 justify-content: center;
586 gap: 10px;
587 position: relative;
588 box-shadow: 0 4px 12px rgba(16, 185, 129, 0.3);
589 }
590
591 .submit-button:hover:not(:disabled) {
592 background: linear-gradient(135deg, #059669 0%, #047857 100%);
593 transform: translateY(-2px);
594 box-shadow: 0 8px 20px rgba(16, 185, 129, 0.4);
595 }
596
597 .submit-button:active:not(:disabled) {
598 transform: translateY(0);
599 box-shadow: 0 4px 12px rgba(16, 185, 129, 0.3);
600 }
601
602 .submit-button:disabled {
603 background: #9ca3af;
604 cursor: not-allowed;
605 transform: none;
606 box-shadow: none;
607 }
608
609 .button-loader {
610 display: flex;
611 align-items: center;
612 gap: 10px;
613 }
614
615 .button-loader.hidden {
616 display: none;
617 }
618
619 .loader {
620 width: 18px;
621 height: 18px;
622 border: 2px solid rgba(255, 255, 255, 0.3);
623 border-top: 2px solid #ffffff;
624 border-radius: 50%;
625 animation: spin 1s linear infinite;
626 }
627
628 @keyframes spin {
629 0% { transform: rotate(0deg); }
630 100% { transform: rotate(360deg); }
631 }
632
633 .security-note {
634 display: flex;
635 align-items: center;
636 justify-content: center;
637 gap: 8px;
638 margin-top: 16px;
639 font-size: 13px;
640 color: #6b7280;
641 padding: 12px;
642 background: #f9fafb;
643 border-radius: 8px;
644 }
645
646 .security-note i {
647 font-size: 14px;
648 color: #10b981;
649 }
650
651 /* Responsive */
652 @media (max-width: 768px) {
653 .easy-invoice-payment-sidebar {
654 width: 100%;
655 height: 100vh;
656 }
657
658 .payment-header {
659 padding: 24px 20px 20px;
660 }
661
662 .payment-form {
663 padding: 20px;
664 }
665
666 .method-label {
667 padding: 16px;
668 }
669
670 .submit-button {
671 padding: 16px 20px;
672 }
673 }
674
675 /* Scrollbar */
676 .payment-form::-webkit-scrollbar {
677 width: 6px;
678 }
679
680 .payment-form::-webkit-scrollbar-track {
681 background: #f1f5f9;
682 border-radius: 3px;
683 }
684
685 .payment-form::-webkit-scrollbar-thumb {
686 background: #cbd5e1;
687 border-radius: 3px;
688 }
689
690 .payment-form::-webkit-scrollbar-thumb:hover {
691 background: #94a3b8;
692 }
693
694
695
696 /* Utility */
697 .hidden {
698 display: none !important;
699 }
700 </style>
701
702 <script>
703 document.addEventListener('DOMContentLoaded', function() {
704 const paymentForm = document.getElementById('easy-invoice-payment-form');
705 const payButton = document.getElementById('pay-now-button');
706 const messageArea = document.getElementById('payment-message-area');
707 const paymentMethods = document.querySelectorAll('input[name="payment_method_radio"]');
708 const paymentAmountInput = document.getElementById('payment_amount');
709
710 window.selectedGateway = null;
711
712 // Initialize payment methods
713 paymentMethods.forEach(method => {
714 method.addEventListener('change', handlePaymentMethodChange);
715 });
716
717 // Handle payment amount changes
718 if (paymentAmountInput) {
719 paymentAmountInput.addEventListener('input', updatePayButtonText);
720 paymentAmountInput.addEventListener('change', updatePayButtonText);
721 }
722
723 // Initialize button text on page load (always call this)
724 updatePayButtonText();
725
726 // Also call it after a short delay to ensure all elements are loaded
727 setTimeout(() => {
728 updatePayButtonText();
729 }, 500);
730
731 // Handle form submission
732 paymentForm.addEventListener('submit', handlePaymentSubmit);
733
734 function handlePaymentMethodChange(e) {
735 window.selectedGateway = e.target.value;
736 const methodEntry = e.target.closest('.method-option');
737
738 // Update UI
739 document.querySelectorAll('.method-option').forEach(entry => {
740 entry.classList.remove('selected');
741 });
742 methodEntry.classList.add('selected');
743
744 // Update hidden payment_method field
745 const paymentMethodField = document.getElementById('payment_method');
746 if (paymentMethodField) {
747 paymentMethodField.value = window.selectedGateway;
748 }
749
750 // Enable pay button
751 payButton.disabled = false;
752
753 // Load gateway-specific content
754 loadGatewayContent(window.selectedGateway);
755 }
756
757 function loadGatewayContent(gateway) {
758 // Find the specific gateway content div for this gateway
759 const contentDiv = document.getElementById('gateway-content-' + gateway);
760
761 if (!contentDiv) {
762 console.error('Gateway content div not found for:', gateway);
763 return;
764 }
765
766 // Hide all gateway content divs first
767 document.querySelectorAll('.gateway-content').forEach(div => {
768 div.style.display = 'none';
769 });
770
771 // Clear existing content
772 contentDiv.innerHTML = '';
773
774
775 // Load gateway content via AJAX
776 const formData = new FormData();
777 formData.append('action', 'easy_invoice_get_payment_instructions');
778 formData.append('gateway', gateway);
779 formData.append('invoice_id', document.querySelector('input[name="invoice_id"]').value);
780 formData.append('nonce', document.querySelector('input[name="payment_nonce"]').value);
781
782 fetch('<?php echo admin_url('admin-ajax.php'); ?>', {
783 method: 'POST',
784 body: formData
785 })
786 .then(response => {
787 if (!response.ok) {
788 throw new Error('Network response was not ok');
789 }
790 return response.json();
791 })
792 .then(response => {
793 if (response.success && response.data.instructions) {
794 contentDiv.innerHTML = response.data.instructions;
795 contentDiv.style.display = 'block';
796 } else {
797 contentDiv.style.display = 'none';
798 }
799 })
800 .catch(error => {
801 console.error('Error loading gateway content:', error);
802 contentDiv.style.display = 'none';
803 });
804 }
805
806 function loadGatewayContentViaAjax(gateway, contentDiv) {
807 const formData = new FormData();
808 formData.append('action', 'easy_invoice_get_payment_instructions');
809 formData.append('gateway', gateway);
810 formData.append('invoice_id', document.querySelector('input[name="invoice_id"]').value);
811 formData.append('nonce', document.querySelector('input[name="payment_nonce"]').value);
812
813 fetch('<?php echo admin_url('admin-ajax.php'); ?>', {
814 method: 'POST',
815 body: formData
816 })
817 .then(response => response.json())
818 .then(response => {
819 if (response.success && response.data.instructions) {
820 contentDiv.innerHTML = response.data.instructions;
821 contentDiv.style.display = 'block';
822 } else {
823 contentDiv.style.display = 'none';
824 }
825 })
826 .catch(error => {
827 console.error('Error loading gateway content:', error);
828 contentDiv.style.display = 'none';
829 });
830 }
831
832
833
834 function handlePaymentSubmit(e) {
835 e.preventDefault();
836 payButton.disabled = true;
837
838 if (!window.selectedGateway) {
839 showPaymentMessage('Please select a payment method first.', 'error');
840 payButton.disabled = false;
841 return;
842 }
843
844 // Show loading state
845 payButton.querySelector('.button-text').classList.add('hidden');
846 payButton.querySelector('.button-loader').classList.remove('hidden');
847
848 // Handle all payment methods (PayPal, etc.)
849 processStandardPayment();
850 }
851
852
853
854 function processStandardPayment() {
855 const formData = new FormData(paymentForm);
856 formData.append('payment_method', window.selectedGateway);
857
858 // Get AJAX URL from WordPress
859 const ajaxUrl = '<?php echo admin_url('admin-ajax.php'); ?>';
860
861 fetch(ajaxUrl, {
862 method: 'POST',
863 body: formData
864 })
865 .then(response => response.json())
866 .then(response => {
867 if (response.success) {
868 handlePaymentSuccess(response.data);
869 } else {
870 const errorMsg = response.data && response.data.message
871 ? response.data.message
872 : 'Payment processing failed.';
873 showPaymentMessage(errorMsg, 'error');
874 resetPayButton();
875 }
876 })
877 .catch(error => {
878 console.error('Payment AJAX error:', error);
879 showPaymentMessage('Server error during payment. Please try again.', 'error');
880 resetPayButton();
881 });
882 }
883
884
885
886 function handlePaymentSuccess(data) {
887 // Handle redirect if provided (for PayPal and other external gateways)
888 if (data.redirect_url) {
889 // Get gateway-specific message or use default
890 const redirectMessage = data.message || 'Redirecting to payment gateway to complete your payment...';
891
892 // Update button state to show redirecting
893 payButton.querySelector('.button-text').textContent = 'Processing...';
894 payButton.querySelector('.button-loader').classList.add('hidden');
895 payButton.querySelector('.button-text').classList.remove('hidden');
896 payButton.disabled = true;
897
898 // Show redirect message
899 showPaymentMessage(redirectMessage, 'info');
900
901 // Redirect immediately
902 setTimeout(() => {
903 window.location.href = data.redirect_url;
904 }, 1000);
905 return;
906 }
907
908 // For successful payments without redirect
909 // Update button state
910 payButton.querySelector('.button-text').textContent = 'Payment Successful!';
911 payButton.querySelector('.button-loader').classList.add('hidden');
912 payButton.querySelector('.button-text').classList.remove('hidden');
913 payButton.disabled = true;
914
915 // Show success message
916 showPaymentMessage(data.message || 'Payment successful!', 'success');
917
918 // Reload the page after delay
919 setTimeout(() => {
920 window.location.reload();
921 }, 2000);
922 }
923
924 function showPaymentMessage(message, type) {
925 let icon = 'info-circle';
926 if (type === 'success') {
927 icon = 'check-circle';
928 } else if (type === 'error') {
929 icon = 'exclamation-triangle';
930 } else if (type === 'warning') {
931 icon = 'exclamation-triangle';
932 }
933
934 messageArea.innerHTML = `
935 <div class="payment-message ${type}">
936 <i class="fas fa-${icon}"></i>
937 ${message}
938 </div>
939 `;
940 }
941
942 function updatePayButtonText() {
943 const hiddenPaymentAmount = document.getElementById('payment_amount');
944 const paymentAmount = hiddenPaymentAmount ? hiddenPaymentAmount.value : '0';
945 const currencySymbol = '<?php echo esc_js($currency_symbol); ?>';
946
947 if (paymentAmount && paymentAmount > 0) {
948 const formattedAmount = parseFloat(paymentAmount).toFixed(2);
949 payButton.querySelector('.button-text').textContent = `Pay ${currencySymbol}${formattedAmount}`;
950 } else {
951 payButton.querySelector('.button-text').textContent = 'Pay';
952 }
953 }
954
955 // Make the function globally accessible
956 window.updatePayButtonText = updatePayButtonText;
957
958 function resetPayButton() {
959 payButton.querySelector('.button-text').textContent = 'Pay Now';
960 payButton.querySelector('.button-loader').classList.add('hidden');
961 payButton.querySelector('.button-text').classList.remove('hidden');
962 payButton.disabled = false;
963 }
964
965
966
967
968 });
969 </script>
970
971 <?php
972 // Allow Pro plugins to add additional variables
973 do_action('easy_invoice_payment_form_variables');
974 ?>