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

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

284 lines 14.6 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('Invoice Preview', 'easy-invoice'); ?></h2>
15 <p class="mt-1 text-sm text-gray-500"><?php esc_html_e('Live preview of your invoice', 'easy-invoice'); ?></p>
16 </div>
17 </div>
18 <?php if($invoice_id > 0 ){ ?>
19 <a href="<?php echo esc_url(get_permalink($invoice_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 = $invoice ? $invoice->getTemplate() : 'standard';
30 if (empty($current_template)) {
31 $current_template = 'standard';
32 }
33 $template_class = 'template-' . $current_template;
34
35 // Initialize formatter for the invoice templates
36 $formatter = new \EasyInvoice\Helpers\InvoiceFormatter($invoice);
37 ?>
38
39 <div id="invoice-container" class="invoice-container">
40 <?php
41 // Add custom template builder CSS if using a custom template
42 if ($invoice && method_exists($invoice, 'getId')) {
43 $template_id = get_post_meta($invoice->getId(), '_easy_invoice_invoice_template', true);
44 if ($template_id && class_exists('\EasyInvoicePro\TemplateParser') && class_exists('\EasyInvoicePro\Addons\CustomTemplates\Controllers\TemplateBuilderController')) {
45 $templateData = \EasyInvoicePro\TemplateParser::parseTemplateFromDatabase($template_id);
46 if ($templateData && isset($templateData['elements'])) {
47 echo '<style>';
48 // Canvas settings
49 $canvas = $templateData['canvas'] ?? [];
50 $canvasWidth = $canvas['width'] ?? 794;
51 $canvasHeight = $canvas['height'] ?? 1123;
52 $canvasDesignCSS = \EasyInvoicePro\Addons\CustomTemplates\Controllers\TemplateBuilderController::generateCanvasCSS($templateData);
53
54 echo "#canvas { position: relative; width: " . floatval($canvasWidth) . "px; height: " . floatval($canvasHeight) . "px; margin: 0; overflow: visible; ";
55 if ($canvasDesignCSS) {
56 echo wp_strip_all_tags(str_replace('!important;', ';', $canvasDesignCSS)); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- CSS inside a <style> element; tags stripped, entities are not decoded there.
57 }
58 echo " }\n";
59
60 // Element styles
61 foreach ($templateData['elements'] as $element) {
62 $elementId = $element['id'] ?? '';
63 if (!$elementId) continue;
64
65 echo '#' . esc_attr($elementId) . ' { position: absolute; ';
66 if (isset($element['position']['left'])) echo "left: " . floatval($element['position']['left']) . "px; ";
67 if (isset($element['position']['top'])) echo "top: " . floatval($element['position']['top']) . "px; ";
68 if (isset($element['dimensions']['width'])) echo "width: " . floatval($element['dimensions']['width']) . "px; ";
69 if (isset($element['dimensions']['height'])) echo "min-height: " . floatval($element['dimensions']['height']) . "px; ";
70
71 if (isset($element['styles']) && is_array($element['styles'])) {
72 foreach ($element['styles'] as $property => $value) {
73 if ($value !== '' && !in_array($property, ['position', 'dimensions'])) {
74 echo esc_attr($property) . ": " . esc_attr($value) . "; ";
75 }
76 }
77 }
78 echo "}\n";
79 }
80 echo '</style>';
81 }
82 }
83 }
84
85 // Dynamically load the selected template
86 $template_file = easy_invoice_design_template( 'invoice', (string) $current_template );
87 if (file_exists($template_file)) {
88 include_once $template_file;
89 } else {
90 // Show template not found message
91 ?>
92 <div class="template-not-found">
93 <div class="template-not-found-icon">
94 <i class="fas fa-exclamation-circle"></i>
95 </div>
96 <h3><?php esc_html_e('Template Not Found', 'easy-invoice'); ?></h3>
97 <p>The selected template "<?php echo esc_html($current_template); ?>" does not exist.</p>
98 <p><?php esc_html_e('Please select a different template or contact support if you believe this is an error.', 'easy-invoice'); ?></p>
99 </div>
100 <style>
101 .template-not-found {
102 text-align: center;
103 padding: 40px;
104 background: #fff;
105 border-radius: 8px;
106 box-shadow: 0 2px 4px rgba(0,0,0,0.1);
107 }
108 .template-not-found-icon {
109 font-size: 48px;
110 color: #dc3545;
111 margin-bottom: 20px;
112 }
113 .template-not-found h3 {
114 font-size: 24px;
115 color: #32325d;
116 margin-bottom: 10px;
117 }
118 .template-not-found p {
119 color: #8898aa;
120 margin-bottom: 10px;
121 }
122 </style>
123 <?php
124 }
125 ?>
126 </div>
127 </div>
128
129 <style>
130 /* Loading state styles */
131 .loading-overlay {
132 position: absolute;
133 top: 0;
134 left: 0;
135 right: 0;
136 bottom: 0;
137 background: rgba(255, 255, 255, 0.9);
138 display: flex;
139 justify-content: center;
140 align-items: center;
141 z-index: 1000;
142 }
143
144 .loading-spinner {
145 text-align: center;
146 }
147
148 .invoice-container.loading .loading-overlay {
149 display: flex;
150 }
151
152 /* (Resize logic removed per request) */
153 </style>
154
155 <script>
156 // Localize easyInvoice object for this page
157 window.easyInvoice = window.easyInvoice || {};
158 window.easyInvoice.isPro = <?php echo easy_invoice_has_pro() ? 'true' : 'false'; ?>;
159 window.easyInvoice.ajaxUrl = '<?php echo esc_url(admin_url('admin-ajax.php')); ?>';
160 window.easyInvoice.nonce = '<?php echo esc_attr(wp_create_nonce('easy_invoice_nonce')); ?>';
161
162 jQuery(document).ready(function($) {
163 // Function to update the live preview
164 function updateLivePreview(templateId) {
165 // Show loading state
166 $('#invoice-container').addClass('loading');
167
168 // Make AJAX call to load the template
169 $.ajax({
170 url: window.easyInvoice.ajaxUrl,
171 type: 'POST',
172 data: {
173 action: 'easy_invoice_load_template',
174 template: templateId,
175 form_data: jQuery('#invoice-form').length ? jQuery('#invoice-form').serialize() : '',
176 invoice_id: '<?php echo esc_js($invoice_id); ?>',
177 nonce: window.easyInvoice.nonce
178 },
179 success: function(response) {
180 if (response.success) {
181 // Update the preview content
182 $('#invoice-container').html(response.data.html);
183 } else {
184 // Show error message
185 $('#invoice-container').html(`
186 <div class="template-not-found">
187 <div class="template-not-found-icon">
188 <i class="fas fa-exclamation-circle"></i>
189 </div>
190 <h3><?php esc_html_e('Template Not Found', 'easy-invoice'); ?></h3>
191 <p>The selected template "${templateId}" does not exist.</p>
192 <p><?php esc_html_e('Please select a different template or contact support if you believe this is an error.', 'easy-invoice'); ?></p>
193 </div>
194 `);
195 }
196 },
197 error: function(xhr, status, error) {
198 // Show error message
199 $('#invoice-container').html(`
200 <div class="template-not-found">
201 <div class="template-not-found-icon">
202 <i class="fas fa-exclamation-circle"></i>
203 </div>
204 <h3><?php esc_html_e('Error Loading Template', 'easy-invoice'); ?></h3>
205 <p><?php esc_html_e('There was an error loading the template. Please try again.', 'easy-invoice'); ?></p>
206 </div>
207 `);
208 },
209 complete: function() {
210 // Remove loading state
211 $('#invoice-container').removeClass('loading');
212 }
213 });
214 }
215
216 // Listen for template changes from the template cards
217 $('.template-card').on('click', function(e) {
218 const templateId = $(this).data('template-id');
219
220 // Check if this is a premium template in free version
221 const isPremium = $(this).attr('data-is-premium') === 'true';
222 const isFreeVersion = !window.easyInvoice || !window.easyInvoice.isPro;
223 if (isPremium && isFreeVersion) {
224 // Show premium upgrade modal instead of selecting the template
225 if (typeof EasyInvoiceConfirmation !== 'undefined' && EasyInvoiceConfirmation.showFeatureUpgrade) {
226 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 invoices a unique and professional look.', 'easy-invoice')); ?>');
227 } else {
228 alert('<?php echo esc_js(__('This is a premium feature. Please upgrade to Pro to access all templates.', 'easy-invoice')); ?>');
229 }
230 return;
231 }
232
233 updateLivePreview(templateId);
234 });
235
236 // Listen for template changes from the gallery
237 $('.gallery-template-card').on('click', function() {
238 const templateId = $(this).data('template-id');
239 updateLivePreview(templateId);
240 });
241
242
243 // Live means live: re-render as the builder changes, not only when the
244 // template changes. Debounced so typing a description does not fire a
245 // request per keystroke.
246 (function () {
247 var $form = $('#invoice-form'); if (!$form.length) { return; }
248 var timer = null;
249 var current = function () { return $form.find('input[name="invoice_template"]').val() || $('.template-card.selected, .template-card.active').first().data('template-id') || 'standard'; };
250 var schedule = function () { clearTimeout(timer); timer = setTimeout(function () { updateLivePreview(current()); }, 700); };
251 $form.on('input change', 'input, textarea, select', schedule);
252 $(document).on('click', '.add-item-button, .remove-item, .client-option, #remove-selected-client, .template-card', schedule);
253 $(document).on('easy_invoice_items_changed easy_invoice_client_changed', schedule);
254 })();
255
256 });
257 </script>
258
259 <script>
260 // Scale the A4 design to the preview pane instead of letting it reflow: the
261 // preview then shows the sheet the client will see, only smaller.
262 (function () {
263 var box = document.getElementById('invoice-container');
264 if (!box || !window.ResizeObserver) { return; }
265 var SHEET = 794;
266 function fit() {
267 var sheet = box.querySelector('.template, [class*="template-"]');
268 if (!sheet) { box.style.height = ''; return; }
269 var avail = box.clientWidth;
270 if (avail <= 0) { return; }
271 var k = Math.min(1, avail / SHEET);
272 sheet.style.width = SHEET + 'px';
273 sheet.style.maxWidth = 'none';
274 sheet.style.transformOrigin = 'top left';
275 sheet.style.transform = k < 1 ? 'scale(' + k + ')' : '';
276 box.style.overflow = 'hidden';
277 box.style.height = k < 1 ? Math.ceil(sheet.offsetHeight * k) + 'px' : '';
278 }
279 new ResizeObserver(fit).observe(box);
280 new MutationObserver(fit).observe(box, { childList: true, subtree: true });
281 fit();
282 })();
283 </script>
284