PluginProbe
Easy Invoice – Invoice Generator, PDF Quotes & Payments / 2.4.0
Easy Invoice – Invoice Generator, PDF Quotes & Payments v2.4.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 / quotes / live-preview.php

live-preview.php in Easy Invoice – Invoice Generator, PDF Quotes & Payments 2.4.0, at templates/quotes/live-preview.php

215 lines 8.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) {
3 exit;
4 }
5 ?><div class="bg-white shadow rounded-lg" style="padding: 10px;">
6
7 <div class="px-6 py-5 border-b border-gray-200" style="margin-bottom: 10px;">
8 <div class="flex justify-between items-center">
9 <div class="flex items-center">
10 <div class="flex-shrink-0 bg-indigo-100 rounded-lg p-3">
11 <i class="fas fa-eye text-indigo-600 text-xl"></i>
12 </div>
13 <div class="ml-4">
14 <h2 class="text-lg font-medium text-gray-900"><?php esc_html_e('Quote Preview', 'easy-invoice'); ?></h2>
15 <p class="mt-1 text-sm text-gray-500"><?php esc_html_e('Live preview of your quote', 'easy-invoice'); ?></p>
16 </div>
17 </div>
18 <?php if($quote_id > 0 ){ ?>
19 <a href="<?php echo esc_url(get_permalink($quote_id)); ?>" target="_blank" class="inline-flex items-center px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
20 <i class="fas fa-external-link-alt mr-2"></i>
21 Full Preview
22 </a>
23 <?php } ?>
24 </div>
25 </div>
26
27 <?php
28 // Get the current template (default to 'standard')
29 $current_template = $quote ? $quote->getTemplate() : 'standard';
30 if (empty($current_template)) {
31 $current_template = 'standard';
32 }
33 $template_class = 'template-' . $current_template;
34
35 // Initialize formatter for the quote templates
36 $formatter = new \EasyInvoice\Helpers\QuoteFormatter($quote);
37 ?>
38
39 <div id="quote-container" class="quote-container quote-preview <?php echo esc_attr($template_class); ?>" style="position: relative;">
40 <?php
41 // Dynamically load the selected template from quote templates directory
42 // Dynamically load the selected template
43 $template_file = easy_invoice_design_template( 'quote', (string) $current_template );
44 if (file_exists($template_file)) {
45 include_once $template_file;
46 } else {
47 // Show template not found message
48 ?>
49 <div class="template-not-found">
50 <div class="template-not-found-icon">
51 <i class="fas fa-exclamation-circle"></i>
52 </div>
53 <h3><?php esc_html_e('Template Not Found', 'easy-invoice'); ?></h3>
54 <p>The selected template "<?php echo esc_html($current_template); ?>" does not exist.</p>
55 <p><?php esc_html_e('Please select a different template or contact support if you believe this is an error.', 'easy-invoice'); ?></p>
56 </div>
57 <style>
58 .template-not-found {
59 text-align: center;
60 padding: 40px;
61 background: #fff;
62 border-radius: 8px;
63 box-shadow: 0 2px 4px rgba(0,0,0,0.1);
64 }
65 .template-not-found-icon {
66 font-size: 48px;
67 color: #dc3545;
68 margin-bottom: 20px;
69 }
70 .template-not-found h3 {
71 font-size: 24px;
72 color: #32325d;
73 margin-bottom: 10px;
74 }
75 .template-not-found p {
76 color: #8898aa;
77 margin-bottom: 10px;
78 }
79 </style>
80 <?php
81 }
82 ?>
83 </div>
84 </div>
85
86 <style>
87 /* Loading state styles */
88 .loading-overlay {
89 position: absolute;
90 top: 0;
91 left: 0;
92 right: 0;
93 bottom: 0;
94 background: rgba(255, 255, 255, 0.9);
95 display: flex;
96 justify-content: center;
97 align-items: center;
98 z-index: 1000;
99 }
100
101 .loading-spinner {
102 text-align: center;
103 }
104
105 .quote-container.loading .loading-overlay {
106 display: flex;
107 }
108
109 /* (Resize logic removed per request) */
110 </style>
111
112 <script>
113 jQuery(document).ready(function($) {
114 // Localize easyInvoice object for this page
115 // Localize easyInvoice object for this page
116 window.easyInvoiceQ = window.easyInvoice || {};
117 window.easyInvoice.isPro = <?php echo easy_invoice_has_pro() ? 'true' : 'false'; ?>;
118 window.easyInvoice.ajaxUrl = '<?php echo esc_url(admin_url('admin-ajax.php')); ?>';
119 window.easyInvoice.nonce = '<?php echo esc_attr(wp_create_nonce('easy_invoice_nonce')); ?>';
120
121 // Function to update the live preview using AJAX
122 function updateLivePreview(templateId) {
123 $('#quote-container').addClass('loading');
124 $.ajax({
125 url: window.easyInvoice.ajaxUrl,
126 type: 'POST',
127 data: {
128 action: 'easy_invoice_load_quote_template',
129 template: templateId,
130 form_data: jQuery('#quote-form').length ? jQuery('#quote-form').serialize() : '',
131 quote_id: <?php echo (int) ($quote ? $quote->getId() : 0); ?>,
132 nonce: window.easyInvoice.nonce
133 },
134 success: function(response) {
135 if (response.success) {
136 $('#quote-container').html(response.data.html);
137 } else {
138 $('#quote-container').html('<div class="error">Failed to load template: ' + response.data.message + '</div>');
139 }
140 $('#quote-container').removeClass('loading');
141 },
142 error: function(xhr, status, error) {
143 $('#quote-container').html('<div class="error"><?php esc_html_e('Failed to load template. Please try again.', 'easy-invoice'); ?></div>');
144 $('#quote-container').removeClass('loading');
145 }
146 });
147 }
148
149 // Listen for template changes
150 $('.template-card').on('click', function(e) {
151 const templateId = $(this).data('template-id');
152
153 // Check if this is a premium template in free version
154 const isPremium = $(this).attr('data-is-premium') === 'true';
155 const isFreeVersion = !window.easyInvoice || !window.easyInvoice.isPro;
156
157 if (isPremium && isFreeVersion) {
158 // Show premium upgrade modal instead of selecting the template
159 if (typeof EasyInvoiceConfirmation !== 'undefined' && EasyInvoiceConfirmation.showFeatureUpgrade) {
160 EasyInvoiceConfirmation.showFeatureUpgrade('<?php echo esc_js(__('Premium Templates', 'easy-invoice')); ?>', '<?php echo esc_js(__('Access all premium templates including Modern, Professional, Classic, and more to give your quotes a unique and professional look.', 'easy-invoice')); ?>');
161 } else {
162 alert('<?php echo esc_js(__('This is a premium feature. Please upgrade to Pro to access all templates.', 'easy-invoice')); ?>');
163 }
164 return;
165 }
166
167 updateLivePreview(templateId);
168 });
169
170
171
172
173
174 // Live means live: re-render as the builder changes, not only when the
175 // template changes. Debounced so typing a description does not fire a
176 // request per keystroke.
177 (function () {
178 var $form = $('#quote-form'); if (!$form.length) { return; }
179 var timer = null;
180 var current = function () { return $form.find('input[name="quote_template"]').val() || $('.template-card.selected, .template-card.active').first().data('template-id') || 'standard'; };
181 var schedule = function () { clearTimeout(timer); timer = setTimeout(function () { updateLivePreview(current()); }, 700); };
182 $form.on('input change', 'input, textarea, select', schedule);
183 $(document).on('click', '.add-item-button, .remove-item, .client-option, #remove-selected-client, .template-card', schedule);
184 $(document).on('easy_invoice_items_changed easy_invoice_client_changed', schedule);
185 })();
186
187 });
188 </script>
189
190 <script>
191 // Scale the A4 design to the preview pane instead of letting it reflow: the
192 // preview then shows the sheet the client will see, only smaller.
193 (function () {
194 var box = document.getElementById('quote-container');
195 if (!box || !window.ResizeObserver) { return; }
196 var SHEET = 794;
197 function fit() {
198 var sheet = box.querySelector('.template, [class*="template-"]');
199 if (!sheet) { box.style.height = ''; return; }
200 var avail = box.clientWidth;
201 if (avail <= 0) { return; }
202 var k = Math.min(1, avail / SHEET);
203 sheet.style.width = SHEET + 'px';
204 sheet.style.maxWidth = 'none';
205 sheet.style.transformOrigin = 'top left';
206 sheet.style.transform = k < 1 ? 'scale(' + k + ')' : '';
207 box.style.overflow = 'hidden';
208 box.style.height = k < 1 ? Math.ceil(sheet.offsetHeight * k) + 'px' : '';
209 }
210 new ResizeObserver(fit).observe(box);
211 new MutationObserver(fit).observe(box, { childList: true, subtree: true });
212 fit();
213 })();
214 </script>
215