PluginProbe
Easy Invoice – Invoice Generator, PDF Quotes & Payments / 2.3.3
Easy Invoice – Invoice Generator, PDF Quotes & Payments v2.3.3
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 / assets / js / confirmation-modal.js

confirmation-modal.js in Easy Invoice – Invoice Generator, PDF Quotes & Payments 2.3.3, at assets/js/confirmation-modal.js

525 lines 28.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Generic Confirmation Modal
3 *
4 * A reusable confirmation modal that can be used across all EasyInvoice pages.
5 *
6 * @package EasyInvoice
7 * @since 1.0.0
8 *
9 * USAGE EXAMPLES:
10 *
11 * 1. Regular confirmation dialog:
12 * EasyInvoiceConfirmation.show({
13 * title: 'Delete Item',
14 * message: 'Are you sure you want to delete this item?',
15 * confirmText: 'Delete',
16 * confirmClass: 'bg-red-600 hover:bg-red-700',
17 * onConfirm: function() { // delete logic }
18 * });
19 *
20 * 2. Quick confirmation for common actions:
21 * EasyInvoiceConfirmation.confirmAction('delete', 'invoice INV-001', function() {
22 * // delete logic
23 * });
24 *
25 * 3. Generic upgrade dialog for premium features:
26 * EasyInvoiceConfirmation.showFeatureUpgrade('Quote Duplication');
27 *
28 * 4. Custom upgrade dialog:
29 * EasyInvoiceConfirmation.showUpgradeDialog({
30 * featureName: 'Custom Feature',
31 * description: 'Custom description of the feature benefits',
32 * onUpgrade: function() { window.open('https://upgrade-url.com', '_blank'); },
33 * onCancel: function() { }
34 * });
35 *
36 * AVAILABLE PREMIUM FEATURES:
37 * - Quote Duplication
38 * - Advanced Reporting
39 * - Custom Branding
40 * - Bulk Operations
41 * - Email Templates
42 * - Payment Integration
43 * - Client Portal
44 * - Recurring Invoices
45 */
46
47 (function($) {
48 'use strict';
49
50 // Create the modal HTML if it doesn't exist
51 if ($('#easy-invoice-confirmation-modal').length === 0) {
52 const modalHTML = `
53 <div id="easy-invoice-confirmation-modal" class="fixed z-50 inset-0 overflow-y-auto hidden">
54 <div class="flex items-center justify-center min-h-screen px-4">
55 <div class="fixed inset-0 transition-opacity" aria-hidden="true">
56 <div class="absolute inset-0 bg-gray-500 opacity-75"></div>
57 </div>
58 <div class="bg-white rounded-lg overflow-hidden shadow-xl transform transition-all sm:max-w-lg w-full z-50">
59 <div class="px-6 py-6">
60 <div class="flex items-center mb-4">
61 <div class="flex-shrink-0">
62 <svg class="h-6 w-6 text-red-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
63 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z" />
64 </svg>
65 </div>
66 <div class="ml-3">
67 <h3 class="text-lg font-medium text-gray-900" id="confirmation-title">Confirm Action</h3>
68 </div>
69 </div>
70 <div class="mt-2">
71 <p class="text-sm text-gray-500" id="confirmation-message">Are you sure you want to perform this action?</p>
72 </div>
73 <div class="mt-6 flex justify-end space-x-3">
74 <button type="button" id="confirmation-cancel" class="px-4 py-2 bg-gray-200 text-gray-700 rounded-md hover:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-gray-500">
75 Cancel
76 </button>
77 <button type="button" id="confirmation-confirm" class="px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500">
78 Confirm
79 </button>
80 </div>
81 </div>
82 </div>
83 </div>
84 </div>
85 `;
86 $('body').append(modalHTML);
87 }
88
89 // Global confirmation modal object
90 window.EasyInvoiceConfirmation = {
91 /**
92 * Show confirmation modal
93 *
94 * @param {Object} options Configuration options
95 * @param {string} options.title Modal title
96 * @param {string} options.message Modal message
97 * @param {string} options.confirmText Confirm button text (default: "Confirm")
98 * @param {string} options.cancelText Cancel button text (default: "Cancel")
99 * @param {string} options.confirmClass CSS class for confirm button (default: "bg-red-600 hover:bg-red-700")
100 * @param {Function} options.onConfirm Callback function when confirmed
101 * @param {Function} options.onCancel Callback function when cancelled
102 */
103 show: function(options) {
104 const defaults = {
105 title: 'Confirm Action',
106 message: 'Are you sure you want to perform this action?',
107 confirmText: 'Confirm',
108 cancelText: 'Cancel',
109 confirmClass: 'bg-red-600 hover:bg-red-700',
110 onConfirm: function() {},
111 onCancel: function() {}
112 };
113
114 const config = $.extend({}, defaults, options);
115
116 // Update modal content
117 $('#confirmation-title').text(config.title);
118 $('#confirmation-message').text(config.message);
119 $('#confirmation-confirm').text(config.confirmText);
120 $('#confirmation-cancel').text(config.cancelText);
121
122 // Update confirm button styling
123 var btnClass = config.confirmClass && config.confirmClass.trim() !== ''
124 ? config.confirmClass
125 : 'bg-red-600 hover:bg-red-700';
126 $('#confirmation-confirm')
127 .removeClass()
128 .addClass('px-4 py-2 rounded-md focus:outline-none focus:ring-2 focus:ring-red-500 ' + btnClass);
129
130 // Store callbacks
131 $('#easy-invoice-confirmation-modal').data('onConfirm', config.onConfirm);
132 $('#easy-invoice-confirmation-modal').data('onCancel', config.onCancel);
133
134 // Show modal
135 $('#easy-invoice-confirmation-modal').removeClass('hidden');
136 },
137
138 /**
139 * Show upgrade to pro modal - Special encouraging dialog
140 *
141 * @param {Object} options Configuration options
142 * @param {string} options.featureName Name of the premium feature (e.g., "Quote Duplication")
143 * @param {string} options.description Custom description (optional)
144 * @param {Function} options.onUpgrade Callback function when user clicks upgrade
145 * @param {Function} options.onCancel Callback function when user cancels
146 */
147 showUpgradeDialog: function(options) {
148 const defaults = {
149 featureName: 'Premium Feature',
150 description: '',
151 onUpgrade: function() {
152 // Default upgrade action - redirect to upgrade page
153 window.open('https://matrixaddons.com/plugins/easy-invoice/#pricing', '_blank');
154 },
155 onCancel: function() {}
156 };
157
158 const config = $.extend({}, defaults, options);
159
160 // Create upgrade modal HTML if it doesn't exist
161 if ($('#easy-invoice-upgrade-modal').length === 0) {
162 const upgradeModalHTML = `
163 <div id="easy-invoice-upgrade-modal" class="fixed z-50 inset-0 overflow-y-auto hidden">
164 <div class="flex items-center justify-center min-h-screen px-4">
165 <div class="fixed inset-0 transition-opacity" aria-hidden="true">
166 <div class="absolute inset-0 bg-gray-500 opacity-75"></div>
167 </div>
168 <div class="bg-gradient-to-br from-indigo-50 to-purple-50 rounded-lg overflow-hidden shadow-xl transform transition-all sm:max-w-lg w-full z-50 border border-indigo-200 relative">
169 <button type="button" id="upgrade-close" class="absolute top-4 right-4 text-gray-400 hover:text-gray-600 focus:outline-none" aria-label="Close">
170 <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
171 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
172 </svg>
173 </button>
174 <div class="px-6 py-6">
175 <!-- Header with premium icon -->
176 <div class="flex items-center justify-center mb-4">
177 <div class="flex-shrink-0">
178 <div class="w-16 h-16 bg-purple-600 rounded-full flex items-center justify-center">
179 <svg class="w-8 h-8 text-white" fill="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
180 <path d="M12 8L15 13.2L18 10.5L17.3 14H6.7L6 10.5L9 13.2L12 8M12 4L8.5 10L3 5L5 16H19L21 5L15.5 10L12 4Z"/>
181 </svg>
182 </div>
183 </div>
184 </div>
185
186 <!-- Title -->
187 <div class="text-center mb-4">
188 <h3 class="text-xl font-bold text-gray-900" id="upgrade-title">Unlock Premium Features</h3>
189 <p class="text-sm text-indigo-600 font-medium mt-1" id="upgrade-feature">${config.featureName}</p>
190 </div>
191
192 <!-- Description -->
193 <div class="text-center mb-6">
194 <p class="text-sm text-gray-600" id="upgrade-description">
195 ${config.description || `Upgrade to Easy Invoice Pro to unlock ${config.featureName} and many other premium features that will help you manage your business more efficiently.`}
196 </p>
197 </div>
198
199 <!-- Benefits list -->
200 <div class="bg-white rounded-lg p-4 mb-6 border border-indigo-100">
201 <h4 class="text-sm font-semibold text-gray-900 mb-3">Why teams upgrade to Pro</h4>
202 <div class="grid grid-cols-1 sm:grid-cols-2 gap-2 text-sm text-gray-700">
203 <div class="flex items-start">
204 <svg class="w-4 h-4 text-green-500 mr-2 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
205 <span>Advanced reporting & analytics</span>
206 </div>
207 <div class="flex items-start">
208 <svg class="w-4 h-4 text-green-500 mr-2 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
209 <span>Client Portal with secure online payments</span>
210 </div>
211 <div class="flex items-start">
212 <svg class="w-4 h-4 text-green-500 mr-2 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
213 <span>Partial payments & deposits</span>
214 </div>
215 <div class="flex items-start">
216 <svg class="w-4 h-4 text-green-500 mr-2 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
217 <span>Recurring invoices & subscriptions</span>
218 </div>
219 <div class="flex items-start">
220 <svg class="w-4 h-4 text-green-500 mr-2 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
221 <span>Payment gateways: Stripe, Square, Mollie, Bank Transfer</span>
222 </div>
223 <div class="flex items-start">
224 <svg class="w-4 h-4 text-green-500 mr-2 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
225 <span>Smart reminders & automated emails</span>
226 </div>
227 <div class="flex items-start">
228 <svg class="w-4 h-4 text-green-500 mr-2 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
229 <span>Custom branding, premium templates & PDF watermarking</span>
230 </div>
231 <div class="flex items-start">
232 <svg class="w-4 h-4 text-green-500 mr-2 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
233 <span>Unlimited quotes & invoices</span>
234 </div>
235 <div class="flex items-start">
236 <svg class="w-4 h-4 text-green-500 mr-2 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
237 <span>CSV export & integrations-ready</span>
238 </div>
239 <div class="flex items-start">
240 <svg class="w-4 h-4 text-green-500 mr-2 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
241 <span>Priority support & automatic updates</span>
242 </div>
243 </div>
244 <!-- Trust badges -->
245 <div class="mt-4 flex flex-wrap items-center justify-center gap-3 text-xs text-gray-500">
246 <span class="inline-flex items-center px-2 py-1 bg-gray-100 rounded">No coding required</span>
247 <span class="inline-flex items-center px-2 py-1 bg-gray-100 rounded">Cancel anytime</span>
248 <span class="inline-flex items-center px-2 py-1 bg-gray-100 rounded">Fast, friendly support</span>
249 </div>
250 </div>
251
252 <!-- Action button -->
253 <div class="flex flex-col space-y-3">
254 <button type="button" id="upgrade-confirm" class="w-full px-4 py-3 bg-purple-600 text-white rounded-md hover:bg-purple-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-purple-500 font-medium transition-all duration-200 transform hover:scale-105">
255 <svg class="w-4 h-4 inline mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
256 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6"></path>
257 </svg>
258 Upgrade to Pro
259 </button>
260 <p class="text-[11px] text-gray-500 text-center">You can activate your license instantly after purchase.</p>
261 </div>
262 </div>
263 </div>
264 </div>
265 </div>
266 `;
267
268 $('body').append(upgradeModalHTML);
269
270 // Event handlers for upgrade modal
271 $(document).on('click', '#upgrade-confirm', function() {
272 const modal = $('#easy-invoice-upgrade-modal');
273 const onUpgrade = modal.data('onUpgrade');
274
275 if (typeof onUpgrade === 'function') {
276 onUpgrade();
277 }
278
279 EasyInvoiceConfirmation.hideUpgradeDialog();
280 });
281
282 // Close button handler
283 $(document).on('click', '#upgrade-close', function() {
284 const modal = $('#easy-invoice-upgrade-modal');
285 const onCancel = modal.data('onCancel');
286 if (typeof onCancel === 'function') {
287 onCancel();
288 }
289 EasyInvoiceConfirmation.hideUpgradeDialog();
290 });
291
292 // Close modal on backdrop click
293 $(document).on('click', '#easy-invoice-upgrade-modal', function(e) {
294 if (e.target === this) {
295 EasyInvoiceConfirmation.hideUpgradeDialog();
296 }
297 });
298
299 // Close modal on escape key
300 $(document).on('keydown', function(e) {
301 if (e.key === 'Escape' && !$('#easy-invoice-upgrade-modal').hasClass('hidden')) {
302 EasyInvoiceConfirmation.hideUpgradeDialog();
303 }
304 });
305 }
306
307 // Update modal content
308 $('#upgrade-feature').text(config.featureName);
309 $('#upgrade-description').html(config.description || `Upgrade to Easy Invoice Pro to unlock ${config.featureName} and many other premium features that will help you manage your business more efficiently.`);
310
311 // Store callbacks
312 $('#easy-invoice-upgrade-modal').data('onUpgrade', config.onUpgrade);
313 $('#easy-invoice-upgrade-modal').data('onCancel', config.onCancel);
314
315 // Show modal
316 $('#easy-invoice-upgrade-modal').removeClass('hidden');
317 },
318
319 /**
320 * Quick upgrade dialog for common premium features
321 *
322 * @param {string} featureName Name of the premium feature
323 * @param {string} customDescription Custom description (optional)
324 * @param {string} upgradeUrl Custom upgrade URL (optional)
325 */
326 showFeatureUpgrade: function(featureName, customDescription, upgradeUrl) {
327 const featureConfigs = {
328 'Quote Duplication': {
329 description: 'Create copies of your quotes instantly to save time and maintain consistency across similar projects. Perfect for recurring clients and template-based work.',
330 icon: 'copy'
331 },
332 'Invoice Duplication': {
333 description: 'Create copies of your invoices instantly to save time and maintain consistency across similar projects. Perfect for recurring clients and template-based work.',
334 icon: 'copy'
335 },
336 'Advanced Reporting': {
337 description: 'Get detailed insights into your business performance with advanced analytics, charts, and customizable reports to make data-driven decisions.',
338 icon: 'chart'
339 },
340 'Custom Branding': {
341 description: 'Add your company logo, colors, and branding to all your quotes and invoices for a professional, branded appearance.',
342 icon: 'paint'
343 },
344 'Bulk Operations': {
345 description: 'Perform actions on multiple quotes or invoices at once to save time and streamline your workflow.',
346 icon: 'bulk'
347 },
348 'Email Templates': {
349 description: 'Create and customize professional email templates for sending quotes and invoices to clients.',
350 icon: 'email'
351 },
352 'Payment Integration': {
353 description: 'Accept online payments directly through your quotes and invoices with popular payment gateways.',
354 icon: 'payment'
355 },
356 'Client Portal': {
357 description: 'Give your clients access to view and manage their quotes and invoices through a secure client portal.',
358 icon: 'portal'
359 },
360 'Recurring Invoices': {
361 description: 'Automate your billing with recurring invoices that are sent automatically on your schedule.',
362 icon: 'recurring'
363 }
364 };
365
366 const config = featureConfigs[featureName] || {
367 description: customDescription || `Upgrade to Easy Invoice Pro to unlock ${featureName} and many other premium features.`,
368 icon: 'star'
369 };
370
371 this.showUpgradeDialog({
372 featureName: featureName,
373 description: config.description,
374 onUpgrade: function() {
375 // Redirect to upgrade page
376 window.open(upgradeUrl || 'https://matrixaddons.com/plugins/easy-invoice/#pricing', '_blank');
377 },
378 onCancel: function() {
379 // User chose to skip for now
380 }
381 });
382 },
383
384 /**
385 * Hide upgrade dialog
386 */
387 hideUpgradeDialog: function() {
388 $('#easy-invoice-upgrade-modal').addClass('hidden');
389 },
390
391 /**
392 * Hide confirmation modal
393 */
394 hide: function() {
395 $('#easy-invoice-confirmation-modal').addClass('hidden');
396 },
397
398 /**
399 * Send invoice or quote by email — uses easyInvoice.i18n when available.
400 *
401 * @param {'invoice'|'quote'} kind Document type
402 * @param {Function} onConfirm Called when user confirms
403 */
404 confirmSendDocument: function(kind, onConfirm) {
405 var i18n = (window.easyInvoice && window.easyInvoice.i18n) ? window.easyInvoice.i18n : {};
406 var isQuote = kind === 'quote';
407 var title = isQuote
408 ? (i18n.confirm_send_quote_title || 'Send quote by email')
409 : (i18n.confirm_send_invoice_title || 'Send invoice by email');
410 var message = isQuote
411 ? (i18n.confirm_send_quote_message || 'The quote will be emailed to the client using your template.')
412 : (i18n.confirm_send_invoice_message || 'The invoice will be emailed to the client using your template.');
413 var confirmText = i18n.confirm_send_confirm || i18n.send_invoice || 'Send';
414 var cancelText = i18n.confirm_cancel || i18n.cancel || 'Cancel';
415
416 this.show({
417 title: title,
418 message: message,
419 confirmText: confirmText,
420 cancelText: cancelText,
421 confirmClass: 'bg-indigo-600 hover:bg-indigo-700',
422 onConfirm: typeof onConfirm === 'function' ? onConfirm : function() {}
423 });
424 },
425
426 /**
427 * Quick confirmation for common actions
428 *
429 * @param {string} action Action type (delete, trash, draft, etc.)
430 * @param {string} itemName Name of the item being acted upon
431 * @param {Function} onConfirm Callback function when confirmed
432 */
433 confirmAction: function(action, itemName, onConfirm) {
434 const actionConfigs = {
435 'delete': {
436 title: 'Delete Permanently',
437 message: `Are you sure you want to permanently delete ${itemName}? This action cannot be undone.`,
438 confirmText: 'Delete Permanently',
439 confirmClass: 'bg-red-600 hover:bg-red-700'
440 },
441 'trash': {
442 title: 'Move to Trash',
443 message: `Are you sure you want to move ${itemName} to trash?`,
444 confirmText: 'Move to Trash',
445 confirmClass: 'bg-orange-600 hover:bg-orange-700'
446 },
447 'draft': {
448 title: 'Move to Draft',
449 message: `Are you sure you want to move ${itemName} to draft?`,
450 confirmText: 'Move to Draft',
451 confirmClass: 'bg-gray-600 hover:bg-gray-700'
452 },
453 'publish': {
454 title: 'Publish',
455 message: `Are you sure you want to publish ${itemName}?`,
456 confirmText: 'Publish',
457 confirmClass: 'bg-green-600 hover:bg-green-700'
458 },
459 'restore': {
460 title: 'Restore',
461 message: `Are you sure you want to restore ${itemName}?`,
462 confirmText: 'Restore',
463 confirmClass: 'bg-green-600 hover:bg-green-700'
464 }
465 };
466
467 const config = actionConfigs[action] || {
468 title: 'Confirm Action',
469 message: `Are you sure you want to ${action} ${itemName}?`,
470 confirmText: 'Confirm',
471 confirmClass: 'bg-red-600 hover:bg-red-700'
472 };
473
474 this.show({
475 title: config.title,
476 message: config.message,
477 confirmText: config.confirmText,
478 confirmClass: config.confirmClass,
479 onConfirm: onConfirm
480 });
481 }
482 };
483
484 // Event handlers
485 $(document).ready(function() {
486 // Confirm button click
487 $(document).on('click', '#confirmation-confirm', function() {
488 const modal = $('#easy-invoice-confirmation-modal');
489 const onConfirm = modal.data('onConfirm');
490
491 if (typeof onConfirm === 'function') {
492 onConfirm();
493 }
494
495 EasyInvoiceConfirmation.hide();
496 });
497
498 // Cancel button click
499 $(document).on('click', '#confirmation-cancel', function() {
500 const modal = $('#easy-invoice-confirmation-modal');
501 const onCancel = modal.data('onCancel');
502
503 if (typeof onCancel === 'function') {
504 onCancel();
505 }
506
507 EasyInvoiceConfirmation.hide();
508 });
509
510 // Close modal on backdrop click
511 $(document).on('click', '#easy-invoice-confirmation-modal', function(e) {
512 if (e.target === this) {
513 EasyInvoiceConfirmation.hide();
514 }
515 });
516
517 // Close modal on escape key
518 $(document).on('keydown', function(e) {
519 if (e.key === 'Escape' && !$('#easy-invoice-confirmation-modal').hasClass('hidden')) {
520 EasyInvoiceConfirmation.hide();
521 }
522 });
523 });
524
525 })(jQuery);