PluginProbe
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF / 1.10
Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF v1.10
2.3.4 2.3.3 2.3.2 2.3.1 2.3.0 2.2.9 2.2.8 trunk 1.10 1.3.3 1.3.4 1.3.5 1.3.5.1 1.3.5.2 1.3.6 1.3.6.1 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.5 All 103 releases
imagify / assets / js / pricing-modal.js

pricing-modal.js in Imagify Image Optimization: Optimize Images | Compress & Convert to WebP/AVIF 1.10, at assets/js/pricing-modal.js

1,329 lines 41.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 // Imagify tabs ====================================================================================
2 (function ($, d, w, undefined) { // eslint-disable-line no-unused-vars, no-shadow, no-shadow-restricted-names
3
4 /**
5 * @Markup:
6 * ul.imagify-tabs
7 * li.imagify-tab.imagify-current
8 * a[href="#target"]
9 * div.imagify-tabs-contents
10 * div.imagify-tab-content#target
11 */
12 $(d).on('click.imagify', '.imagify-tab', function (e) {
13 var $_this = $(this),
14 curr_class = 'imagify-current',
15 target;
16
17 e.preventDefault();
18
19 if ($_this.hasClass('imagify-current')) {
20 return;
21 }
22
23 target = $_this.find('a').attr('href') || '#' + $_this.find('a').attr('aria-controls');
24
25 // Show right tab content.
26 $_this.closest('.imagify-tabs').next('.imagify-tabs-contents').find('.imagify-tab-content').hide().attr('aria-hidden', 'true');
27 $(target).fadeIn(275).attr('aria-hidden', 'false');
28
29 // Change active tabs.
30 $_this.closest('.imagify-tabs').find('.imagify-tab').removeClass(curr_class).attr('aria-selected', 'false');
31 $_this.addClass(curr_class).attr('aria-selected', 'true');
32 });
33
34 })(jQuery, document, window);
35
36
37 // Imagify payment modal ===========================================================================
38 (function ($, d, w, undefined) { // eslint-disable-line no-unused-vars, no-shadow, no-shadow-restricted-names
39
40 /**
41 * Payment Modal.
42 *
43 * @since 1.6
44 * @since 1.6.3 include discount campaign
45 * @author Geoffrey
46 */
47 var imagifyModal = {};
48
49 if (! $('#imagify-pricing-modal').length) {
50 return;
51 }
52
53 imagifyModal = {
54 $modal: $('#imagify-pricing-modal'),
55 $checkboxes: $('.imagify-offer-line .imagify-checkbox'),
56 $radios: $('.imagify-payment-modal .imagify-radio-line input'),
57 // Plans selection view & payment process view hidden by default.
58 $preView: $('#imagify-pre-checkout-view'),
59 $plansView: $('#imagify-plans-selection-view').hide(),
60 $paymentView: $('#imagify-payment-process-view').hide(),
61 $successView: $('#imagify-success-view').hide(),
62 $anotherBtn: $('.imagify-choose-another-plan'),
63 speedFadeIn: 300,
64
65 getHtmlPrice: function (content, period) {
66 var monthly, yearly, m, y, output;
67
68 if (! period) {
69 period = null;
70 }
71
72 if (typeof content !== 'object') {
73 content += ''; // Be sure content is a string.
74 content = content.split('.');
75 content[1] = content[1].length === 1 ? content[1] + '0' : ('' + content[1]).substring(0, 2);
76
77 output = '<span class="imagify-price-big">' + content[0] + '</span> ';
78 output += '<span class="imagify-price-mini">.' + content[1] + '</span>';
79
80 return output;
81 }
82
83 monthly = content.monthly + '';
84 yearly = content.yearly + '';
85 m = '0' === monthly ? ['0', '00'] : monthly.split('.');
86 y = '0' === yearly ? ['0', '00'] : yearly.split('.');
87 output = '<span class="imagify-switch-my">';
88 /* eslint-disable indent */
89 output += '<span aria-hidden="' + (period === 'monthly' ? 'false' : 'true') + '" class="imagify-monthly">';
90 output += '<span class="imagify-price-big">' + m[0] + '</span> ';
91 output += '<span class="imagify-price-mini">.' + (m[1].length === 1 ? m[1] + '0' : ('' + m[1]).substring(0, 2)) + '</span>';
92 output += '</span> ';
93 output += '<span aria-hidden="' + (period === 'yearly' ? 'false' : 'true') + '" class="imagify-yearly">';
94 output += '<span class="imagify-price-big">' + y[0] + '</span> ';
95 output += '<span class="imagify-price-mini">.' + (y[1].length === 1 ? y[1] + '0' : ('' + y[1]).substring(0, 2)) + '</span>';
96 output += '</span>';
97 /* eslint-enable indent */
98 output += '</span>';
99
100 return output;
101 },
102
103 getHtmlDiscountPrice: function (content, period) {
104 var monthly, yearly,
105 output = '';
106
107 if (! period) {
108 period = null;
109 }
110
111 if (typeof content === 'object') {
112 monthly = content.monthly + '';
113 yearly = content.yearly + '';
114
115 output += '<span class="imagify-price-discount">';
116 /* eslint-disable indent */
117 output += '<span class="imagify-price-discount-dollar">$</span>';
118 output += '<span class="imagify-switch-my">';
119 output += '<span aria-hidden="' + (period === 'monthly' ? 'false' : 'true') + '" class="imagify-monthly">';
120 output += '<span class="imagify-price-discount-number">' + monthly + '</span>';
121 output += '</span>';
122 output += '<span aria-hidden="' + (period === 'yearly' ? 'false' : 'true') + '" class="imagify-yearly">';
123 output += '<span class="imagify-price-discount-number">' + yearly + '</span>';
124 output += '</span>';
125 output += '</span>';
126 /* eslint-enable indent */
127 output += '</span>';
128 } else {
129 content += ''; // Be sure content is a string.
130 output += '<span class="imagify-price-discount">';
131 /* eslint-disable indent */
132 output += '<span class="imagify-price-discount-dollar">$</span>';
133 output += '<span class="imagify-price-discount-number">' + content + '</span>';
134 /* eslint-enable indent */
135 output += '</span>';
136 }
137
138 return output;
139 },
140
141 /**
142 * @uses imagifyModal.getHtmlPrice()
143 * @uses imagifyModal.getHtmlDiscountPrice()
144 */
145 populateOffer: function ($offer, datas, type, classes) {
146 var promo = w.imagify_discount_datas,
147 add = datas.additional_gb, // 4 (monthly)
148 ann = datas.annual_cost, // 49.9 (monthly)
149 id = datas.id, // 3 (monthly/onetime)
150 lab = datas.label, // 'lite' (monthly/onetime)
151 mon = datas.monthly_cost, // 4.99 (monthly)
152 quo = datas.quota, // 1000 (MB) - 5000 images (monthly/onetime)
153 cos = datas.cost, // 3.49 (onetime)
154 name = -1 === quo ? 'Unlimited' : (quo >= 1000 ? quo / 1000 + ' GB' : quo + ' MB'),
155 pcs = 'monthly' === type ? {monthly: mon, yearly: Math.round(ann / 12 * 100) / 100} : cos,
156 pcsd = pcs, // Used if discount is active.
157 percent, $datas_c, datas_content, applies_to = [];
158
159 applies_to = imagifyModal.getPromoAppliesTo(promo);
160
161
162 // Change pricing value only if discount in percentage is active and if offer is a monthly and not a onetime.
163 if (
164 promo.is_active
165 && 'percentage' === promo.coupon_type
166 && 'monthly' === type
167 && (0 < mon)
168 && (applies_to.includes(lab) || 'all' === applies_to[0])
169 ) {
170 percent = (100 - promo.coupon_value) / 100;
171 pcs = 'monthly' === type ? {
172 monthly: mon * percent,
173 yearly: Math.round((ann * percent) / 12 * 100) / 100
174 } : cos * percent;
175 }
176
177 if (typeof classes !== 'undefined') {
178 $offer.addClass('imagify-' + type + '-' + lab + classes);
179 }
180
181 // Name.
182 $offer.find('.imagify-offer-size').text(name);
183
184 // Main prices (pcs can be an object or a string).
185 $offer.find('.imagify-number-block').html(imagifyModal.getHtmlPrice(pcs, 'monthly'));
186
187 // discount prices
188 $offer.find('.imagify-price-block').prev('.imagify-price-discount').remove();
189 if (
190 promo.is_active
191 && 'percentage' === promo.coupon_type
192 && 'monthly' === type
193 && (0 < mon)
194 && (applies_to.includes(lab) || 'all' === applies_to[0])
195 ) {
196 $offer.find('.imagify-price-block').before(imagifyModal.getHtmlDiscountPrice(pcsd, 'monthly'));
197 }
198 // Nb images.
199 $offer.find('.imagify-approx-nb').text(quo * 5);
200
201 if ('monthly' === type) {
202 // Additionnal price.
203 $offer.find('.imagify-price-add-data').text('$' + add);
204 }
205
206 // Button data-offer attr.
207 $datas_c = $offer.find('.imagify-payment-btn-select-plan').length ? $offer.find('.imagify-payment-btn-select-plan') : $offer;
208
209 if ('monthly' === type) {
210 datas_content = '{"' + lab + '":{"id":' + id + ',"name":"' + name + '","label":"' + lab + '","data":' + quo + ',"dataf":"' + name + '","imgs":' + (quo * 5) + ',"prices":{"monthly":' + pcs.monthly + ',"yearly":' + pcs.yearly + ',"add":' + add + '}}}';
211 } else {
212 datas_content = '{"ot' + lab + '":{"id":' + id + ',"name":"' + name + '","label":"' + lab + '","data":' + quo + ',"dataf":"' + name + '","imgs":' + (quo * 5) + ',"price":' + pcs + '}}';
213 }
214
215 $datas_c.attr('data-offer', datas_content);
216
217 return $offer;
218 },
219
220 populatePayBtn: function () {
221 var $monthlyOffer = $('.imagify-offer-monthly'),
222 $onetimeOffer = $('.imagify-offer-onetime'),
223 pl_datas, ot_datas,
224 price = 0,
225 price_pl = 0,
226 price_ot = 0;
227
228 if ($monthlyOffer.length) {
229 pl_datas = JSON.parse($monthlyOffer.attr('data-offer'));
230 // Calculate price_pl only if that offer is selected.
231 if ($monthlyOffer.hasClass('imagify-offer-selected')) {
232 if ($('#imagify-subscription-monthly').filter(':checked').length) {
233 price_pl = pl_datas[Object.keys(pl_datas)[0]].prices.monthly;
234 } else {
235 price_pl = pl_datas[Object.keys(pl_datas)[0]].prices.yearly * 12;
236 }
237 }
238 }
239
240 if ($onetimeOffer.length) {
241 ot_datas = JSON.parse($onetimeOffer.attr('data-offer'));
242 // Calculate price_ot only if that offer is selected.
243 if ($onetimeOffer.hasClass('imagify-offer-selected')) {
244 price_ot = ot_datas[Object.keys(ot_datas)[0]].price;
245 }
246 }
247
248 // Calculate price.
249 price = parseFloat(price_ot + price_pl).toFixed(2);
250
251 // Edit button price.
252 //$( '.imagify-global-amount' ).text( price ); // Not used.
253
254 if ('0.00' === price || 0 === price) {
255 $('#imagify-modal-checkout-btn').prop('disabled', true).addClass('imagify-button-disabled');
256 } else {
257 $('#imagify-modal-checkout-btn').prop('disabled', false).removeClass('imagify-button-disabled');
258 }
259 },
260
261 checkCoupon: function () {
262 var code = $('#imagify-coupon-code').val(),
263 $cptext, $label, $section, nonce;
264
265 $cptext = $('.imagify-coupon-text');
266 $label = $cptext.find('label');
267 $section = $('.imagify-coupon-section');
268
269 if ('' === code) {
270 $section.removeClass('validated').removeClass('invalid');
271 $label.html(imagifyPricingModal.labels.defaultCouponLabel);
272 return;
273 }
274
275 nonce = $('#imagify-get-pricing-modal').data('nonce');
276
277 $cptext.addClass('checking');
278
279 // Get the true prices.
280 $.post(ajaxurl, {action: 'imagify_check_coupon', coupon: code, imagifynonce: nonce}, function (response) {
281 var coupon_value;
282
283 $cptext.removeClass('checking');
284
285 // Error during the request.
286 if (! response.success) {
287 $section.removeClass('validated').addClass('invalid');
288 $label.text(imagifyPricingModal.labels.errorCouponAPI);
289 } else if (response.data.success) {
290 coupon_value = 'percentage' === response.data.coupon_type ? response.data.value + '%' : '$' + response.data.value;
291 var $selected_plan_line = $('.imagify-pre-checkout-view .imagify-pre-checkout-offers .imagify-offer-line');
292 var offer_data = JSON.parse($selected_plan_line.attr('data-offer'));
293 var applies_to = imagifyModal.getPromoAppliesTo(response.data);
294 if ( applies_to.includes(offer_data[Object.keys(offer_data)[0]].label ) || "all" === applies_to[0] ){
295 $section.removeClass('invalid').addClass('validated');
296 $label.html(imagifyPricingModal.labels.successCouponAPI);
297 $label.find('.imagify-coupon-offer').text(coupon_value);
298 $label.find('.imagify-coupon-word').text(code);
299 } else {
300 $section.removeClass('validated').addClass('invalid');
301 $label.html(imagifyPricingModal.labels.errorCouponPlan);
302 $('#imagify-coupon-code').val('');
303
304 }
305 } else {
306 $section.removeClass('validated').addClass('invalid');
307 $label.text(response.data.detail);
308 }
309 });
310 },
311
312 /**
313 * @uses imagifyModal.populateOffer()
314 * @uses imagifyModal.populatePayBtn()
315 * @uses imagifyModal.checkCoupon()
316 */
317 getPricing: function ($button) {
318 var nonce = $button.data('nonce'),
319 prices_rq_datas = {
320 action: 'imagify_get_prices',
321 imagifynonce: nonce
322 },
323 imgs_rq_datas = {
324 action: 'imagify_get_images_counts',
325 imagifynonce: nonce
326 },
327 prices_rq_discount = {
328 action: 'imagify_get_discount',
329 imagifynonce: nonce
330 };
331
332 imagifyModal.$modal.find('.imagify-modal-loader').hide().show();
333 imagifyModal.$modal.addClass('imagify-modal-loading');
334
335 /**
336 * TODO: change the way to waterfall requests.
337 * Use setInterval + counter instead.
338 */
339
340 // Get the true prices.
341 $.post(ajaxurl, prices_rq_datas, function (prices_response) {
342
343 if (! prices_response.success) {
344 // TODO: replace modal content by any information.
345 // An error occurred.
346
347 // Populate Pay button.
348 imagifyModal.populatePayBtn();
349 return;
350 }
351
352 // get the image estimates sizes
353 $.post(ajaxurl, imgs_rq_datas, function (imgs_response) {
354
355 if (! imgs_response.success) {
356 // TODO: replace modal content by any information.
357 // An error occurred.
358 return;
359 }
360
361 // Get the discount informations.
362 $.post(ajaxurl, prices_rq_discount, function (discount_response) {
363 var images_datas, prices_datas, promo_datas,
364 offers, consumption, suggested,
365 freeQuota = 25,
366 ot_html = '',
367 mo_html = '',
368 $mo_tpl, $ot_tpl,
369 ot_clone, mo_clone,
370 $estim_block, $offers_block,
371 $banners, date_end, plan_names, promo, discount;
372
373 if (! discount_response.success) {
374 // TODO: replace modal content by any information.
375 // An error occurred.
376 return;
377 }
378
379 images_datas = imgs_response.data;
380 prices_datas = prices_response.data;
381 promo_datas = discount_response.data;
382 offers = {
383 mo: [],
384 ot: []
385 };
386 consumption = {
387 month: images_datas.average_month_size.raw / Math.pow(1024, 2), // Bytes to MB.
388 total: images_datas.total_library_size.raw / Math.pow(1024, 2) // Bytes to MB.
389 };
390 $mo_tpl = $('#imagify-offer-monthly-template');
391 $ot_tpl = $('#imagify-offer-onetime-template');
392 ot_clone = $ot_tpl.html();
393 mo_clone = $mo_tpl.html();
394 $estim_block = $('.imagify-estimation-block');
395
396 // Remove inactive offers.
397 $.each(prices_datas.monthlies, function (index, value) {
398 if ('undefined' === typeof value.active
399 ||
400 ('undefined' !== typeof value.active && true === value.active)
401 ) {
402 if ('free' === value.label) {
403 freeQuota = value.quota;
404 }
405 offers.mo.push(value);
406 }
407 });
408 $.each(prices_datas.onetimes, function (index, value) {
409 if ('undefined' === typeof value.active
410 ||
411 ('undefined' !== typeof value.active && true === value.active)
412 ) {
413 offers.ot.push(value);
414 }
415 });
416
417 // Refresh Analyzing block.
418 $estim_block.removeClass('imagify-analyzing');
419 $estim_block.find('.average-month-size').text(images_datas.average_month_size.human);
420 $estim_block.find('.total-library-size').text(images_datas.total_library_size.human);
421
422 // Switch offers title if < 25mb.
423 if (consumption.total + consumption.month < freeQuota) {
424 $('.imagify-pre-checkout-offers .imagify-modal-title').addClass('imagify-enough-free');
425 } else {
426 $('.imagify-enough-free').removeClass('imagify-enough-free');
427 }
428
429 // Reset offer selection.
430 $('.imagify-offer-selected').removeClass('imagify-offer-selected').find('.imagify-checkbox').prop('checked', false);
431
432 // Don't create prices table if something went wrong during request.
433 if (null === offers.mo || null === offers.ot) {
434 $offers_block = $('.imagify-pre-checkout-offers');
435
436 // Hide main content.
437 $offers_block.hide().attr('aria-hidden', true);
438
439 // Show error message.
440 $offers_block.closest('.imagify-modal-views').find('.imagify-popin-message').remove();
441 $offers_block.after('<div class="imagify-popin-message imagify-error"><p>' + imagifyPricingModal.labels.errorPriceAPI + '</p></div>');
442
443 // Show the modal content.
444 imagifyModal.$modal.find('.imagify-modal-loader').fadeOut(300);
445 imagifyModal.$modal.removeClass('imagify-modal-loading');
446 return;
447 }
448
449 // Autofill coupon code & Show banner if discount is active.
450 w.imagify_discount_datas = promo_datas;
451
452 if (promo_datas.is_active) {
453 if (promo_datas.applies_to instanceof Array) {
454 plan_names = [];
455 var plan_list = [];
456
457 for (var plan_infos = 0; plan_infos < promo_datas.applies_to.length; plan_infos++) {
458 plan_list.push(promo_datas.applies_to[plan_infos].plan_name);
459 }
460
461 plan_list.forEach(function (item) {
462 if (! plan_names.includes(item)) {
463 plan_names.push(item);
464 }
465 });
466
467 plan_names = plan_names.join(', ');
468 } else {
469 plan_names = promo_datas.applies_to;
470 }
471
472 $banners = $('.imagify-modal-promotion');
473 date_end = promo_datas.date_end.split('T')[0];
474 promo = promo_datas.coupon_value;
475 discount = 'percentage' === promo_datas.coupon_type ? promo + '%' : '$' + promo;
476
477
478 // Show banners.
479 $banners.addClass('active').attr('aria-hidden', 'false');
480
481 // Populate banners.
482 $banners.find('.imagify-promotion-number').text(discount);
483 $banners.find('.imagify-promotion-plan-name').text(plan_names);
484 $banners.find('.imagify-promotion-date').text(date_end);
485
486 }
487
488 /**
489 * Find which plan(s) should be pre-selected.
490 */
491 suggested = imagifyModal.getSuggestedOffers(offers, consumption, freeQuota);
492
493 /**
494 * Below lines will build Plan and Onetime offers lists.
495 * It will also pre-select a Plan and/or Onetime in both of views: pre-checkout and pricing tables.
496 */
497 if (0 === offers.mo.length) {
498 $('.imagify-pre-checkout-offers .imagify-offer-monthly').remove();
499 $('.imagify-tabs').remove();
500 $('.imagify-pricing-tab-monthly').remove();
501 } else {
502 // Now, do the MONTHLIES Markup.
503 $.each(offers.mo, function (index, value) {
504 var $tpl, $offer,
505 classes = '';
506
507 // If offer is too big (far) than estimated needs, don't show the offer.
508 if ((index - suggested.mo.index) > 2) {
509 return true;
510 }
511
512 if (index === suggested.mo.index) {
513 // It's the one to display.
514 $offer = $('.imagify-pre-checkout-offers .imagify-offer-monthly');
515
516 if (suggested.mo.selected) {
517 classes = ' imagify-offer-selected';
518
519 // Add this offer as pre-selected item in pre-checkout view.
520 $offer.addClass('imagify-offer-selected').find('.imagify-checkbox').prop('checked', true);
521 }
522 // Populate the Pre-checkout view depending on user_cons.
523 imagifyModal.populateOffer($offer, value, 'monthly');
524 }
525
526 // Populate each offer.
527 $tpl = $(mo_clone).clone();
528 $tpl = imagifyModal.populateOffer($tpl, value, 'monthly', classes);
529
530 // Complete Monthlies HTML.
531 mo_html += $tpl[0].outerHTML;
532 });
533 }
534
535 if (0 === offers.ot.length) {
536 $('.imagify-pre-checkout-offers .imagify-offer-onetime').remove();
537 $('.imagify-tabs').remove();
538 $('.imagify-pricing-tab-onetime').remove();
539 } else {
540 // Do the ONETIMES Markup.
541 $.each(offers.ot, function (index, value) {
542 var $tpl, $offer,
543 classes = '';
544
545 // Parent classes.
546 if (index === suggested.ot.index) {
547 $offer = $('.imagify-pre-checkout-offers .imagify-offer-onetime');
548
549 if (suggested.ot.selected) {
550 classes = ' imagify-offer-selected';
551
552 // Add this offer as pre-selected item in pre-checkout view.
553 $offer.addClass('imagify-offer-selected').find('.imagify-checkbox').prop('checked', true);
554 }
555
556 // Populate the Pre-checkout view depending on user_cons.
557 imagifyModal.populateOffer($offer, value, 'onetime');
558 }
559
560 // Populate each offer.
561 $tpl = $(ot_clone).clone();
562 $tpl = imagifyModal.populateOffer($tpl, value, 'onetime', classes);
563
564 // complete Onetimes HTML
565 ot_html += $tpl[0].outerHTML;
566 });
567 }
568 if (promo_datas){
569 var applies_to = imagifyModal.getPromoAppliesTo(promo_datas);
570 if ( applies_to.includes(suggested.mo.plan_label) || applies_to.includes(suggested.ot.plan_label) || 'all' === applies_to[0]){
571 $('#imagify-coupon-code').val(promo_datas.label);
572 }
573 if (promo_datas.is_active) {
574 imagifyModal.checkCoupon();
575 }
576 }
577 // Fill pricing tables.
578 if ($mo_tpl.parent().find('.imagify-offer-line')) {
579 $mo_tpl.parent().find('.imagify-offer-line').remove();
580 }
581
582 $mo_tpl.before(mo_html);
583
584 if ($ot_tpl.parent().find('.imagify-offer-line')) {
585 $ot_tpl.parent().find('.imagify-offer-line').remove();
586 }
587
588 $ot_tpl.before(ot_html);
589
590 // Show the content.
591 imagifyModal.$modal.find('.imagify-modal-loader').fadeOut(300);
592 imagifyModal.$modal.removeClass('imagify-modal-loading');
593
594 }); // Third AJAX request to get discount information.
595
596 }); // Second AJAX request for image estimation sizes.
597
598 // Populate Pay button.
599 imagifyModal.populatePayBtn();
600 }); // End $.post.
601 },
602
603 /**
604 * Tell which offer(s) should be pre-selected.
605 *
606 * @param object offers {
607 * An object build like this:
608 *
609 * @type array mo Monthly offers. The most important data being 'quota' (MBytes).
610 * @type array ot One-Time offers. The most important data being 'quota' (MBytes).
611 * }
612 * @param object consumption {
613 * An object build like this:
614 *
615 * @type array month Average image size uploaded each month on the site (MBytes).
616 * @type array total Total image size in the library (MBytes).
617 * }
618 * @param int freeQuota Quota of the free monthly offer (MBytes). Currently 25.
619 * @return object {
620 * An object build like this:
621 *
622 * @type object mo An object containing the index of the suggested monthly offer, and if it should be selected.
623 * @type object ot An object containing the index of the suggested one-time offer, and if it should be selected.
624 * }
625 */
626 getSuggestedOffers: function (offers, consumption, freeQuota) {
627 var tmpMB = consumption.total + consumption.month,
628 plan,
629 biggestPlan = {
630 quota: 0
631 },
632 unlimitedPlan,
633 suggested = {
634 mo: false,
635 ot: false
636 };
637
638 if (0 > offers.ot.length){
639 var last_ot_plan_id = offers.ot[offers.ot.length - 1].id;
640 var last_ot_plan_label = offers.ot[offers.ot.length - 1].label;
641 }
642 if (0 > offers.ot.length){
643 var last_mo_plan_id = offers.mo[offers.mo.length - 1].id;
644 var last_mo_plan_label = offers.mo[offers.mo.length - 1].label;
645 }
646 /**
647 * Paid monthly plan.
648 */
649 $.each(offers.mo, function (index, value) {
650 // if this is the unlimited plan, save it; we may need to come back to it.
651 if (0 > value.quota) {
652 unlimitedPlan = {
653 index: index,
654 selected: 1,
655 plan_id: value.id,
656 plan_label: value.label
657 };
658 }
659
660 // This is the biggest plan we've seen so far. Save it in case we need it later.
661 if (value.quota > biggestPlan.quota) {
662 biggestPlan = {
663 index: index,
664 selected: 1,
665 quota: value.quota,
666 plan_id: value.id,
667 plan_label: value.label
668 };
669 }
670
671 // Skip the free plan.
672 if ((0 === value.monthly_cost) && (0 === value.annual_cost)) {
673 return true;
674 }
675
676 // For all except unlimited plan: Rule out this plan if quota is less than either library size or monthly usage.
677 if ((0 >= value.quota) && (consumption.month > value.quota) || (consumption.total > value.quota)) {
678 return true;
679 }
680
681 // For all except unlimited plan: Consider this plan if its quota meets consumption needs.
682 if ((0 <= value.quota) && (consumption.month < value.quota) && (consumption.total < value.quota)) {
683 // Select this one when (1) we haven't yet selected a plan, or (2) when this plan is less quota than the current one.
684 if (('undefined' === typeof plan) || (plan.quota > value.quota)) {
685 plan = value;
686 suggested.mo = {
687 index: index,
688 selected: (freeQuota > consumption.month) && (freeQuota > consumption.total) ? 0 : 1,
689 plan_id: value.id,
690 plan_label: value.label
691 };
692 }
693
694 return true;
695 }
696
697 return true;
698 });
699
700 // If we don't have a plan selected by the time we get here, we need the infinite plan, or the biggest if infinite isn't available.
701 if (false === suggested.mo) {
702 if ('undefined' !== typeof unlimitedPlan) {
703 suggested.mo = unlimitedPlan;
704 } else {
705 suggested.mo = biggestPlan;
706 }
707 }
708 // Remaining MB.
709 tmpMB -= offers.mo[suggested.mo.index].quota;
710
711 // If we don't have active onetime plans, we're done.
712 if (0 === offers.ot.length) {
713 return suggested;
714 }
715
716 if (tmpMB <= 0) {
717 /**
718 * The monthly plan is big enough to optimize all the images that already are in the library.
719 * We'll display a One-Time plan that is able to optimize the whole library, in case the user doesn't want a monthly plan, but it won't be pre-selected.
720 */
721 $.each(offers.ot, function (index, value) {
722 if (value.quota < consumption.total) {
723 // This plan is not big enough for the user needs.
724 return true;
725 }
726
727 // Suggested monthly plan.
728 suggested.ot = {
729 index: index,
730 selected: 0,
731 plan_id: value.id,
732 plan_label: value.label
733 };
734 return false;
735 });
736
737 if (false === suggested.ot) {
738 suggested.ot = {
739 index: offers.ot.length - 1,
740 selected: 0,
741 plan_id: last_ot_plan_id,
742 plan_label: last_ot_plan_label
743 };
744 }
745
746 return suggested;
747 }
748
749 /**
750 * The monthly plan is not big enough to optimize all the images that already are in the library.
751 * We need to select a One-Time plan.
752 */
753 $.each(offers.ot, function (index, value) {
754 if (value.quota < tmpMB) {
755 // This plan is not big enough for the user needs.
756 return true;
757 }
758
759 // Suggested one-time plan.
760 suggested.ot = {
761 index: index,
762 selected: 1,
763 plan_id: value.id,
764 plan_label: value.label
765 };
766 return false;
767 });
768
769 if (false !== suggested.ot) {
770 // OK, we have all we need.
771 return suggested;
772 }
773
774 /**
775 * If nothing is selected, that means no OT plan is big enough for the user.
776 * In that case we fallback to the biggest available, and we need to increase the monthly plan.
777 */
778 suggested.ot = {
779 index: offers.ot.length - 1,
780 selected: 1,
781 plan_id: last_ot_plan_id,
782 plan_label: last_ot_plan_label
783 };
784
785 // Reset monthly plan.
786 suggested.mo = false;
787
788 // Reset the remaining MB and subtract the OT plan quota.
789 tmpMB = consumption.total + consumption.month - offers.ot[suggested.ot.index].quota;
790
791 // Search for a new monthly plan.
792 $.each(offers.mo, function (index, value) {
793 if (value.quota < tmpMB) {
794 // This plan is not big enough for the user needs.
795 return true;
796 }
797
798 // Suggested monthly plan.
799 suggested.mo = {
800 index: index,
801 selected: 1,
802 plan_id: value.id,
803 plan_label: value.label
804 };
805 return false;
806 });
807
808 if (false === suggested.mo) {
809 /**
810 * If nothing is selected, that means no monthly plan is big enough for the user's monthly consumption.
811 * In that case we fallback to the biggest available.
812 */
813 suggested.mo = {
814 index: offers.mo.length - 1,
815 selected: 1,
816 plan_id: last_mo_plan_id,
817 plan_label: last_mo_plan_label
818 };
819 }
820
821 return suggested;
822 },
823
824 /**
825 * @uses imagifyModal.populatePayBtn()
826 */
827 checkCheckbox: function ($checkbox) {
828 var sel_class = 'imagify-offer-selected';
829
830 $checkbox.each(function () {
831 var $this = $(this);
832
833 if ($this.is(':checked')) {
834 $this.closest('.imagify-offer-line').addClass(sel_class);
835 } else {
836 $this.closest('.imagify-offer-line').removeClass(sel_class);
837 }
838 });
839
840 // Update pay button.
841 imagifyModal.populatePayBtn();
842 },
843
844 /**
845 * @uses imagifyModal.populatePayBtn()
846 */
847 checkRadio: function ($radio) {
848 var year_class = 'imagify-year-selected',
849 month_class = 'imagify-month-selected';
850
851 $radio.each(function () {
852 // To handle modal pricing & modal suggestion.
853 var $_this = $(this),
854 $parent, $to_switch;
855
856 if ($_this.parent('.imagify-cart-list-switcher').length) {
857 $parent = $_this.closest('.imagify-cart');
858 } else if ($_this.parent('.imagify-small-options').length) {
859 $parent = $_this.parent('.imagify-small-options').next('.imagify-pricing-table');
860 } else {
861 $parent = $_this.closest('.imagify-offer-line');
862 }
863
864 $to_switch = $parent.find('.imagify-switch-my');
865
866 if ($_this.val() === 'yearly') {
867 $parent.addClass(year_class).removeClass(month_class);
868 $to_switch.find('.imagify-monthly').attr('aria-hidden', 'true');
869 $to_switch.find('.imagify-yearly').attr('aria-hidden', 'false');
870 } else {
871 $parent.addClass(month_class).removeClass(year_class);
872 $to_switch.find('.imagify-monthly').attr('aria-hidden', 'false');
873 $to_switch.find('.imagify-yearly').attr('aria-hidden', 'true');
874 }
875 });
876
877 // Update Pay button information.
878 imagifyModal.populatePayBtn();
879
880 return $radio;
881 },
882
883 /**
884 * Currently not used.
885 * @uses imagifyModal.populatePayBtn()
886 */
887 populateBtnPrice: setInterval(function () {
888 imagifyModal.populatePayBtn();
889 }, 1000),
890
891 /**
892 * 1) Modal Payment change/select plan
893 * 2) Checkout selection(s)
894 * 3) Payment process
895 */
896
897 getPeriod: function () {
898 return $('.imagify-offer-monthly').hasClass('imagify-month-selected') ? 'monthly' : 'yearly';
899 },
900
901 getApiKey: function () {
902 return $('#imagify-payment-iframe').data('imagify-api');
903 },
904
905 switchToView: function ($view, data) {
906
907 var viewId = $view.attr('id'),
908 $modalContent = imagifyModal.$modal.children('.imagify-modal-content');
909
910 $view.siblings('.imagify-modal-views').hide().attr('aria-hidden', 'true');
911
912 // Plans view has tabs: display the right one.
913 if (data && data.tab) {
914 $view.find('a[href="#' + data.tab + '"]').trigger('click.imagify');
915 }
916
917 // Payment view: it's an iframe.
918 if ('imagify-payment-process-view' === viewId) {
919 $modalContent.addClass('imagify-iframe-viewing');
920 } else {
921 $modalContent.removeClass('imagify-iframe-viewing');
922 }
923
924 // Success view: some tweaks.
925 if ('imagify-success-view' === viewId) {
926 $modalContent.addClass('imagify-success-viewing');
927 imagifyModal.$modal.attr('aria-labelledby', 'imagify-success-view');
928 } else {
929 $modalContent.removeClass('imagify-success-viewing');
930 imagifyModal.$modal.removeAttr('aria-labelledby');
931 }
932
933 $view.fadeIn(imagifyModal.speedFadeIn).attr('aria-hidden', 'false');
934 },
935
936 /**
937 * @uses imagifyModal.getApiKey()
938 */
939 iframeSetSrc: function (params) {
940 /**
941 * params = {
942 * 'monthly': {
943 * 'lite': {
944 * name: 'something',
945 * id: ''
946 * }
947 * },
948 * 'onetime': {
949 * 'recommended': {
950 * name: 'Recommend',
951 * id: ''
952 * }
953 * },
954 * 'period': 'monthly'|'yearly'
955 * }
956 */
957
958 var $iframe = $('#imagify-payment-iframe'),
959 iframe_src = $iframe.attr('src'),
960 pay_src = $iframe.data('src'),
961 monthly_id = 0,
962 onetime_id = 0,
963 // Stop it ESLint, you're drunk.
964 key, amount, // eslint-disable-line no-unused-vars
965 rt_onetime, rt_yearly, rt_monthly, coupon, rt_coupon, $iframeClone, tofind;
966
967 // If we only change monthly/yearly payment mode.
968 if (typeof params === 'string' && '' !== iframe_src) {
969 tofind = 'monthly' === params ? 'yearly' : 'monthly';
970 iframe_src = iframe_src.replace(tofind, params);
971 $iframe.attr('src', iframe_src);
972 return;
973 }
974
975 // If we get new informations about products.
976 if (typeof params !== 'object') {
977 return;
978 }
979
980 if (params.monthly) {
981 monthly_id = params.monthly[Object.keys(params.monthly)[0]].id;
982 }
983
984 if (params.onetime) {
985 onetime_id = params.onetime[Object.keys(params.onetime)[0]].id;
986 // If onetime ID === 999 it's a custom plan, send datas instead.
987 onetime_id = (onetime_id + '' === '999' ? params.onetime[Object.keys(params.onetime)[0]].data : onetime_id);
988 }
989
990 if (! params.period) {
991 w.imagify.info('No period defined');
992 return;
993 }
994
995 key = imagifyModal.getApiKey();
996 rt_onetime = onetime_id;
997 rt_yearly = 'yearly' === params.period ? monthly_id : 0;
998 rt_monthly = 'monthly' === params.period ? monthly_id : 0;
999 coupon = $('#imagify-coupon-code').val();
1000 rt_coupon = '' === coupon ? 'none' : coupon;
1001 // Not used but...
1002 amount = parseFloat($('.imagify-global-amount').text()).toFixed(2);
1003
1004 // Compose route.
1005 // pay_src + :ontimeplan(0)/:monthlyplan(0)/:yearlyplan(0)/:coupon(none)/
1006 pay_src = pay_src + rt_onetime + '/' + rt_monthly + '/' + rt_yearly + '/' + rt_coupon + '/';
1007
1008 // iFrame sort of cache fix.
1009 $iframeClone = $iframe.remove().attr('src', pay_src);
1010
1011 imagifyModal.$paymentView.html($iframeClone);
1012 },
1013
1014 /**
1015 * Public function triggered by payement iframe.
1016 */
1017 paymentClose: function () {
1018 $('.imagify-iframe-viewing .close-btn').trigger('click.imagify');
1019 $('.imagify-iframe-viewing').removeClass('imagify-iframe-viewing');
1020 },
1021
1022 /**
1023 * @uses imagifyModal.switchToView()
1024 */
1025 paymentBack: function () {
1026 imagifyModal.switchToView(imagifyModal.$preView);
1027 },
1028
1029 /**
1030 * @uses imagifyModal.switchToView()
1031 */
1032 paymentSuccess: function () {
1033 imagifyModal.switchToView(imagifyModal.$successView);
1034 },
1035
1036 /**
1037 * @uses imagifyModal.paymentClose()
1038 * @uses imagifyModal.paymentBack()
1039 * @uses imagifyModal.paymentSuccess()
1040 */
1041 checkPluginMessage: function (e) {
1042 var origin = e.origin || e.originalEvent.origin; // eslint-disable-line no-shadow
1043
1044 if ( imagifyPricingModal.imagify_app_domain !== origin ) {
1045 return;
1046 }
1047
1048 switch (e.data) {
1049 case 'cancel':
1050 imagifyModal.paymentClose();
1051 break;
1052 case 'back':
1053 imagifyModal.paymentBack();
1054 break;
1055 case 'success':
1056 imagifyModal.paymentSuccess();
1057 break;
1058 }
1059 },
1060 getPromoAppliesTo: function(promo){
1061 var applies_to = [];
1062 if (promo.applies_to instanceof Array) {
1063 var plan_list = [];
1064
1065 for (var plan_infos = 0; plan_infos < promo.applies_to.length; plan_infos++) {
1066 plan_list.push(promo.applies_to[plan_infos].plan_name);
1067 }
1068
1069 plan_list.forEach(function (item) {
1070 if (! applies_to.includes(item)) {
1071 applies_to.push(item);
1072 }
1073 });
1074 } else {
1075 applies_to = [promo.applies_to];
1076 }
1077 return applies_to;
1078 }
1079 };
1080
1081 /**
1082 * INIT.
1083 */
1084
1085 // Check all boxes on load.
1086 imagifyModal.checkCheckbox(imagifyModal.$checkboxes);
1087 imagifyModal.checkRadio(imagifyModal.$radios.filter(':checked'));
1088
1089 // Check coupon onload.
1090 imagifyModal.checkCoupon();
1091
1092 // Check the changed box.
1093 imagifyModal.$checkboxes.on('change.imagify', function () {
1094 imagifyModal.checkCheckbox($(this));
1095 });
1096
1097 // Check the radio box.
1098 imagifyModal.$radios.on('change.imagify', function () {
1099 imagifyModal.checkRadio($(this));
1100 });
1101
1102 /**
1103 * Get pricings on modal opening.
1104 * Build the pricing tables inside modal.
1105 */
1106 $('#imagify-get-pricing-modal').on('click.imagify-ajax', function () {
1107 imagifyModal.getPricing($(this));
1108 });
1109
1110 /**
1111 * Reset the modal on close.
1112 */
1113 $(d).on('modalClosed.imagify', '.imagify-payment-modal', function () {
1114 // Reset viewing class & aria-labelledby.
1115 $('#imagify-coupon-code').val('');
1116
1117 $(this).find('.imagify-modal-content').removeClass('imagify-success-viewing imagify-iframe-viewing');
1118
1119 // Reset first view after fadeout ~= 300 ms.
1120 setTimeout(function () {
1121 $('.imagify-modal-views').hide();
1122 $('#imagify-pre-checkout-view').show();
1123 }, 300);
1124
1125 //delay scrolltop top to avoid flickering
1126 setTimeout(function () {
1127 $('.imagify-payment-modal').find('.imagify-modal-content').scrollTop(0);
1128 }, 400);
1129 });
1130
1131 /**
1132 * Get validation for Coupon Code
1133 * - On blur
1134 * - On Enter or Spacebar press
1135 * - On click OK button
1136 *
1137 * @since 1.6.3 Only if field hasn't readonly attribute (discount auto-applied).
1138 */
1139 $('#imagify-coupon-code').on('blur.imagify', function () {
1140 if (! $(this).attr('readonly')) {
1141 imagifyModal.checkCoupon();
1142 }
1143 }).on('keydown.imagify', function (e) {
1144 var $this = $(this);
1145
1146 if ($this.attr('readonly')) {
1147 return;
1148 }
1149 if (13 === e.keyCode || 32 === e.keyCode) {
1150 imagifyModal.checkCoupon();
1151 return false;
1152 }
1153 if ($this.val().length >= 3) {
1154 $this.closest('.imagify-coupon-input').addClass('imagify-canbe-validate');
1155 } else {
1156 $this.closest('.imagify-coupon-input').removeClass('imagify-canbe-validate');
1157 }
1158 });
1159
1160 $('#imagify-coupon-validate').on('click.imagify', function () {
1161 imagifyModal.checkCoupon();
1162 $(this).closest('.imagify-canbe-validate').removeClass('imagify-canbe-validate');
1163 });
1164
1165 /**
1166 * View game, step by step.
1167 */
1168
1169 // 1) when you decide to choose another plan.
1170
1171 /**
1172 * 1.a) on click, display choices.
1173 *
1174 * @uses imagifyModal.switchToView()
1175 */
1176 imagifyModal.$anotherBtn.on('click.imagify', function (e) {
1177 var type = $(this).data('imagify-choose'),
1178 tab = 'imagify-pricing-tab-' + ('plan' === type ? 'monthly' : 'onetime');
1179
1180 e.preventDefault();
1181
1182 imagifyModal.switchToView(imagifyModal.$plansView, {tab: tab});
1183 });
1184
1185 /**
1186 * 1.b) on click in a choice, return to pre-checkout step.
1187 *
1188 * @uses imagifyModal.getHtmlPrice()
1189 * @uses imagifyModal.switchToView()
1190 * @uses imagifyModal.populatePayBtn()
1191 */
1192 imagifyModal.$modal.on('click.imagify', '.imagify-payment-btn-select-plan', function (e) {
1193 var $_this = $(this),
1194 $offer_line = $_this.closest('.imagify-offer-line'),
1195 datas = $_this.data('offer'),
1196 datas_str = $_this.attr('data-offer'),
1197 is_onetime = $_this.closest('.imagify-tab-content').attr('id') !== 'imagify-pricing-tab-monthly',
1198 $target_line = is_onetime ? imagifyModal.$preView.find('.imagify-offer-onetime') : imagifyModal.$preView.find('.imagify-offer-monthly'),
1199 period = is_onetime ? null : ($_this.closest('.imagify-pricing-table').hasClass('imagify-month-selected') ? 'monthly' : 'yearly'),
1200 price = is_onetime ? imagifyModal.getHtmlPrice(datas[Object.keys(datas)[0]].price) : imagifyModal.getHtmlPrice(datas[Object.keys(datas)[0]].prices, period),
1201 monthly_txt = is_onetime ? '' : '<span class="imagify-price-by">' + $offer_line.find('.imagify-price-by').text() + '</span>',
1202 discount = $offer_line.find('.imagify-price-discount').html(),
1203 imgs = $offer_line.find('.imagify-approx-nb').text(),
1204 offer_size = $offer_line.find('.imagify-offer-size').text(),
1205 $coupon_input = $('#imagify-coupon-code');
1206
1207 e.preventDefault();
1208
1209 // Change views to go back pre-checkout.
1210 imagifyModal.switchToView(imagifyModal.$preView);
1211
1212 // Change price (+ "/month" if found in monthly plans).
1213 $target_line.find('.imagify-number-block').html(price + monthly_txt);
1214
1215 // Change discount.
1216 if (discount) {
1217 if ($target_line.find('.imagify-price-discount').length <= 0) {
1218 $target_line.find('.imagify-col-price').prepend('<span class="imagify-price-discount"></span>');
1219 }
1220 $target_line.find('.imagify-price-discount').html(discount);
1221 $target_line.find('.imagify-price-discount').show();
1222 } else {
1223 $target_line.find('.imagify-price-discount').hide();
1224 }
1225
1226 // Change approx images nb.
1227 $target_line.find('.imagify-approx-nb').text(imgs);
1228
1229 // Change offer size name.
1230 $target_line.find('.imagify-offer-size').text(offer_size);
1231
1232 // Change datas (json).
1233 $target_line.attr('data-offer', datas_str);
1234
1235 if (! is_onetime) {
1236 $target_line.find('.imagify-price-add-data').text($offer_line.find('.imagify-price-add-data').text());
1237
1238 // Trigger period selected from offer selection view to pre-checkout view.
1239 if ('monthly' === period) {
1240 $target_line.find('#imagify-subscription-monthly').trigger('click.imagify');
1241 } else {
1242 $target_line.find('#imagify-subscription-yearly').trigger('click.imagify');
1243 }
1244 $target_line.find('.imagify-inline-options').find('input:radio:checked').trigger('change.imagify');
1245 }
1246
1247 $coupon_input = $('#imagify-coupon-code');
1248 $coupon_input.val('');
1249
1250 if ( w.imagify_discount_datas ){
1251 var applies_to = imagifyModal.getPromoAppliesTo(w.imagify_discount_datas);
1252 if ( applies_to.includes(datas[Object.keys(datas)[0]].label ) || "all" === applies_to[0] ){
1253 $coupon_input.val(w.imagify_discount_datas.label);
1254 }
1255 }
1256
1257 imagifyModal.checkCoupon();
1258
1259 // Update price information in button.
1260 imagifyModal.populatePayBtn();
1261 });
1262
1263 /**
1264 * 2) when you checkout.
1265 *
1266 * @uses imagifyModal.switchToView()
1267 * @uses imagifyModal.getPeriod()
1268 * @uses imagifyModal.iframeSetSrc()
1269 */
1270 $('#imagify-modal-checkout-btn').on('click.imagify', function (e) {
1271 var $monthly_offer, $onetime_offer, checkout_datas;
1272
1273 e.preventDefault();
1274
1275 // Do nothing if button disabled.
1276 if ($(this).hasClass('imagify-button-disabled')) {
1277 return;
1278 }
1279
1280 $monthly_offer = $('.imagify-offer-monthly');
1281 $onetime_offer = $('.imagify-offer-onetime');
1282 checkout_datas = {};
1283
1284 // If user choose a monthly plan.
1285 if ($monthly_offer.hasClass('imagify-offer-selected')) {
1286 checkout_datas.monthly = JSON.parse($monthly_offer.attr('data-offer'));
1287 }
1288
1289 // If user choose a One Time plan.
1290 if ($onetime_offer.hasClass('imagify-offer-selected')) {
1291 checkout_datas.onetime = JSON.parse($onetime_offer.attr('data-offer'));
1292 }
1293
1294 // Clear user account cache.
1295 if (imagifyPricingModal.userDataCache) {
1296 $.post(ajaxurl, {
1297 action: imagifyPricingModal.userDataCache.deleteAction,
1298 _wpnonce: imagifyPricingModal.userDataCache.deleteNonce
1299 });
1300 }
1301
1302 // Change views to go to checkout/payment view.
1303 imagifyModal.switchToView(imagifyModal.$paymentView);
1304
1305 checkout_datas.period = imagifyModal.getPeriod();
1306 imagifyModal.iframeSetSrc(checkout_datas);
1307 });
1308
1309 /**
1310 * Go back to previous step ("Choose Another Plan" links).
1311 */
1312 $('.imagify-back-to-plans').on('click.imagify', function (e) {
1313 var $_this = $(this),
1314 is_onetime = $_this.closest('.imagify-cart-item').hasClass('imagify-cart-item-onetime');
1315
1316 e.preventDefault();
1317
1318 if (is_onetime) {
1319 $('.imagify-offer-onetime').find('.imagify-choose-another-plan').trigger('click.imagify');
1320 } else {
1321 $('.imagify-offer-monthly').find('.imagify-choose-another-plan').trigger('click.imagify');
1322 }
1323 });
1324
1325 // Message/communication API.
1326 w.addEventListener('message', imagifyModal.checkPluginMessage, true);
1327
1328 })(jQuery, document, window);
1329