PluginProbe
Easy Invoice – Invoice Generator, PDF Quotes & Payments / 2.2.0
Easy Invoice – Invoice Generator, PDF Quotes & Payments v2.2.0
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.2.0, at templates/payment-section.php

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