PageSourceSearch

https://lady2fight.com/wp-content/plugins/revenue/assets/js/frontend/campaign.js?ver=2.2.6

js lady2fight.com collected 2026-09-30 05:05:10 UTC 74,762 bytes, 2,660 lines download raw bytes

1/* eslint-disable @wordpress/no-unused-vars-before-return */
2( function ( $ ) {
3	( 'use strict' );
4
5	const makeTemplatesVisible = () => {
6		const templates = document.querySelectorAll( '.revx-template' );
7		templates.forEach( ( template ) => {
8			template.style.visibility = 'visible';
9			template.style.opacity = '1';
10		} );
11	};
12
13	// Run on first load
14	makeTemplatesVisible();
15
16	// add events that does partial refresh of the DOM instead of full reload, to make the templates visible again
17	// Listen for cart / checkout partial refreshes
18	$( document.body ).on(
19		'updated_checkout updated_cart_totals woocommerce_update_order_review',
20		makeTemplatesVisible
21	);
22	// Listen for mini-cart updates
23	$( document.body ).on(
24		'wc_fragments_loaded wc_fragments_refreshed',
25		makeTemplatesVisible
26	);
27
28	// -----------------
29	// Plugins
30	$.fn.revxSlider = function () {
31		return this.each( function () {
32			const $container = $( this );
33			const $sliderIcons = $container.find( '.revx-slider-icons' );
34			const $items = $container.find( '.revx-grid-item' );
35			const itemCount = $items.length;
36
37			let currentPosition = 0;
38
39			function getBreakpoint( containerWidth ) {
40				if ( containerWidth <= 300 ) {
41					return 'sm';
42				}
43				if ( containerWidth <= 500 ) {
44					return 'md';
45				}
46				return 'lg';
47			}
48
49			function getVisibleItems() {
50				const containerWidth = $container.width();
51				const layout = $container.data( 'layout' ) || 'inpage';
52				const sliderColumns = $container.data( 'slider-columns' ) || {};
53				const breakpoint = getBreakpoint( containerWidth );
54
55				if (
56					sliderColumns[ layout ] &&
57					sliderColumns[ layout ][ breakpoint ]
58				) {
59					return parseInt(
60						sliderColumns[ layout ][ breakpoint ],
61						10
62					);
63				}
64
65				return 1;
66			}
67
68			function getMaxStartIndex() {
69				return itemCount - getVisibleItems();
70			}
71
72			function updateSliderPosition() {
73				$container.css(
74					'--revx-slider-translate',
75					`-${ currentPosition * 100 }%`
76				);
77			}
78
79			function handleNext() {
80				const maxStartIndex = getMaxStartIndex();
81				currentPosition =
82					currentPosition >= maxStartIndex ? 0 : currentPosition + 1;
83				updateSliderPosition();
84			}
85
86			function handlePrev() {
87				const maxStartIndex = getMaxStartIndex();
88				currentPosition =
89					currentPosition <= 0 ? maxStartIndex : currentPosition - 1;
90				updateSliderPosition();
91			}
92
93			function updateSliderVisibility() {
94				const visibleItems = getVisibleItems();
95				const isSliderNeeded = itemCount > visibleItems;
96
97				$container.toggleClass( 'has-slider', isSliderNeeded );
98
99				return isSliderNeeded;
100			}
101
102			function initializeSlider() {
103				const visibleItems = getVisibleItems();
104				const maxStartIndex = itemCount - visibleItems;
105
106				if ( currentPosition > maxStartIndex ) {
107					currentPosition = Math.max( 0, maxStartIndex );
108					updateSliderPosition();
109				}
110
111				updateSliderVisibility();
112			}
113
114			// Attach events
115			$sliderIcons
116				.find( '.next' )
117				.off( 'click' )
118				.on( 'click', handleNext );
119			$sliderIcons
120				.find( '.prev' )
121				.off( 'click' )
122				.on( 'click', handlePrev );
123
124			// Resize event
125			$( window ).on( 'resize', initializeSlider );
126
127			// Resize observer for wrapper
128			if ( typeof ResizeObserver !== 'undefined' ) {
129				const resizeObserver = new ResizeObserver( initializeSlider );
130				const wrapper = $container
131					.find( '.revx-items-wrapper' )
132					.get( 0 );
133				if ( wrapper ) {
134					resizeObserver.observe( wrapper );
135				}
136			}
137
138			// Initial setup
139			initializeSlider();
140		} );
141	};
142
143	$.fn.revxCountdownTimer = function ( options ) {
144		const settings = $.extend(
145			{
146				endTimeAttr: 'data-end-time',
147				startTimeAttr: 'data-start-time',
148				formatTimeUnit( unit ) {
149					return unit < 10 ? '0' + unit : unit;
150				},
151				onEnd( $el ) {
152					$el.html( '<span>00</span><span>:</span><span>00</span>' );
153				},
154				onBeforeStart( $el ) {
155					$el.html( '<span>00</span><span>:</span><span>00</span>' ); // You can change to "Coming Soon..." etc
156				},
157			},
158			options
159		);
160
161		function initTimer( $timer ) {
162			if ( $timer.data( 'revxCountdownInitialized' ) ) {
163				return;
164			}
165			$timer.data( 'revxCountdownInitialized', true );
166
167			const endTime = parseInt( $timer.attr( settings.endTimeAttr ), 10 );
168			const startTime =
169				parseInt( $timer.attr( settings.startTimeAttr ), 10 ) || null;
170
171			if ( isNaN( endTime ) ) {
172				settings.onEnd( $timer );
173				return;
174			}
175
176			function update() {
177				const now = Date.now();
178
179				if ( startTime && now < startTime ) {
180					settings.onBeforeStart( $timer );
181					return;
182				}
183
184				const diff = endTime - now;
185
186				if ( diff <= 0 ) {
187					clearInterval( interval );
188					settings.onEnd( $timer );
189					return;
190				}
191
192				const days = Math.floor( diff / ( 1000 * 60 * 60 * 24 ) );
193				const hours = Math.floor( ( diff / ( 1000 * 60 * 60 ) ) % 24 );
194				const minutes = Math.floor( ( diff / ( 1000 * 60 ) ) % 60 );
195				const seconds = Math.floor( ( diff / 1000 ) % 60 );
196
197				let html = '';
198
199				if ( days > 0 ) {
200					html +=
201						'<span>' +
202						settings.formatTimeUnit( days ) +
203						'</span><span>:</span>';
204				}
205				if ( days > 0 || hours > 0 ) {
206					html +=
207						'<span>' +
208						settings.formatTimeUnit( hours ) +
209						'</span><span>:</span>';
210				}
211				html +=
212					'<span>' +
213					settings.formatTimeUnit( minutes ) +
214					'</span><span>:</span>';
215				html +=
216					'<span>' + settings.formatTimeUnit( seconds ) + '</span>';
217
218				$timer.html( html );
219			}
220
221			update();
222			var interval = setInterval( update, 1000 );
223			$timer.data( 'revxCountdownInterval', interval );
224		}
225
226		// Initialize on each element
227		this.each( function () {
228			const $this = $( this );
229			initTimer( $this );
230		} );
231
232		return this;
233	};
234
235	function calculateCurrentPrice( offerData, productId, quantity ) {
236		const product = offerData[ productId ];
237
238		if ( ! product ) {
239			throw new Error( 'Product not found' );
240		}
241
242		const regularPrice = parseFloat( product.regular_price );
243		let currentPrice = regularPrice;
244
245		if ( product.offer && Array.isArray( product.offer ) ) {
246			for ( let i = 0; i < product.offer.length; i++ ) {
247				const offer = product.offer[ i ];
248				const minQty = parseInt( offer.qty, 10 );
249
250				if ( offer.type == 'free' ) {
251					if ( quantity >= minQty ) {
252						switch ( offer.type ) {
253							case 'free':
254								currentPrice = 0;
255
256								break;
257
258							default:
259								break;
260						}
261						// Add more offer types if needed (e.g., fixed discount)
262					}
263				} else if ( quantity >= minQty ) {
264					switch ( offer.type ) {
265						case 'percentage':
266							currentPrice =
267								regularPrice -
268								( parseFloat( offer.value ) / 100 ) *
269									regularPrice;
270							break;
271						case 'amount':
272						case 'fixed_discount':
273							currentPrice =
274								regularPrice - parseFloat( offer.value );
275
276							break;
277						case 'fixed_price':
278							currentPrice = parseFloat( offer.value );
279
280							break;
281						case 'no_discount':
282							currentPrice = regularPrice;
283
284							break;
285						case 'free':
286							currentPrice = 0;
287
288							break;
289
290						default:
291							break;
292					}
293					// Add more offer types if needed (e.g., fixed discount)
294				}
295			}
296		}
297
298		return parseFloat( currentPrice * quantity );
299	}
300
301	const formatPrice = ( price ) => {
302		const currencyFormat = revenue_campaign?.currency_format;
303		const currencySymbol = revenue_campaign?.currency_format_symbol;
304		const decimalSeparator = revenue_campaign?.currency_format_decimal_sep;
305		const thousandSeparator =
306			revenue_campaign?.currency_format_thousand_sep;
307		const numDecimals = revenue_campaign?.currency_format_num_decimals;
308
309		const fixedPrice = parseFloat( price ).toFixed( numDecimals || 2 );
310
311		const parts = fixedPrice.split( '.' );
312		let integerPart = parts[ 0 ];
313		let decimalSepAndNum = '';
314		if ( numDecimals > 0 ) {
315			decimalSepAndNum = decimalSeparator + ( parts[ 1 ] || '00' );
316		}
317
318		integerPart = integerPart.replace(
319			/\B(?=(\d{3})+(?!\d))/g,
320			thousandSeparator
321		);
322
323		const formattedPrice = integerPart + decimalSepAndNum;
324
325		return currencyFormat
326			.replace( '%1$s', currencySymbol )
327			.replace( '%2$s', formattedPrice );
328	};
329
330	// Volume Discount
331	$( '.revx-volume-discount .revx-campaign-item' ).on(
332		'click',
333		function ( e ) {
334			// Remove selected style from all items
335			e.stopPropagation();
336			const that = $( this );
337			$( '.revx-volume-discount .revx-campaign-item' ).each( function () {
338				const item = $( this ).find( '.revx-volume-discount__tag' );
339				const defaultStyle = item.data( 'default-style' );
340				$( item ).attr( 'style', defaultStyle );
341				$( this ).attr( 'data-revx-selected', false );
342			} );
343			const clickedItem = that.find( '.revx-volume-discount__tag' );
344
345			// Apply selected style to the clicked item
346			const selectedStyle = clickedItem.data( 'selected-style' );
347			clickedItem.attr( 'style', selectedStyle );
348			that.attr( 'data-revx-selected', true );
349
350			$( '.revx-ticket-type' ).trigger( 'change' );
351		}
352	);
353
354	$( 'select.revx-productAttr-wrapper__field' ).on( 'change', function () {
355		const attributeData =
356			$( '.variations_form' ).data( 'product_variations' );
357
358		const attributeName = $( this ).data( 'attribute_name' );
359
360		const parentWrapper = $( this ).closest( '.revx-productAttr-wrapper' );
361		const fieldsInParent = parentWrapper.find(
362			'.revx-productAttr-wrapper__field'
363		);
364
365		let allFieldsHaveValue = true;
366		const values = {};
367		fieldsInParent.each( function () {
368			if ( $( this ).val() === '' ) {
369				allFieldsHaveValue = false;
370				return false; // Break the loop
371			}
372			values[ $( this ).data( 'attribute_name' ) ] = $( this ).val();
373		} );
374
375		let selectedVariation = false;
376
377		if ( allFieldsHaveValue ) {
378			attributeData.forEach( ( element ) => {
379				if (
380					JSON.stringify( element.attributes ) ==
381					JSON.stringify( values )
382				) {
383					selectedVariation = element;
384				}
385			} );
386		}
387
388		$( '.revx-campaign-item' ).removeAttr( 'data-product-id' );
389		if ( selectedVariation ) {
390			const parent = $( this ).closest( '.revx-campaign-item' );
391			const campaignID = parent.data( 'campaignId' );
392			const quantity = parent.data( 'quantity' );
393
394			const offerData = JSON.parse(
395				$( `input[name="revx-offer-data-${ campaignID }"]` ).val()
396			);
397
398			const variation_id = selectedVariation.variation_id;
399
400			const offer = offerData[ variation_id ];
401
402			let nearestOffer = offer.offer[ 0 ];
403			for ( let i = 1; i < offer.offer.length; i++ ) {
404				if ( offer.offer[ i ].qty <= quantity ) {
405					nearestOffer = offer.offer[ i ];
406				} else {
407					break;
408				}
409			}
410
411			let regular_price = offer.regular_price;
412			let sale_price = '';
413
414			switch ( nearestOffer.type ) {
415				case 'percentage':
416					sale_price =
417						parseFloat( offer.regular_price * nearestOffer.qty ) *
418						( 1 - nearestOffer.value / 100 );
419
420					break;
421				case 'amount':
422				case 'fixed_discount':
423					sale_price =
424						Math.max(
425							0,
426							parseFloat( offer.regular_price ) -
427								parseFloat( nearestOffer.value )
428						) * nearestOffer.qty;
429
430					break;
431				case 'fixed_price':
432					sale_price =
433						parseFloat( nearestOffer.value ) * nearestOffer.qty;
434					regular_price = false;
435
436					break;
437				case 'no_discount':
438					sale_price =
439						parseFloat( offer.regular_price ) * nearestOffer.qty;
440					regular_price = false;
441
442					break;
443				case 'free':
444					sale_price = 0;
445
446					break;
447
448				default:
449					break;
450			}
451
452			parent.attr( 'data-product-id', variation_id );
453
454			parent
455				.parent()
456				.parent()
457				.find( '.revx-campaign-add-to-cart-btn' )
458				.attr( 'data-product-id', variation_id );
459
460			parent.find( 'input[data-name=revx_quantity]' ).trigger( 'change' );
461
462			parent
463				.find( '.revx-campaign-item__regular-price' )
464				.html( formatPrice( regular_price * quantity ) );
465			parent
466				.find( '.revx-campaign-item__sale-price' )
467				.html( formatPrice( sale_price ) );
468		} else {
469			const parent = $( this ).closest( '.revx-campaign-item' );
470			parent.find( '.revx-campaign-item__regular-price' ).html( '' );
471			parent.find( '.revx-campaign-item__sale-price' ).html( '' );
472		}
473	} );
474
475	function updatePriceDisplay( parent, quantity, salePrice, regularPrice ) {
476		salePrice = parseFloat( salePrice );
477		regularPrice = parseFloat( regularPrice );
478		const salePriceElement = $( parent ).find(
479			'.revx-campaign-item__sale-price'
480		);
481		const regularPriceElement = $( parent ).find(
482			'.revx-campaign-item__regular-price'
483		);
484		const savingsTag = $( parent ).find( '.revx-builder-savings-tag' );
485
486		if ( quantity == 0 ) {
487			salePriceElement.html( formatPrice( 0 ) );
488			savingsTag.hide();
489			return;
490		}
491
492		if ( salePrice !== regularPrice ) {
493			salePriceElement.html(
494				quantity > 1
495					? `${ quantity } x ` + formatPrice( salePrice )
496					: formatPrice( salePrice )
497			);
498			regularPriceElement.html(
499				quantity > 1
500					? `${ quantity } x ` + formatPrice( regularPrice )
501					: formatPrice( regularPrice )
502			);
503			savingsTag.show();
504		} else {
505			salePriceElement.html(
506				quantity > 1
507					? `${ quantity } x ` + formatPrice( regularPrice )
508					: formatPrice( regularPrice )
509			);
510			regularPriceElement.empty();
511			savingsTag.hide();
512		}
513	}
514
515	$(
516		'.revx-volume-discount .revx-builder__quantity input[data-name=revx_quantity]'
517	).on( 'change', function () {
518		const parent = $( this ).closest( '.revx-campaign-item' );
519		const product_id = $( this )
520			.closest( '.revx-campaign-item' )
521			.data( 'product-id' );
522
523		if ( ! product_id ) {
524			return;
525		}
526
527		const quantity = $( this ).val();
528
529		parent
530			.parent()
531			.parent()
532			.find( '.revx-campaign-add-to-cart-btn' )
533			.attr( 'data-quantity', quantity );
534
535		const campaignId = $( this ).data( 'campaign-id' ); // Get data-campaign-id attribute value
536
537		let offerData = $( `input[name="revx-offer-data-${ campaignId }"]` );
538		offerData = offerData[ 0 ].value;
539		const jsonData = JSON.parse( offerData );
540
541		const regularPrice = (
542			jsonData[ product_id ].regular_price * quantity
543		).toFixed( 2 );
544		const salePrice = calculateCurrentPrice(
545			jsonData,
546			product_id,
547			quantity
548		).toFixed( 2 );
549
550		if ( salePrice != regularPrice ) {
551			$( parent )
552				.find( '.revx-campaign-item__sale-price' )
553				.html( formatPrice( salePrice ) );
554			$( parent )
555				.find( '.revx-campaign-item__regular-price' )
556				.html( formatPrice( regularPrice ) );
557		} else {
558			$( parent )
559				.find( '.revx-campaign-item__regular-price' )
560				.html( formatPrice( salePrice ) );
561		}
562	} );
563
564	// Bundle Discount
565	$(
566		'.revx-bundle-discount .revx-builder__quantity input[data-name=revx_quantity]'
567	).on( 'change', function () {
568		const parent = $( this ).closest( '.revx-campaign-container__wrapper' );
569		const bundle_products = $( this )
570			.closest( '.revx-campaign-container__wrapper' )
571			.data( 'bundle_products' );
572
573		if ( bundle_products.length == 0 ) {
574			return;
575		}
576
577		const quantity = $( this ).val();
578
579		parent
580			.find( '.revenue-campaign-add-bundle-to-cart' )
581			.attr( 'data-quantity', quantity );
582
583		const campaignId = $( this ).data( 'campaign-id' ); // Get data-campaign-id attribute value
584
585		let offerData = $( `input[name="revx-offer-data-${ campaignId }"]` );
586		offerData = offerData[ 0 ].value;
587		const jsonData = JSON.parse( offerData );
588
589		let totalRegularPrice = 0;
590		let totalSalePrice = 0;
591
592		bundle_products.forEach( ( product ) => {
593			const productId = product.item_id;
594			// let quantity = product.quantity;
595
596			if ( jsonData[ productId ] ) {
597				totalRegularPrice += parseFloat(
598					(
599						jsonData[ productId ].regular_price *
600						quantity *
601						product.quantity
602					).toFixed( 2 )
603				);
604				totalSalePrice += parseFloat(
605					calculateCurrentPrice(
606						jsonData,
607						productId,
608						product.quantity * quantity
609					).toFixed( 2 )
610				);
611			}
612		} );
613
614		if ( totalRegularPrice != totalSalePrice ) {
615			$( parent )
616				.find(
617					'.revx-total-price__offer-price .revx-campaign-item__sale-price'
618				)
619				.html( formatPrice( totalSalePrice ) );
620			$( parent )
621				.find(
622					'.revx-total-price__offer-price .revx-campaign-item__regular-price'
623				)
624				.html( formatPrice( totalRegularPrice ) );
625		} else {
626			$( parent )
627				.find(
628					'.revx-total-price__offer-price .revx-campaign-item__regular-price'
629				)
630				.html( formatPrice( totalRegularPrice ) );
631		}
632	} );
633
634	// Normal Discount
635	$(
636		'.revx-normal-discount .revx-builder__quantity input[data-name=revx_quantity]'
637	).on( 'change', function () {
638		const parent = $( this ).closest( '.revx-campaign-item' );
639		const product_id = $( this )
640			.closest( '.revx-campaign-item' )
641			.data( 'product-id' );
642
643		if ( ! product_id ) {
644			return;
645		}
646
647		const quantity = $( this ).val();
648
649		parent
650			.find( '.revx-campaign-add-to-cart-btn' )
651			.attr( 'data-quantity', quantity );
652		const campaignId = $( this ).data( 'campaign-id' ); // Get data-campaign-id attribute value
653
654		let offerData = $( `input[name="revx-offer-data-${ campaignId }"]` );
655		offerData = offerData[ 0 ].value;
656		const jsonData = JSON.parse( offerData );
657
658		if ( ! jsonData[ product_id ] ) {
659			return;
660		}
661
662		const inRP = jsonData[ product_id ].regular_price;
663
664		const regularPrice = (
665			jsonData[ product_id ].regular_price * quantity
666		).toFixed( 2 );
667
668		const salePrice = calculateCurrentPrice(
669			jsonData,
670			product_id,
671			quantity
672		).toFixed( 2 );
673
674		const inSP = ( salePrice / quantity ).toFixed( 2 );
675
676		updatePriceDisplay( parent, quantity, inSP, inRP );
677
678		// if (salePrice != regularPrice) {
679		//     $(parent).find('.revx-campaign-item__sale-price').html(`${qty} x `+formatPrice(inSP));
680		//     $(parent).find('.revx-campaign-item__regular-price').html(`${qty} x `+formatPrice(inRP));
681		// } else {
682		//     $(parent).find('.revx-campaign-item__sale-price').html(`${qty} x `+formatPrice(inRP));
683		// }
684	} );
685
686	// Delegate click event for the 'minus' button
687	// $( document ).on( 'click', '.revx-quantity-minus', function ( e ) {
688	// 	e.preventDefault();
689	// 	e.stopPropagation(); // Stop event propagation to parent elements
690	// 	const $input = $( this ).siblings( 'input[type="number"]' );
691
692	// 	if ( $( this ).data( 'skip-global' ) ) {
693	// 		return;
694	// 	}
695
696	// 	if ( ! $input ) {
697	// 		return;
698	// 	}
699	// 	$input.focus(); // Focus on the input field after updating its value
700
701	// 	const currentValue = parseInt( $input.val(), 10 );
702	// 	const min = $input.attr( 'min' );
703
704	// 	if ( min && currentValue - 1 >= min ) {
705	// 		if ( ! isNaN( currentValue ) && currentValue > 0 ) {
706	// 			$input.val( currentValue - 1 );
707	// 		}
708	// 	}
709	// 	// else if ( ! isNaN( currentValue ) && currentValue - 1 > 0 ) {
710	// 	// 	$input.val( currentValue - 1 );
711	// 	// }
712
713	// 	$input.trigger( 'change' );
714	// } );
715
716	// // Delegate click event for the 'plus' button
717	// $( document ).on( 'click', '.revx-quantity-plus', function ( e ) {
718	// 	e.preventDefault();
719	// 	e.stopPropagation(); // Stop event propagation to parent elements
720
721	// 	// Skip if it has data-skip-global attribute
722	// 	if ( $( this ).data( 'skip-global' ) ) {
723	// 		return;
724	// 	}
725
726	// 	const $input = $( this ).siblings( 'input[type="number"]' );
727	// 	if ( ! $input.length ) {
728	// 		return;
729	// 	}
730	// 	$input.focus(); // Focus on the input field after updating its value
731
732	// 	const currentValue = parseInt( $input.val(), 10 );
733	// 	const maxValue = parseInt( $input.attr( 'max' ), 10 ); // Get the max attribute value
734
735	// 	if ( ! isNaN( currentValue ) ) {
736	// 		// Check if current value is less than the max value
737	// 		if ( ! isNaN( maxValue ) && currentValue < maxValue ) {
738	// 			$input.val( currentValue + 1 );
739	// 		} else if ( isNaN( maxValue ) ) {
740	// 			$input.val( currentValue + 1 ); // No max set, just increment
741	// 		}
742	// 	} else {
743	// 		$input.val( 1 ); // Set default value if current value is not a number
744	// 	}
745
746	// 	$input.trigger( 'change' );
747	// } );
748
749	// Delegate input event for the quantity input field
750	$( document ).on(
751		'input',
752		'input[data-name=revx_quantity]',
753		function ( e ) {
754			const minVal = parseInt( $( this ).attr( 'min' ) ) || 0; // Default to 0 if min is not set
755			const maxVal = parseInt( $( this ).attr( 'max' ) ); // Parse max value from the attribute
756			const val = parseInt( $( this ).val() ); // Get the current value of the input
757
758			// If the current value is less than min, set it to min
759			if ( val < minVal ) {
760				$( this ).val( minVal );
761			}
762
763			// If the current value is greater than max, set it to max
764			if ( ! isNaN( maxVal ) && val > maxVal ) {
765				$( this ).val( maxVal );
766			}
767			// Trigger change event after updating the value
768			$( this ).trigger( 'change' );
769		}
770	);
771
772	function getCookie( cname ) {
773		const name = 'revx_' + cname + '=';
774		const decodedCookie = decodeURIComponent( document.cookie );
775		const ca = decodedCookie.split( ';' );
776		for ( let i = 0; i < ca.length; i++ ) {
777			let c = ca[ i ];
778			while ( c.charAt( 0 ) == ' ' ) {
779				c = c.substring( 1 );
780			}
781			if ( c.indexOf( name ) == 0 ) {
782				return c.substring( name.length, c.length );
783			}
784		}
785		return '';
786	}
787
788	// Function to set the cookie
789	function setCookie( name, value, days ) {
790		const date = new Date();
791		date.setTime( date.getTime() + days * 24 * 60 * 60 * 1000 );
792		const expires = 'expires=' + date.toUTCString();
793		document.cookie =
794			'revx_' +
795			name +
796			'=' +
797			encodeURIComponent( value ) +
798			';' +
799			expires +
800			';path=/';
801	}
802
803	// Mix Match campaigns single product add to cart button.
804	$( '.revx-campaign-product-card .revx-mix-match-product-btn' ).on(
805		'click',
806		function ( e ) {
807			e.preventDefault();
808
809			const campaignId = $( this ).data( 'campaign-id' );
810			const item = $( this ).closest( '.revx-mix_match-add-to-cart' );
811			let productId = item.data( 'product-id' );
812			const productType = item.attr( 'product_type' );
813
814			const quantity =
815				item.find( `input[data-name="revx_quantity"]` ).val() ?? 1;
816
817			const offerData = $(
818				`input[name="revx-offer-data-${ campaignId }"]`
819			).val();
820			const container = $( this ).closest(
821				'.revx-campaign-product-card'
822			);
823			const jsonData = JSON.parse( offerData );
824
825			const qtyData = $(
826				`input[name="revx-qty-data-${ campaignId }"]`
827			).val();
828			const jsonQtyData = JSON.parse( qtyData );
829			let parentId = null;
830			let variationProductDetails = null;
831			let variationAttributes = null;
832			let selectedData = null;
833
834			if ( productType === 'variable' ) {
835				const variationMap = item
836					.find( '[data-variation-map]' )
837					.data( 'variation-map' );
838				selectedData = getSelectedAttributes( item );
839				const odata = container.attr( 'data-variations' );
840				parentId = container.data( 'product-id' );
841				const a = JSON.parse( odata );
842
843				if ( ! selectedData ) {
844					// throw new Error( 'Selected data is undefined or null.' );
845					showToast(
846						revenue_campaign?.select_all_attributes ||
847							'Please select all product attributes before adding to cart.',
848						'error',
849						3000
850					);
851					return;
852				}
853
854				// Check for empty or undefined attribute values
855				for ( const [ , value ] of Object.entries( selectedData ) ) {
856					if (
857						value === '' ||
858						value === null ||
859						value === undefined
860					) {
861						showToast(
862							revenue_campaign?.select_all_attributes ||
863								'Please select all required attributes',
864							'error',
865							3000
866						);
867						return;
868					}
869				}
870
871				// now i need to match product id from variation map with selected data
872				let matchedVariationId = null;
873
874				const matchedVariation = variationMap.find( ( variation ) => {
875					if ( ! variation.attributes ) {
876						return false;
877					}
878					return Object.entries( selectedData ).every(
879						( [ key, val ] ) =>
880							! val ||
881							! variation.attributes[ key ] ||
882							variation.attributes[ key ] === val
883					);
884				} );
885
886				if ( matchedVariation ) {
887					matchedVariationId = matchedVariation.variation_id;
888					productId = matchedVariationId;
889				}
890
891				variationProductDetails = a.find( ( v ) => {
892					return parseInt( v.id ) === parseInt( matchedVariationId );
893				} );
894
895				variationAttributes = Object.entries( selectedData )
896					.filter( ( [ key ] ) => key.startsWith( 'attribute_' ) ) // only attributes
897					.map( ( [ , value ] ) => value ) // just take the value
898					.join( ' - ' ); // join with dash
899
900				jsonData[ matchedVariationId ] = {
901					item_id: parseInt( matchedVariationId ),
902					item_name: `${ jsonData[ parentId ]?.item_name || '' }${
903						variationAttributes ? ' - ' + variationAttributes : ''
904					}`,
905					thumbnail: variationProductDetails.image_url || '',
906					regular_price: variationProductDetails.regular_price || '',
907					sale_price: variationProductDetails.sale_price || '',
908					quantity: 1,
909					parent_id: parentId,
910				};
911			}
912
913			const data = {
914				id: productId,
915				productName:
916					productType === 'variable'
917						? `${ jsonData[ parentId ]?.item_name || '' }${
918								variationAttributes
919									? ' - ' + variationAttributes
920									: ''
921						  }`
922						: jsonData[ productId ]?.item_name,
923				regularPrice:
924					productType === 'variable'
925						? variationProductDetails.regular_price
926						: jsonData[ productId ]?.regular_price,
927				thumbnail:
928					productType === 'variable'
929						? variationProductDetails.image_url
930						: jsonData[ productId ]?.thumbnail,
931				quantity,
932			};
933
934			const cookieName = `mix_match_${ campaignId }`;
935			let prevData = getCookie( cookieName );
936
937			let prevSelectedItems = $(
938				`input[name="revx-selected-items-${ campaignId }"]`
939			).val();
940
941			prevSelectedItems = prevSelectedItems
942				? JSON.parse( prevSelectedItems )
943				: {};
944
945			prevData = prevData ? JSON.parse( prevData ) : {};
946
947			// handles the case of initial render. when the required items are pre-selected and not in cookie,
948			// merge the cookie data with pre selected data and then update accordingly.
949			if ( Object.keys( prevSelectedItems ).length !== 0 ) {
950				for ( const itemId in prevSelectedItems ) {
951					if ( ! prevData[ itemId ] ) {
952						prevData[ itemId ] = prevSelectedItems[ itemId ];
953					}
954				}
955			}
956			let clonedItem;
957
958			if ( prevData[ productId ] ) {
959				prevData[ productId ].quantity =
960					parseInt( prevData[ productId ].quantity ) +
961					parseInt( quantity );
962
963				$(
964					`.revx-selected-item[data-campaign-id=${ campaignId }][data-product-id=${ productId }] .revx-selected-item__product-price .woocommerce-Price-amount`
965				).text( `${ formatPrice( data.regularPrice ) }` );
966				$(
967					`.revx-selected-item[data-campaign-id=${ campaignId }][data-product-id=${ productId }] .revx-selected-item__product-price .revx-qty`
968				).text( `(x ${ prevData[ productId ].quantity })` );
969			} else {
970				const selectedContainer = $(
971					`.revx-campaign-${ campaignId } .revx-selected-container`
972				);
973
974				selectedContainer.removeClass( 'revx-d-none' );
975				selectedContainer.removeClass( 'revx-empty-selected-items' );
976
977				$(
978					`.revx-campaign-${ campaignId } .revx-empty-mix-match`
979				).addClass( 'revx-d-none' );
980
981				prevData[ productId ] = data;
982
983				const placeholderItem = $(
984					`.revx-selected-item.revx-d-none[data-campaign-id=${ campaignId }]`
985				).first(); // ensure only one placeholder.
986				clonedItem = placeholderItem.clone();
987				clonedItem
988					.find( '.revx-selected-title' )
989					.html( data.productName );
990				clonedItem
991					.find( '.revx-campaign-item__image img' )
992					.attr( 'src', data.thumbnail );
993				clonedItem
994					.find( '.revx-campaign-item__image img' )
995					.attr( 'alt', data.productName );
996				clonedItem
997					.find(
998						'.revx-selected-item__product-price .revx-price-placeholder'
999					)
1000					.text( `${ formatPrice( data.regularPrice ) }` );
1001				clonedItem
1002					.find( '.revx-selected-item__product-price .revx-qty' )
1003					.text( `(x ${ quantity })` );
1004				clonedItem.removeClass( 'revx-d-none' );
1005				clonedItem.attr( 'data-product-id', productId );
1006				if ( productType === 'variable' ) {
1007					clonedItem.attr(
1008						'data-selected-attribute',
1009						JSON.stringify( selectedData )
1010					);
1011				}
1012				clonedItem.attr( 'data-parent-id', parentId );
1013				clonedItem.attr( 'data-product-type', productType );
1014				placeholderItem.before( clonedItem );
1015			}
1016
1017			$( `input[name="revx-selected-items-${ campaignId }"]` ).val(
1018				JSON.stringify( prevData )
1019			);
1020
1021			setCookie( cookieName, JSON.stringify( prevData ), 7 );
1022
1023			updateMixMatchHeaderAndPrices( campaignId, prevData, jsonQtyData );
1024
1025			$( this )
1026				.parent()
1027				.find( `input[data-name="revx_quantity"]` )
1028				.val( 1 );
1029			// make the reset button visible after adding any product
1030			$( this )
1031				.closest( '.revx-template' )
1032				.find( '[data-mix-match-reset-btn]' )
1033				.removeClass( 'revx-d-none' );
1034		}
1035	);
1036
1037	function removeMixMatchSelectedItem() {
1038		const productId = $( this )
1039			.closest( '[data-product-id]' )
1040			.data( 'product-id' );
1041		const campaignId = $( this )
1042			.closest( '[data-campaign-id]' )
1043			.data( 'campaign-id' );
1044		const item = $(
1045			`.revx-selected-item[data-campaign-id=${ campaignId }][data-product-id="${ productId }"]`
1046		);
1047
1048		item.remove();
1049
1050		const cookieName = `mix_match_${ campaignId }`;
1051		let prevData = getCookie( cookieName );
1052		let prevSelectedItems = $(
1053			`input[name=revx-selected-items-${ campaignId }]`
1054		).val();
1055		prevSelectedItems = prevSelectedItems
1056			? JSON.parse( prevSelectedItems )
1057			: {};
1058
1059		prevData = prevData ? JSON.parse( prevData ) : {};
1060
1061		// handles the case of initial render, when the required items are pre-selected,
1062		// merge the cookie data with pre selected data and then update accordingly.
1063		if ( Object.keys( prevSelectedItems ).length !== 0 ) {
1064			for ( const itemId in prevSelectedItems ) {
1065				if ( ! prevData[ itemId ] ) {
1066					prevData[ itemId ] = prevSelectedItems[ itemId ];
1067				}
1068			}
1069		}
1070
1071		delete prevData[ productId ];
1072		setCookie( cookieName, JSON.stringify( prevData ), 7 );
1073		$( `input[name=revx-selected-items-${ campaignId }]` ).val(
1074			JSON.stringify( prevData )
1075		);
1076
1077		const qtyData = $( `input[name=revx-qty-data-${ campaignId }]` ).val();
1078		const jsonQtyData = JSON.parse( qtyData );
1079
1080		if ( Object.keys( prevData ).length === 0 ) {
1081			$(
1082				`.revx-campaign-${ campaignId } .revx-empty-selected-products`
1083			).removeClass( 'revx-d-none' );
1084			$(
1085				`.revx-campaign-${ campaignId } .revx-selected-product-container`
1086			).addClass( 'revx-empty-selected-items' );
1087			$(
1088				`.revx-campaign-${ campaignId } .revx-empty-mix-match`
1089			).removeClass( 'revx-d-none' );
1090
1091			$(
1092				`.revx-campaign-${ campaignId } [data-mix-match-reset-btn]`
1093			).addClass( 'revx-d-none' );
1094		}
1095
1096		updateMixMatchHeaderAndPrices( campaignId, prevData, jsonQtyData );
1097	}
1098
1099	$( '[data-container-level="mix_match_file"]' ).on(
1100		'click',
1101		'.revx-selected-remove',
1102		removeMixMatchSelectedItem
1103	);
1104
1105	// refactor later to make DRY
1106	function resetMixMatchSelectedItem() {
1107		const campaignId = $( this )
1108			.closest( '[data-campaign-id]' )
1109			.data( 'campaign-id' );
1110
1111		const cookieName = `mix_match_${ campaignId }`;
1112
1113		let prevSelectedItems = $(
1114			`input[name=revx-selected-items-${ campaignId }]`
1115		).val();
1116		prevSelectedItems = prevSelectedItems
1117			? JSON.parse( prevSelectedItems )
1118			: {};
1119
1120		for ( const itemId in prevSelectedItems ) {
1121			const $item = $( this )
1122				.closest( '[revx-campaign-id]' )
1123				.find(
1124					`.revx-selected-item[data-campaign-id=${ campaignId }][data-product-id="${ itemId }"]`
1125				);
1126			if ( prevSelectedItems[ itemId ].is_required === 'yes' ) {
1127				prevSelectedItems[ itemId ].quantity = 1;
1128				$item.find( '.revx-qty' ).text( '(x 1)' );
1129			} else {
1130				$item.remove();
1131				delete prevSelectedItems[ itemId ];
1132			}
1133		}
1134		setCookie( cookieName, JSON.stringify( prevSelectedItems ), 7 );
1135		$( `input[name=revx-selected-items-${ campaignId }]` ).val(
1136			JSON.stringify( prevSelectedItems )
1137		);
1138
1139		const qtyData = $( `input[name=revx-qty-data-${ campaignId }]` ).val();
1140		const jsonQtyData = JSON.parse( qtyData );
1141
1142		if ( Object.keys( prevSelectedItems ).length === 0 ) {
1143			$(
1144				`.revx-campaign-${ campaignId } .revx-empty-selected-products`
1145			).removeClass( 'revx-d-none' );
1146			$(
1147				`.revx-campaign-${ campaignId } .revx-selected-product-container`
1148			).addClass( 'revx-empty-selected-items' );
1149			$(
1150				`.revx-campaign-${ campaignId } .revx-empty-mix-match`
1151			).removeClass( 'revx-d-none' );
1152			$( this ).addClass( 'revx-d-none' );
1153		}
1154
1155		updateMixMatchHeaderAndPrices(
1156			campaignId,
1157			prevSelectedItems,
1158			jsonQtyData
1159		);
1160	}
1161	$( '[data-container-level="mix_match_file"]' ).on(
1162		'click',
1163		'[data-mix-match-reset-btn]',
1164		resetMixMatchSelectedItem
1165	);
1166
1167	function setTierState( $tier, tierClass, checkboxClass, isChecked ) {
1168		$tier.addClass( tierClass.add ).removeClass( tierClass.remove );
1169		const $checkboxContainer = $tier.find( '.revx-checkbox-container' );
1170		$checkboxContainer
1171			.addClass( checkboxClass.add )
1172			.removeClass( checkboxClass.remove )
1173			.attr( 'data-is-checked', isChecked ? 'yes' : 'no' )
1174			.css( 'display', isChecked ? '' : 'none' ); // Ensure visibility based on state
1175	}
1176
1177	function updateMixMatchHeaderAndPrices(
1178		campaignId,
1179		prevData,
1180		jsonQtyData = {}
1181	) {
1182		const header = $(
1183			`.revx-campaign-${ campaignId } .revx-price-container`
1184		);
1185		const itemCounts = Object.keys( prevData ).length;
1186		let $selectedTier = null;
1187		$( '.revx-tier-button' ).each( function () {
1188			// Extract the item count from the mix-match-title text
1189			const titleText = $( this )
1190				.find( '.revx-mix-match-title' )
1191				.text()
1192				.trim();
1193			const itemCount = parseInt( titleText.split( ' ' )[ 0 ], 10 ); // Extract number from "X item"
1194
1195			if ( itemCounts >= itemCount ) {
1196				$selectedTier = $( this );
1197			}
1198		} );
1199		const selectedClass = {
1200			tierClass: {
1201				add: 'revx-tier-selected',
1202				remove: 'revx-tier-regular',
1203			},
1204			checkboxClass: {
1205				add: 'revx-active',
1206				remove: 'revx-inactive revx-d-none',
1207			},
1208		};
1209		const unselectedClass = {
1210			tierClass: {
1211				add: 'revx-tier-regular',
1212				remove: 'revx-tier-selected',
1213			},
1214			checkboxClass: {
1215				add: 'revx-inactive revx-d-none',
1216				remove: 'revx-active',
1217			},
1218		};
1219		// Update tier button styles based on selection
1220		$( '.revx-tier-button' ).each( function () {
1221			if ( $selectedTier && $( this ).is( $selectedTier ) ) {
1222				setTierState(
1223					$( this ),
1224					selectedClass.tierClass,
1225					selectedClass.checkboxClass,
1226					true
1227				);
1228			} else {
1229				setTierState(
1230					$( this ),
1231					unselectedClass.tierClass,
1232					unselectedClass.checkboxClass,
1233					false
1234				);
1235			}
1236		} );
1237		const qtyData = $( `input[name=revx-qty-data-${ campaignId }]` ).val();
1238		jsonQtyData = qtyData ? JSON.parse( qtyData ) : [];
1239
1240		header.toggleClass( 'revx-d-none', ! itemCounts ); // remove none if more than 0, adds none when item count is 0
1241
1242		// const addToCart = $(`.revx-campaign-add-to-cart-btn[data-campaign-id=${campaign_id}]`);
1243		// if(item_counts==0 && !addToCart.hasClass('revx-d-none') ) {
1244		//     $(`.revx-campaign-add-to-cart-btn[data-campaign-id=${campaign_id}]`).addClass('revx-d-none');
1245		// } else if(item_counts>0) {
1246		//     $(`.revx-campaign-add-to-cart-btn[data-campaign-id=${campaign_id}]`).removeClass('revx-d-none');
1247		// }
1248		header.find( '.revx-selected-product-count' ).html( itemCounts );
1249
1250		let totalRegularPrice = 0;
1251		let totalSalePrice = 0;
1252		let totalQuantity = 0;
1253		Object.values( prevData ).forEach( ( item ) => {
1254			totalRegularPrice +=
1255				parseFloat( item.regularPrice ) * parseInt( item.quantity );
1256			totalQuantity += parseInt( item.quantity );
1257		} );
1258
1259		let selectedIndex = -1;
1260		jsonQtyData.forEach( ( item, idx ) => {
1261			if ( itemCounts >= item.quantity ) {
1262				selectedIndex = idx;
1263
1264				switch ( item.type ) {
1265					case 'percentage':
1266						totalSalePrice =
1267							totalRegularPrice * ( 1 - item.value / 100 );
1268						break;
1269					case 'fixed_discount':
1270						totalSalePrice = Math.max(
1271							0,
1272							parseFloat( totalRegularPrice ) -
1273								parseFloat( item.value * totalQuantity )
1274						);
1275
1276						break;
1277					case 'no_discount':
1278						totalSalePrice = totalRegularPrice;
1279
1280						break;
1281					case 'fixed_price':
1282						totalSalePrice = item.value * totalQuantity;
1283						break;
1284					default:
1285						break;
1286				}
1287			}
1288		} );
1289		// make display none for no_discount, other cases, remove the class
1290		header
1291			.find( '.revx-product-old-price' )
1292			.toggleClass(
1293				'revx-d-none',
1294				jsonQtyData[ selectedIndex ]?.type === 'no_discount' ||
1295					totalSalePrice === 0
1296			);
1297		const that = $(
1298			`.revx-campaign-${ campaignId } .revx-mixmatch-quantity`
1299		);
1300		that.each( function () {
1301			const item = $( this ).find( '.revx-mixmatch-regular-quantity' );
1302
1303			$( item )
1304				.find( '.revx-checkbox-container' )
1305				.addClass( 'revx-d-none' );
1306		} );
1307
1308		const clickedItem = that.find( `div[data-index=${ selectedIndex }]` );
1309		$( clickedItem )
1310			.find( '.revx-checkbox-container' )
1311			.removeClass( 'revx-d-none' );
1312		if ( totalSalePrice === 0 ) {
1313			header
1314				.find( '.revx-campaign-item__sale-price' )
1315				.html( formatPrice( totalRegularPrice ) );
1316		} else {
1317			if (
1318				totalSalePrice &&
1319				header
1320					.find( '.revx-campaign-item__sale-price' )
1321					.hasClass( 'revx-d-none' )
1322			) {
1323				header
1324					.find( '.revx-campaign-item__sale-price' )
1325					.removeClass( 'revx-d-none' );
1326			}
1327			if (
1328				totalRegularPrice &&
1329				header
1330					.find( '.revx-campaign-item__regular-price' )
1331					.hasClass( 'revx-d-none' )
1332			) {
1333				header
1334					.find( '.revx-campaign-item__regular-price' )
1335					.removeClass( 'revx-d-none' );
1336			}
1337
1338			header
1339				.find( '.revx-campaign-item__sale-price' )
1340				.html( formatPrice( totalSalePrice ) );
1341			header
1342				.find( '.revx-product-old-price' )
1343				.html( formatPrice( totalRegularPrice ) );
1344		}
1345	}
1346
1347	// old fbt - available for old campaigns in v1
1348	// Frequently Bought Together
1349	// Function to update the styles based on selection
1350	// function updateStyles( $checkbox, selected ) {
1351	// 	const selectedStyles = $checkbox.data( 'selected-style' );
1352	// 	const defaultStyles = $checkbox.data( 'default-style' );
1353	// 	if ( selected ) {
1354	// 		$checkbox.attr( 'style', selectedStyles );
1355	// 	} else {
1356	// 		$checkbox.attr( 'style', defaultStyles );
1357	// 	}
1358	// }
1359	// $( '.revx-frequently-bought-together' ).on(
1360	// 	'click',
1361	// 	'.revx-item-options .revx-item-option',
1362	// 	function ( e ) {
1363	// 		e.preventDefault();
1364
1365	// 		const $this = $( this );
1366	// 		if ( $this.hasClass( 'revx-item-required' ) ) {
1367	// 			return;
1368	// 		}
1369	// 		const $checkbox = $this.find( '.revx-builder-checkbox' );
1370
1371	// 		const parent = $this.closest( '.revx-campaign-container__wrapper' );
1372
1373	// 		const campaign_id = parent.data( 'campaign-id' );
1374	// 		const cookieName = `campaign_${ campaign_id }`;
1375	// 		let selectedProducts = getCookie( cookieName );
1376	// 		let prevSelectedItems = $(
1377	// 			`input[name=revx-fbt-selected-items-${ campaign_id }]`
1378	// 		).val();
1379	// 		prevSelectedItems = prevSelectedItems
1380	// 			? JSON.parse( prevSelectedItems )
1381	// 			: {};
1382	// 		selectedProducts = selectedProducts
1383	// 			? JSON.parse( selectedProducts )
1384	// 			: {};
1385	// 		if ( Object.keys( selectedProducts ) == 0 ) {
1386	// 			selectedProducts = { ...prevSelectedItems };
1387	// 		}
1388
1389	// 		const productId = $this.data( 'product-id' );
1390
1391	// 		// Toggle the selected state
1392	// 		if ( selectedProducts[ productId ] ) {
1393	// 			// selectedProducts = selectedProducts.filter(id => id !== productId);
1394	// 			delete selectedProducts[ productId ];
1395	// 			updateStyles( $checkbox, false );
1396	// 		} else {
1397	// 			const quantityInput =
1398	// 				$(
1399	// 					`input[name="revx-quantity-${ campaign_id }-${ productId }"]`
1400	// 				).val() ?? $this.data( 'min-quantity' );
1401
1402	// 			selectedProducts[ productId ] = quantityInput;
1403	// 			updateStyles( $checkbox, true );
1404	// 		}
1405	// 		$( `input[name="revx-fbt-selected-items-${ campaign_id }"]` ).val(
1406	// 			JSON.stringify( selectedProducts )
1407	// 		);
1408
1409	// 		// Update the cookie
1410	// 		setCookie( cookieName, JSON.stringify( selectedProducts ), 1 );
1411
1412	// 		fbtCalculation( parent, campaign_id );
1413	// 	}
1414	// );
1415
1416	// const fbtCalculation = ( parent, campaign_id ) => {
1417	// 	const cookieName = `campaign_${ campaign_id }`;
1418	// 	let selectedProducts = getCookie( cookieName );
1419	// 	let prevSelectedItems = $(
1420	// 		`input[name=revx-fbt-selected-items-${ campaign_id }]`
1421	// 	).val();
1422	// 	prevSelectedItems = prevSelectedItems
1423	// 		? JSON.parse( prevSelectedItems )
1424	// 		: {};
1425	// 	selectedProducts = selectedProducts
1426	// 		? JSON.parse( selectedProducts )
1427	// 		: {};
1428	// 	if ( Object.keys( selectedProducts ) == 0 ) {
1429	// 		selectedProducts = { ...prevSelectedItems };
1430	// 	}
1431
1432	// 	const calculateSalePrice = ( data, qty = 1 ) => {
1433	// 		if ( ! data?.type ) {
1434	// 			return data.regular_price * qty;
1435	// 		}
1436	// 		let total = 0;
1437	// 		switch ( data.type ) {
1438	// 			case 'percentage':
1439	// 				total =
1440	// 					parseFloat( data.regular_price ) *
1441	// 					( 1 - data.value / 100 );
1442
1443	// 				break;
1444	// 			case 'amount':
1445	// 			case 'fixed_discount':
1446	// 				total = Math.max(
1447	// 					0,
1448	// 					parseFloat( data.regular_price ) -
1449	// 						parseFloat( data.value )
1450	// 				);
1451
1452	// 				break;
1453	// 			case 'fixed_price':
1454	// 				total = parseFloat( data.value );
1455
1456	// 				break;
1457	// 			case 'no_discount':
1458	// 				total = parseFloat( data.regular_price );
1459
1460	// 				break;
1461	// 			case 'free':
1462	// 				total = 0;
1463
1464	// 				break;
1465
1466	// 			default:
1467	// 				break;
1468	// 		}
1469
1470	// 		return parseFloat( total ) * parseInt( qty );
1471	// 	};
1472	// 	let offerData = $(
1473	// 		`input[name=revx-offer-data-${ campaign_id }]`
1474	// 	).val();
1475
1476	// 	offerData = JSON.parse( offerData );
1477
1478	// 	let totalRegularPrice = 0;
1479	// 	let totalSalePrice = 0;
1480
1481	// 	Object.keys( selectedProducts ).forEach( ( id ) => {
1482	// 		totalRegularPrice +=
1483	// 			parseFloat( offerData[ id ]?.regular_price ) *
1484	// 			parseInt( selectedProducts[ id ] );
1485	// 		totalSalePrice += parseFloat(
1486	// 			calculateSalePrice(
1487	// 				offerData[ id ],
1488	// 				parseInt( selectedProducts[ id ] )
1489	// 			)
1490	// 		);
1491	// 	} );
1492
1493	// 	if ( totalRegularPrice != totalSalePrice ) {
1494	// 		parent
1495	// 			.find(
1496	// 				`.revx-triggerProduct .revx-campaign-item__regular-price`
1497	// 			)
1498	// 			.html( formatPrice( totalRegularPrice ) );
1499	// 		parent
1500	// 			.find( `.revx-triggerProduct .revx-campaign-item__sale-price` )
1501	// 			.html( formatPrice( totalSalePrice ) );
1502	// 	} else {
1503	// 		parent
1504	// 			.find( `.revx-triggerProduct .revx-campaign-item__sale-price` )
1505	// 			.html( formatPrice( totalSalePrice ) );
1506	// 		parent
1507	// 			.find(
1508	// 				`.revx-triggerProduct .revx-campaign-item__regular-price`
1509	// 			)
1510	// 			.html( '' );
1511	// 	}
1512	// 	parent
1513	// 		.find( `.revx-triggerProduct .revx-selected-product-count` )
1514	// 		.html( Object.keys( selectedProducts ).length );
1515	// };
1516
1517	// $( '.revx-frequently-bought-together' ).on(
1518	// 	'change',
1519	// 	'input[data-name=revx_quantity]',
1520	// 	function ( e ) {
1521	// 		e.preventDefault();
1522	// 		const parent = $( this ).closest(
1523	// 			'.revx-campaign-container__wrapper'
1524	// 		);
1525
1526	// 		const quantity = $( this ).val();
1527
1528	// 		const campaign_id = parent.data( 'campaign-id' );
1529
1530	// 		// addFbtRequiredProductsIfNotAdded(campaign_id,false);
1531	// 		const product_id = $( this ).data( 'product-id' );
1532	// 		const cookieName = `campaign_${ campaign_id }`;
1533
1534	// 		let selectedProducts = getCookie( cookieName );
1535	// 		let prevSelectedItems = $(
1536	// 			`input[name=revx-fbt-selected-items-${ campaign_id }]`
1537	// 		).val();
1538	// 		prevSelectedItems = prevSelectedItems
1539	// 			? JSON.parse( prevSelectedItems )
1540	// 			: {};
1541	// 		selectedProducts = selectedProducts
1542	// 			? JSON.parse( selectedProducts )
1543	// 			: {};
1544	// 		if ( Object.keys( selectedProducts ) == 0 ) {
1545	// 			selectedProducts = { ...prevSelectedItems };
1546	// 		}
1547
1548	// 		if ( selectedProducts[ product_id ] ) {
1549	// 			selectedProducts[ product_id ] = quantity;
1550
1551	// 			setCookie( cookieName, JSON.stringify( selectedProducts ), 1 );
1552	// 			fbtCalculation( parent, campaign_id );
1553	// 		}
1554
1555	// 		$( `input[name=revx-fbt-selected-items-${ campaign_id }]` ).val(
1556	// 			JSON.stringify( selectedProducts )
1557	// 		);
1558
1559	// 		const calculateSalePrice = ( data, qty = 1 ) => {
1560	// 			if ( ! data?.type ) {
1561	// 				return data.regular_price * qty;
1562	// 			}
1563	// 			let total = 0;
1564	// 			switch ( data.type ) {
1565	// 				case 'percentage':
1566	// 					total =
1567	// 						parseFloat( data.regular_price ) *
1568	// 						( 1 - data.value / 100 );
1569
1570	// 					break;
1571	// 				case 'amount':
1572	// 				case 'fixed_discount':
1573	// 					total = Math.max(
1574	// 						0,
1575	// 						parseFloat( data.regular_price ) -
1576	// 							parseFloat( data.value )
1577	// 					);
1578
1579	// 					break;
1580	// 				case 'fixed_price':
1581	// 					total = parseFloat( data.value );
1582
1583	// 					break;
1584	// 				case 'no_discount':
1585	// 					total = parseFloat( data.regular_price );
1586
1587	// 					break;
1588	// 				case 'free':
1589	// 					total = 0;
1590
1591	// 					break;
1592
1593	// 				default:
1594	// 					break;
1595	// 			}
1596
1597	// 			return parseFloat( total ) * parseInt( qty );
1598	// 		};
1599	// 		let offerData = $( `input[name=revx-offer-data-${ campaign_id }]` );
1600
1601	// 		offerData = offerData[ 0 ].value;
1602	// 		const jsonData = JSON.parse( offerData );
1603
1604	// 		const salePrice = calculateSalePrice(
1605	// 			jsonData[ product_id ],
1606	// 			quantity
1607	// 		).toFixed( 2 );
1608
1609	// 		const inRP = jsonData[ product_id ].regular_price;
1610
1611	// 		const inSP = ( salePrice / quantity ).toFixed( 2 );
1612
1613	// 		const itemParent = $( this ).closest( '.revx-campaign-item' );
1614
1615	// 		updatePriceDisplay( itemParent, quantity, inSP, inRP );
1616	// 	}
1617	// );
1618
1619	// Buy X Get Y
1620	$( '.revx-buyx-gety' ).on(
1621		'change',
1622		'input[data-name=revx_quantity]',
1623		function ( e ) {
1624			e.preventDefault();
1625			const parent = $( this ).closest( '.revx-campaign-container' );
1626
1627			const quantity = $( this ).val();
1628
1629			const campaign_id = parent.data( 'campaign-id' );
1630
1631			const product_id = $( this ).data( 'product-id' );
1632
1633			let offerData = $( `input[name=revx-offer-data-${ campaign_id }]` );
1634
1635			offerData = offerData[ 0 ].value;
1636			const jsonData = JSON.parse( offerData );
1637
1638			const regularPrice = (
1639				jsonData[ product_id ].regular_price * quantity
1640			).toFixed( 2 );
1641			const salePrice = calculateCurrentPrice(
1642				jsonData,
1643				product_id,
1644				quantity
1645			).toFixed( 2 );
1646
1647			const item = $( this ).closest( '.revx-campaign-item__content' );
1648
1649			item.find( '.revx-campaign-item__regular-price' ).text(
1650				formatPrice( regularPrice )
1651			);
1652			item.find( '.revx-campaign-item__sale-price' ).text(
1653				formatPrice( salePrice )
1654			);
1655
1656			if ( regularPrice == salePrice ) {
1657				if (
1658					! item
1659						.find( '.revx-campaign-item__regular-price' )
1660						.hasClass( 'revx-d-none' )
1661				) {
1662					item.find( '.revx-campaign-item__regular-price' ).addClass(
1663						'revx-d-none'
1664					);
1665				}
1666			} else if (
1667				item
1668					.find( '.revx-campaign-item__regular-price' )
1669					.hasClass( 'revx-d-none' )
1670			) {
1671				item.find( '.revx-campaign-item__regular-price' ).removeClass(
1672					'revx-d-none'
1673				);
1674			}
1675
1676			let totalRegularPrice = 0;
1677			let totalSalePrice = 0;
1678
1679			Object.keys( jsonData ).forEach( ( pid ) => {
1680				const qty = $(
1681					`input[name="revx-quantity-${ campaign_id }-${ pid }"]`
1682				).val();
1683				const rp = ( jsonData[ pid ].regular_price * qty ).toFixed( 2 );
1684				const sp = parseFloat(
1685					calculateCurrentPrice( jsonData, pid, qty ).toFixed( 2 )
1686				);
1687				totalRegularPrice += parseFloat( rp );
1688				totalSalePrice += parseFloat( sp );
1689			} );
1690
1691			parent
1692				.find( '.revx-total-price .revx-campaign-item__regular-price' )
1693				.html( formatPrice( totalRegularPrice ) );
1694			parent
1695				.find( '.revx-total-price .revx-campaign-item__sale-price' )
1696				.html( formatPrice( totalSalePrice ) );
1697		}
1698	);
1699
1700	// Slider -----------------------
1701
1702	function checkOverflow( container ) {
1703		$( container ).each( function () {
1704			const $this = $( this );
1705
1706			const isOverflowing =
1707				$this[ 0 ].scrollWidth > $this[ 0 ].offsetWidth;
1708
1709			if ( isOverflowing ) {
1710				$( this )
1711					.find( '.revx-builderSlider-icon' )
1712					.addClass( 'revx-has-overflow' );
1713			} else {
1714				$( this )
1715					.find( '.revx-builderSlider-icon' )
1716					.removeClass( 'revx-has-overflow' );
1717			}
1718		} );
1719	}
1720
1721	// function initializeSlider(
1722	// 	$sliderContainer,
1723	// 	$containerSelector = '.revx-inpage-container',
1724	// 	$campaign_type = ''
1725	// ) {
1726	// 	const $container = $sliderContainer.closest( $containerSelector );
1727	// 	const containerElement = $container.get( 0 );
1728	// 	const computedStyle = getComputedStyle( containerElement );
1729	// 	const gridColumnValue = computedStyle
1730	// 		.getPropertyValue( '--revx-grid-column' )
1731	// 		.trim();
1732	// 	let itemGap = parseInt(
1733	// 		computedStyle.getPropertyValue( 'gap' ).trim()
1734	// 	);
1735
1736	// 	if ( ! itemGap ) {
1737	// 		itemGap = 16;
1738	// 	}
1739
1740	// 	const $slides = $sliderContainer.find( '.revx-campaign-item' );
1741	// 	const minSlideWidth = 100; // 12rem in pixels (assuming 1rem = 16px)
1742
1743	// 	let containerWidth = $sliderContainer.parent().width();
1744
1745	// 	if ( $campaign_type == 'mix_match' ) {
1746	// 		containerWidth = $sliderContainer
1747	// 			.closest( '.revx-slider-items-wrapper' )
1748	// 			.innerWidth();
1749	// 	}
1750	// 	if ( $campaign_type == 'bundle_discount' ) {
1751	// 		containerWidth = $sliderContainer
1752	// 			.closest( '.revx-slider-items-wrapper' )
1753	// 			.outerWidth();
1754	// 		itemGap = 0;
1755	// 	}
1756	// 	if ( $campaign_type == 'fbt' ) {
1757	// 		containerWidth = $container
1758	// 			.find( '.revx-slider-items-wrapper' )
1759	// 			.innerWidth();
1760	// 	}
1761	// 	if ( $campaign_type == 'normal_discount' ) {
1762	// 		containerWidth = $container
1763	// 			.closest( '.revx-slider-items-wrapper' )
1764	// 			.innerWidth();
1765	// 		itemGap = 0;
1766	// 	}
1767
1768	// 	let slidesVisible = Math.min(
1769	// 		gridColumnValue,
1770	// 		Math.floor( containerWidth / minSlideWidth )
1771	// 	); // Calculate initial slides visible
1772
1773	// 	let slideWidth = containerWidth / slidesVisible;
1774	// 	slideWidth -= itemGap;
1775
1776	// 	if ( $campaign_type == 'bundle_discount' ) {
1777	// 		slideWidth -= $container
1778	// 			.find( '.revx-builder__middle_element' )
1779	// 			.width();
1780	// 	}
1781
1782	// 	const totalSlides = $slides.length;
1783	// 	let slideIndex = 0;
1784
1785	// 	function updateSlideWidth() {
1786	// 		containerWidth = $sliderContainer
1787	// 			.closest( '.revx-slider-items-wrapper' )
1788	// 			.innerWidth();
1789
1790	// 		slidesVisible = Math.min(
1791	// 			gridColumnValue,
1792	// 			Math.floor( containerWidth / minSlideWidth )
1793	// 		); // Recalculate slides visible
1794	// 		slideWidth = containerWidth / slidesVisible;
1795	// 		slideWidth -= itemGap;
1796
1797	// 		if ( $campaign_type == 'bundle_discount' ) {
1798	// 			slideWidth -= $sliderContainer
1799	// 				.find( '.revx-builder__middle_element' )
1800	// 				.width();
1801	// 		}
1802
1803	// 		$slides.css( 'width', slideWidth + 'px' );
1804
1805	// 		moveToSlide( slideIndex );
1806	// 	}
1807
1808	// 	setTimeout( () => {
1809	// 		updateSlideWidth();
1810	// 	} );
1811
1812	// 	function moveToSlide( index ) {
1813	// 		let tempWidth = slideWidth;
1814	// 		if ( $campaign_type == 'fbt' ) {
1815	// 			tempWidth += $sliderContainer
1816	// 				.find( '.revx-product-bundle' )
1817	// 				.width();
1818	// 		}
1819	// 		if ( $campaign_type == 'bundle_discount' ) {
1820	// 			tempWidth += $sliderContainer
1821	// 				.find( '.revx-builder__middle_element' )
1822	// 				.width();
1823	// 		}
1824	// 		if ( $campaign_type == 'mix_match' ) {
1825	// 			tempWidth += itemGap;
1826	// 		}
1827	// 		const offset = -tempWidth * index;
1828
1829	// 		$sliderContainer.css( {
1830	// 			transition: 'transform 0.5s ease-in-out',
1831	// 			transform: `translateX(${ offset }px)`,
1832	// 		} );
1833	// 	}
1834
1835	// 	function moveToNextSlide() {
1836	// 		slideIndex++;
1837
1838	// 		if ( slideIndex > totalSlides - slidesVisible ) {
1839	// 			slideIndex = 0;
1840	// 		}
1841
1842	// 		moveToSlide( slideIndex );
1843	// 	}
1844
1845	// 	function moveToPrevSlide() {
1846	// 		slideIndex--;
1847
1848	// 		if ( slideIndex < 0 ) {
1849	// 			slideIndex = totalSlides - slidesVisible;
1850	// 		}
1851
1852	// 		moveToSlide( slideIndex );
1853	// 	}
1854
1855	// 	$sliderContainer
1856	// 		.siblings( '.revx-builderSlider-right' )
1857	// 		.click( function () {
1858	// 			if ( ! $sliderContainer.is( ':animated' ) ) {
1859	// 				moveToNextSlide();
1860	// 			}
1861	// 		} );
1862
1863	// 	$sliderContainer
1864	// 		.siblings( '.revx-builderSlider-left' )
1865	// 		.click( function () {
1866	// 			if ( ! $sliderContainer.is( ':animated' ) ) {
1867	// 				moveToPrevSlide();
1868	// 			}
1869	// 		} );
1870
1871	// 	setTimeout( () => {
1872	// 		// // const initialWidth = $sliderContainer.width();
1873	// 		// $sliderContainer.width(containerWidth + 1); // Increase width by 1px
1874	// 		// $sliderContainer.width(containerWidth); // Reset to original width
1875	// 		$sliderContainer.parent().width( containerWidth ); // Reset to original width
1876	// 		$sliderContainer.parent().width( containerWidth + 1 ); // Reset to original width
1877	// 		$( window ).trigger( 'resize' ); // Trigger window resize
1878	// 	} );
1879
1880	// 	$( window ).resize( function () {
1881	// 		updateSlideWidth();
1882	// 	} );
1883
1884	// 	$sliderContainer
1885	// 		.closest( '.revx-inpage-container' )
1886	// 		.css( 'visibility', 'visible' );
1887	// }
1888
1889	// function buxXGetYSlider() {
1890	// 	$( '.revx-inpage-container.revx-buyx-gety-grid' ).each( function () {
1891	// 		const $container = $( this ).find(
1892	// 			'.revx-campaign-container__wrapper'
1893	// 		);
1894	// 		const containerElement = $container.get( 0 );
1895	// 		const computedStyle = getComputedStyle( containerElement );
1896
1897	// 		let gridColumnValue = parseInt(
1898	// 			computedStyle.getPropertyValue( '--revx-grid-column' ).trim()
1899	// 		);
1900	// 		const minSlideWidth = 132; // 12rem in pixels (assuming 1rem = 16px)
1901
1902	// 		const $triggerItemContainer = $container.find(
1903	// 			'.revx-bxgy-trigger-items'
1904	// 		);
1905	// 		const $offerItemContainer = $container.find(
1906	// 			'.revx-bxgy-offer-items'
1907	// 		);
1908
1909	// 		let triggerItemColumn = parseInt(
1910	// 			getComputedStyle( $triggerItemContainer.get( 0 ) )
1911	// 				.getPropertyValue( '--revx-grid-column' )
1912	// 				.trim()
1913	// 		);
1914	// 		let offerItemColumn = parseInt(
1915	// 			getComputedStyle( $offerItemContainer.get( 0 ) )
1916	// 				.getPropertyValue( '--revx-grid-column' )
1917	// 				.trim()
1918	// 		);
1919
1920	// 		let containerWidth = $container.width();
1921
1922	// 		const seperatorWidth = $container
1923	// 			.find( '.revx-product-bundle' )
1924	// 			.width();
1925
1926	// 		containerWidth -= seperatorWidth - 16;
1927
1928	// 		gridColumnValue = gridColumnValue ? gridColumnValue : 4;
1929
1930	// 		gridColumnValue = Math.min(
1931	// 			gridColumnValue,
1932	// 			Math.floor( containerWidth / minSlideWidth )
1933	// 		);
1934	// 		triggerItemColumn = Math.min(
1935	// 			$triggerItemContainer.find( '.revx-campaign-item' ).length,
1936	// 			triggerItemColumn
1937	// 		);
1938	// 		offerItemColumn = Math.min(
1939	// 			$offerItemContainer.find( '.revx-campaign-item' ).length,
1940	// 			offerItemColumn
1941	// 		);
1942
1943	// 		gridColumnValue = Math.min(
1944	// 			gridColumnValue,
1945	// 			triggerItemColumn + offerItemColumn
1946	// 		);
1947
1948	// 		// gridColumnValue = gridColumnValue ? gridColumnValue : 4;
1949
1950	// 		// Ensure the total columns for trigger and offer items do not exceed the available grid columns
1951	// 		if ( triggerItemColumn + offerItemColumn > gridColumnValue ) {
1952	// 			const excessColumns =
1953	// 				triggerItemColumn + offerItemColumn - gridColumnValue;
1954
1955	// 			// Adjust columns proportionally to ensure total columns match gridColumnValue
1956	// 			const triggerAdjustment = Math.floor(
1957	// 				( triggerItemColumn /
1958	// 					( triggerItemColumn + offerItemColumn ) ) *
1959	// 					excessColumns
1960	// 			);
1961	// 			const offerAdjustment = excessColumns - triggerAdjustment;
1962
1963	// 			triggerItemColumn -= triggerAdjustment;
1964	// 			offerItemColumn -= offerAdjustment;
1965	// 		}
1966
1967	// 		const slideWidth = containerWidth / gridColumnValue;
1968
1969	// 		initializeSubSlider(
1970	// 			$triggerItemContainer,
1971	// 			triggerItemColumn,
1972	// 			slideWidth,
1973	// 			'trigger'
1974	// 		);
1975	// 		initializeSubSlider(
1976	// 			$offerItemContainer,
1977	// 			offerItemColumn,
1978	// 			slideWidth,
1979	// 			'offer'
1980	// 		);
1981
1982	// 		$( this ).css( 'visibility', 'visible' );
1983	// 	} );
1984	// }
1985
1986	// function initializeSubSlider(
1987	// 	$sliderContainer,
1988	// 	itemColumn,
1989	// 	slideWidth,
1990	// 	type
1991	// ) {
1992	// 	const $container = $sliderContainer.find( '.revx-slider-container' );
1993	// 	const itemGap = parseInt(
1994	// 		getComputedStyle( $container.get( 0 ) )
1995	// 			.getPropertyValue( 'gap' )
1996	// 			.trim()
1997	// 	);
1998
1999	// 	// slideWidth -=itemGap;
2000	// 	slideWidth -= itemGap;
2001	// 	const containerWidth = itemColumn * slideWidth;
2002	// 	$sliderContainer.width( containerWidth );
2003	// 	slideWidth -= 16;
2004
2005	// 	if ( type == 'offer' ) {
2006	// 		slideWidth += itemGap;
2007	// 	}
2008
2009	// 	$sliderContainer = $container;
2010
2011	// 	const $slides = $sliderContainer.find( '.revx-campaign-item' );
2012	// 	$slides.css( { width: slideWidth + 'px' } );
2013
2014	// 	const totalSlides = $slides.length;
2015	// 	let slideIndex = 0; // Start at the first slide
2016
2017	// 	function moveToSlide( index ) {
2018	// 		let tempWidth = slideWidth;
2019	// 		tempWidth += itemGap + 16;
2020	// 		tempWidth += index;
2021
2022	// 		if ( itemColumn == 1 ) {
2023	// 			tempWidth += itemGap;
2024	// 		}
2025
2026	// 		if ( type == 'offer' ) {
2027	// 			tempWidth -= 16;
2028	// 		}
2029
2030	// 		const offset = -tempWidth * index;
2031
2032	// 		$sliderContainer.css( {
2033	// 			transition: 'transform 0.5s ease-in-out',
2034	// 			transform: `translateX(${ offset }px)`,
2035	// 		} );
2036	// 	}
2037
2038	// 	function moveToNextSlide() {
2039	// 		slideIndex++;
2040	// 		if ( slideIndex > totalSlides - itemColumn ) {
2041	// 			slideIndex = 0;
2042	// 		}
2043	// 		moveToSlide( slideIndex );
2044	// 	}
2045
2046	// 	function moveToPrevSlide() {
2047	// 		slideIndex--;
2048	// 		if ( slideIndex < 0 ) {
2049	// 			slideIndex = totalSlides - itemColumn;
2050	// 		}
2051	// 		moveToSlide( slideIndex );
2052	// 	}
2053
2054	// 	$sliderContainer
2055	// 		.siblings( '.revx-builderSlider-right' )
2056	// 		.click( function () {
2057	// 			if ( ! $sliderContainer.is( ':animated' ) ) {
2058	// 				moveToNextSlide();
2059	// 			}
2060	// 		} );
2061
2062	// 	$sliderContainer
2063	// 		.siblings( '.revx-builderSlider-left' )
2064	// 		.click( function () {
2065	// 			if ( ! $sliderContainer.is( ':animated' ) ) {
2066	// 				moveToPrevSlide();
2067	// 			}
2068	// 		} );
2069
2070	// 	$( window ).resize( function () {
2071	// 		moveToSlide( slideIndex );
2072	// 	} );
2073
2074	// 	moveToSlide( slideIndex );
2075	// }
2076
2077	// buxXGetYSlider();
2078
2079	// $( window ).resize( function () {
2080	// 	buxXGetYSlider();
2081	// } );
2082
2083	// $(
2084	// 	'.revx-inpage-container.revx-normal-discount-grid .revx-slider-container'
2085	// ).each( function () {
2086	// 	initializeSlider(
2087	// 		$( this ),
2088	// 		'.revx-campaign-view__items',
2089	// 		'normal_discount'
2090	// 	);
2091	// } );
2092	// $(
2093	// 	'.revx-inpage-container.revx-mix-match-grid .revx-slider-container'
2094	// ).each( function () {
2095	// 	initializeSlider(
2096	// 		$( this ),
2097	// 		'.revx-campaign-view__items',
2098	// 		'mix_match'
2099	// 	);
2100	// } );
2101	// $(
2102	// 	'.revx-inpage-container.revx-bundle-discount-grid .revx-slider-container'
2103	// ).each( function () {
2104	// 	initializeSlider(
2105	// 		$( this ),
2106	// 		'.revx-campaign-view__items',
2107	// 		'bundle_discount'
2108	// 	);
2109	// } );
2110	// $(
2111	// 	'.revx-inpage-container.revx-frequently-bought-together-grid .revx-slider-container'
2112	// ).each( function () {
2113	// 	initializeSlider( $( this ), '.revx-inpage-container', 'fbt' );
2114	// } );
2115
2116	// $( window ).on( 'load resize', function () {
2117	// 	checkOverflow( '.revx-slider' );
2118	// } );
2119
2120	// ---------------- Slider
2121
2122	// $('.revx-ticket-type')
2123
2124	$( '.revx-ticket-type' ).change( function () {
2125		const selectedSlug = $( this ).val();
2126		const campaignID = $( this ).data( 'campaign-id' );
2127		const offerQty = $( this ).data( 'quantity' );
2128
2129		const prices = $( this ).data( 'prices' );
2130
2131		$( this )
2132			.closest( '.revx-campaign-item' )
2133			.find( '.revx-total-ticket-price' )
2134			.text(
2135				`Total Price: ${ formatPrice(
2136					prices[ selectedSlug ] * offerQty
2137				) }`
2138			);
2139
2140		const selectedItem = $( this )
2141			.closest( '.revx-volume-discount' )
2142			.find( '.revx-campaign-item[data-revx-selected=true]' );
2143
2144		if ( selectedItem.length ) {
2145			// Check if the selectedItem exists
2146			// selectedItem.data('data-selected-ticket', selectedSlug);
2147			selectedItem.attr( 'data-selected-ticket', selectedSlug );
2148			selectedItem.attr(
2149				'data-selected-ticket-price',
2150				prices[ selectedSlug ] * offerQty
2151			);
2152		}
2153	} );
2154
2155	$( '.revx-ticket-type' ).trigger( 'change' );
2156
2157	// Tooltip - Spending Goal
2158	function updateTooltipPosition( $container ) {
2159		const $tooltip = $container.find( '.revx-gift-tooltip' );
2160		if ( ! $tooltip.length ) {
2161			return;
2162		}
2163
2164		const containerRect = $container[ 0 ].getBoundingClientRect();
2165		const tooltipRect = $tooltip[ 0 ].getBoundingClientRect();
2166		const windowHeight = $( window ).height();
2167		const windowWidth = $( window ).width();
2168
2169		// Calculate available space
2170		const spaceAbove = containerRect.top;
2171		const spaceBelow = windowHeight - containerRect.bottom;
2172
2173		// Determine position (top or bottom)
2174		const position = spaceAbove > spaceBelow ? 'top' : 'bottom';
2175		$tooltip.attr( 'data-position', position );
2176
2177		// Handle horizontal overflow
2178		const tooltipWidth = $tooltip.outerWidth();
2179		const containerCenterX = containerRect.left + containerRect.width / 2;
2180		const spaceLeft = containerCenterX;
2181		const spaceRight = windowWidth - containerCenterX;
2182
2183		if ( tooltipWidth / 2 > spaceLeft ) {
2184			// Not enough space on the left
2185			$tooltip.css( {
2186				left: '0',
2187				transform: 'translateX(0)',
2188			} );
2189		} else if ( tooltipWidth / 2 > spaceRight ) {
2190			// Not enough space on the right
2191			$tooltip.css( {
2192				left: 'auto',
2193				right: '0',
2194				transform: 'translateX(0)',
2195			} );
2196		} else {
2197			// Center aligned
2198			$tooltip.css( {
2199				// left: '50%',
2200				right: 'auto',
2201				transform: 'translateX(-50%)',
2202			} );
2203		}
2204	}
2205
2206	// Handle mouse enter
2207	$( '.revx-step-icon-container' ).on( 'mouseenter', function () {
2208		updateTooltipPosition( $( this ) );
2209	} );
2210
2211	// Update positions on window resize
2212	let resizeTimer;
2213	$( window ).on( 'resize', function () {
2214		clearTimeout( resizeTimer );
2215		resizeTimer = setTimeout( function () {
2216			$( '.revx-step-icon-container:hover' ).each( function () {
2217				updateTooltipPosition( $( this ) );
2218			} );
2219		}, 250 );
2220	} );
2221
2222	function updateGiftPosition( $container ) {
2223		const $gift = $container.find( '.revx-gift-container' );
2224		const $giftWrapper = $container.find( '.revx-spending-gift' );
2225		if ( ! $gift.length ) {
2226			return;
2227		}
2228		// remove the class before. otherwise top calculation is wrong.
2229		$gift.removeClass( 'revx-d-none' );
2230
2231		const iconRect = $container[ 0 ].getBoundingClientRect(); // relative to viewport
2232		const giftRect = $gift[ 0 ].getBoundingClientRect();
2233
2234		const giftWidth = giftRect?.width;
2235		const iconWidth = iconRect?.width;
2236		const windowWidth = window.innerWidth;
2237		const giftCenterToLeft = Math.abs( giftWidth - iconWidth ) / 2;
2238
2239		const isAbove = iconRect?.top > giftRect?.height + 10;
2240		const isRightSpace = iconRect?.left + giftCenterToLeft < windowWidth;
2241		const isLeftSpace = iconRect?.left - giftCenterToLeft >= 0;
2242
2243		const top = isAbove
2244			? ( giftRect?.height + 8 ) * -1
2245			: iconRect?.height + 8;
2246
2247		let left = 0;
2248		if ( ! isLeftSpace && isRightSpace ) {
2249			left = -20; // small offset from left edge
2250		} else if ( isLeftSpace && ! isRightSpace ) {
2251			left = iconWidth - giftWidth;
2252		} else {
2253			// for space both left/right OR no space left/right keep center.
2254			left = giftCenterToLeft * -1;
2255		}
2256
2257		$gift.css( {
2258			position: 'fixed',
2259			top: `${ top }px`,
2260			left: `${ left }px`,
2261			zIndex: 999999,
2262			visibility: 'visible',
2263			opacity: 1,
2264		} );
2265		$giftWrapper.css( {
2266			transformOrigin: `${ isAbove ? 'bottom' : 'top' } ${
2267				! isLeftSpace && isRightSpace
2268					? 'left'
2269					: isLeftSpace && ! isRightSpace
2270					? 'right'
2271					: 'center'
2272			}`,
2273		} );
2274	}
2275
2276	// Stock Scarcity
2277	$( '.revx-flip-wrapper' ).each( function () {
2278		const $this = $( this ); // Define $this as the current .revx-flip-wrapper element
2279		const flipTextHeight = $this.find( '.revx-flip-text' ).outerHeight();
2280		$this.css( 'min-height', flipTextHeight + 'px' );
2281	} );
2282
2283	let giftHideTimer;
2284	$( document )
2285		.on( 'mouseenter', '.revx-progress-step-icon-container', function () {
2286			clearTimeout( giftHideTimer ); // prevent hiding
2287			updateGiftPosition( $( this ) );
2288		} )
2289		.on( 'mouseleave', '.revx-progress-step-icon-container', function () {
2290			const $this = $( this );
2291			giftHideTimer = setTimeout( () => {
2292				$this
2293					.find( '.revx-gift-container' )
2294					.addClass( 'revx-d-none' )
2295					.css( {
2296						visibility: 'hidden',
2297						opacity: 0,
2298						left: '-250px', // to handle the overflow x case
2299						top: 'unset',
2300					} );
2301			}, 200 ); // adjust delay as needed
2302		} );
2303
2304	$( document )
2305		.on( 'mouseenter', '.revx-gift-container', function () {
2306			clearTimeout( giftHideTimer ); // prevent hiding
2307		} )
2308		.on( 'mouseleave', '.revx-gift-container', function () {
2309			$( this ).addClass( 'revx-d-none' ).css( {
2310				visibility: 'hidden',
2311				opacity: 0,
2312				left: 'unset',
2313				top: 'unset',
2314			} );
2315		} );
2316
2317	// Reposition gift on resize or scroll
2318	$( window ).on( 'resize scroll', function () {
2319		$( '.revx-progress-step-icon-container:hover' ).each( function () {
2320			updateGiftPosition( $( this ) );
2321		} );
2322	} );
2323
2324	function adjustContentMarginTop() {
2325		// const helloBar = $( '.revx-spending-goal-top' ).length
2326		// 	? $( '.revx-spending-goal-top' )
2327		// 	: $( '.revx-campaign-fsb-top' );
2328		const helloBar = $( '.revx-campaign-top' ).length
2329			? $( '.revx-campaign-top' )
2330			: $( '.revx-campaign-fsb-top' );
2331
2332		// Check if hello bar exists
2333		if ( helloBar.length === 0 ) {
2334			return;
2335		}
2336
2337		const helloBarHeight = helloBar.outerHeight();
2338
2339		// Only adjust if we have a valid height
2340		if ( helloBarHeight ) {
2341			$( 'body' ).css( 'margin-top', helloBarHeight );
2342
2343			// Remove margin-bottom as it's causing double spacing
2344			// helloBar.css( 'margin-top', -helloBarHeight );
2345		}
2346	}
2347
2348	adjustContentMarginTop();
2349	function adjustContentMarginBottom() {
2350		const helloBar = $( '.revx-campaign-bottom' ).length
2351			? $( '.revx-campaign-bottom' )
2352			: $( '.revx-campaign-fsb-bottom' );
2353
2354		// Check if hello bar exists
2355		if ( helloBar.length === 0 ) {
2356			return;
2357		}
2358
2359		const helloBarHeight = helloBar.outerHeight();
2360
2361		// Only adjust if we have a valid height
2362		if ( helloBarHeight ) {
2363			$( 'body' ).css( 'margin-bottom', helloBarHeight );
2364
2365			// Remove margin-bottom as it's causing double spacing
2366			// helloBar.css('margin-bottom', -helloBarHeight);
2367		}
2368	}
2369
2370	adjustContentMarginBottom();
2371
2372	function showToast( message, type = 'success', duration = 3000 ) {
2373		// Check if toast container exists, otherwise create it
2374		let $toastContainer = $( '.revx-toaster-container' );
2375		if ( $toastContainer.length === 0 ) {
2376			$toastContainer = $( '<div class="revx-toaster-container"></div>' );
2377			$( 'body' ).append( $toastContainer );
2378		}
2379
2380		// Determine toast class and icon based on type
2381		const toastClasses = {
2382			success: 'revx-toaster__success',
2383			warning: 'revx-toaster__warning',
2384			error: 'revx-toaster__error',
2385		};
2386
2387		const icon = `
2388				<svg xmlns="http://www.w3.org/2000/svg" width="16px" height="16px" fill="none" viewBox="0 0 16 16" class="revx-toaster__close-icon revx-toaster__icon">
2389					<path stroke="#fff" strokeLinecap="round" strokeLinejoin="round" strokeWidth="1.2" d="m12 4-8 8M4 4l8 8"></path>
2390				</svg>
2391			`;
2392
2393		// Create a new toast element as a jQuery object
2394		const $toast = $( `
2395			<div class="revx-toaster revx-justify-space revx-toaster-lg ${ toastClasses[ type ] }" style="display: flex;">
2396				<div class="revx-paragraph--xs revx-align-center-xs">
2397					${ message }
2398				</div>
2399				<div class="revx-paragraph--xs revx-align-center">
2400					${ icon }
2401				</div>
2402			</div>
2403		` );
2404
2405		// Add close button functionality
2406		$toast.find( '.revx-toaster__close-icon' ).on( 'click', function () {
2407			$toast.fadeOut( 400, function () {
2408				$( this ).remove(); // Remove the toast from DOM
2409			} );
2410		} );
2411
2412		// Append the toast to the toast container
2413		$toastContainer.append( $toast );
2414
2415		// Show the toast
2416		$toast.fadeIn( 400 );
2417
2418		// Set timeout to hide the toast after the specified duration
2419		setTimeout( function () {
2420			if ( $toast.is( ':visible' ) ) {
2421				// Only remove if still visible
2422				$toast.fadeOut( 400, function () {
2423					$( this ).remove(); // Remove the toast from DOM
2424				} );
2425			}
2426		}, duration );
2427	}
2428
2429	const $drawerContainer = $( '.revx-drawer-container' ).first();
2430	if ( $drawerContainer.length ) {
2431		// Clone the entire container including content
2432		// const $drawerContent = $drawerContainer.find( '.revx-drawer-content' );
2433		// $drawerContent.each( function () {
2434		// 	this.style.setProperty( 'max-width', '0vh', 'important' );
2435		// 	this.style.setProperty( 'padding', '0vh', 'important' );
2436		// } );
2437
2438		const $clone = $drawerContainer.clone( true, true );
2439		const $cloneContent = $clone.find( '.revx-drawer-content' );
2440		// Remove max-width and padding limits on drawer-content inside clone
2441		$cloneContent.each( function () {
2442			this.style.setProperty( 'max-width', 'none', 'important' );
2443			this.style.setProperty(
2444				'padding-top',
2445				'var(--revx-drawer-padding-top)',
2446				'important'
2447			);
2448			this.style.setProperty(
2449				'padding-right',
2450				'var(--revx-drawer-padding-right)',
2451				'important'
2452			);
2453			this.style.setProperty(
2454				'padding-bottom',
2455				'var(--revx-drawer-padding-bottom)',
2456				'important'
2457			);
2458			this.style.setProperty(
2459				'padding-left',
2460				'var(--revx-drawer-padding-left)',
2461				'important'
2462			);
2463			// this.style.setProperty( 'position', 'static', 'important' );
2464		} );
2465		// $cloneContent.find( '*' ).each( function () {
2466		// 	this.style.setProperty( 'position', 'static', 'important' );
2467		// } );
2468
2469		$clone.css( {
2470			display: 'flex',
2471			position: 'absolute',
2472			top: '-9999px',
2473			left: '-9999px',
2474			visibility: 'hidden',
2475			bottom: 'unset',
2476			right: 'unset',
2477		} );
2478		// Append clone to body so you can see it on top
2479		$( 'body' ).append( $clone );
2480		const cloneHeight = $clone.innerHeight();
2481		// const cloneHeight = $clone.outerHeight( true );
2482		$drawerContainer.each( function () {
2483			this.style.setProperty( 'height', cloneHeight + 'px', 'important' );
2484			this.style.setProperty( 'display', 'flex', 'important' );
2485		} );
2486	}
2487
2488	// Open campaign drawer
2489	$( document ).on( 'click', '.revx-drawer-opener', function () {
2490		const $container = $( this ).closest( '.revx-drawer-container' );
2491		const $drawerContent = $container.find( '.revx-drawer-content' );
2492
2493		// $drawerContent.each( function () {
2494		// 	this.style.setProperty( 'transition', 'all 0.2s', 'important' );
2495		// } );
2496		$drawerContent.addClass( 'revx-transition' );
2497
2498		if ( $container.hasClass( 'revx-active' ) ) {
2499			$container.removeClass( 'revx-active' );
2500			$container.css( { overflow: 'hidden' } );
2501			// $drawerContent.each( function () {
2502			// 	this.style.setProperty( 'max-width', '0vh', 'important' );
2503			// 	this.style.setProperty( 'padding', '0vh', 'important' );
2504			// } );
2505		} else {
2506			$container.addClass( 'revx-active' );
2507			$container.css( { overflow: 'visible' } );
2508			// $drawerContent.each( function () {
2509			// 	this.style.removeProperty( 'max-width' );
2510			// 	this.style.removeProperty( 'padding' );
2511			// } );
2512		}
2513	} );
2514	// Close campaign drawer
2515	$( document ).on( 'click', '.revx-drawer-closer', function () {
2516		const $container = $( this ).closest( '.revx-drawer-container' );
2517		// const $drawerContent = $container.find( '.revx-drawer-content' );
2518		$container.removeClass( 'revx-active' );
2519		// $drawerContent.each( function () {
2520		// 	this.style.setProperty( 'max-width', '0vh', 'important' );
2521		// 	this.style.setProperty( 'padding', '0vh', 'important' );
2522		// } );
2523	} );
2524
2525	// Hide Campaign on Close Button Click
2526	$( document ).on( 'click', '.revx-campaign-close', function () {
2527		const campaignID = $( this ).data( 'campaign-id' );
2528		$( `.revx-campaign-${ campaignID }` ).hide();
2529		$( 'body' ).css( 'margin-bottom', 0 );
2530		$( 'body' ).css( 'margin-top', 0 );
2531	} );
2532
2533	// Next Order Coupon Copy Clip-Borad
2534	$( '.revx-coupon-copy-btn' ).on( 'click', function () {
2535		const $btn = $( this );
2536
2537		// // const $content = $btn.closest( '.revx-Coupon-button' );
2538		// const text = $content
2539		// 	.clone() // Clone to avoid modifying original
2540		// 	.children() // Remove children (like .revx-coupon-copy-btn)
2541		// 	.remove()
2542		// 	.end() // Go back to cloned parent
2543		// 	.text()
2544		// 	.trim(); // Get just the raw text
2545
2546		const $content = $btn.siblings( '.revx-coupon-value' );
2547		const text = $content.text().trim();
2548
2549		// Fallback for browsers that do not support navigator.clipboard
2550		const tempInput = $( '<input>' );
2551		$( 'body' ).append( tempInput );
2552		tempInput.val( text ).select();
2553		try {
2554			document.execCommand( 'copy' );
2555			// $btn.text( 'Copied!' );
2556			$( '.revx-coupon-value' ).css( 'background-color', '#008000' );
2557			$( '.revx-coupon-value' ).css( {
2558				transition: 'background-color 0.4s',
2559			} );
2560
2561			setTimeout(
2562				() =>
2563					$( '.revx-coupon-value' ).css(
2564						'background-color',
2565						'unset'
2566					),
2567				400
2568			);
2569		} catch ( err ) {
2570			console.error( 'Fallback: Failed to copy:', err );
2571		}
2572		tempInput.remove();
2573	} );
2574
2575	window.Revenue = {
2576		getCookie,
2577		setCookie,
2578		calculateCurrentPrice,
2579		formatPrice,
2580		updatePriceDisplay,
2581		updateMixMatchHeaderAndPrices,
2582		// fbtCalculation,
2583		// updateStyles,
2584		showToast,
2585	};
2586	// eslint-disable-next-line no-undef
2587
2588	$( '.revx-slider-wrapper' ).each( function () {
2589		if ( ! $( this ).data( 'slider-initialized' ) ) {
2590			$( this ).revxSlider();
2591			$( this ).data( 'slider-initialized', true );
2592		}
2593	} );
2594
2595	// Auto initialize on page load
2596	// function initTimers( $context ) {
2597	// 	$context.find( '.revx-countdown-timer' ).revxCountdownTimer();
2598	// }
2599
2600	// $( document ).ready( function () {
2601	// 	initTimers( $( document ) );
2602
2603	// 	// MutationObserver for dynamically added timers
2604	// 	const observer = new MutationObserver( function ( mutations ) {
2605	// 		mutations.forEach( function ( mutation ) {
2606	// 			$( mutation.addedNodes ).each( function () {
2607	// 				if ( this.nodeType === 1 ) {
2608	// 					const $el = $( this );
2609	// 					if ( $el.is( '.revx-countdown-timer' ) ) {
2610	// 						$el.revxCountdownTimer();
2611	// 					} else {
2612	// 						initTimers( $el );
2613	// 					}
2614	// 				}
2615	// 			} );
2616	// 		} );
2617	// 	} );
2618
2619	// 	observer.observe( document.body, {
2620	// 		childList: true,
2621	// 		subtree: true,
2622	// 	} );
2623	// } );
2624
2625	function getSelectedAttributes( $form ) {
2626		const selectedData = {};
2627		$form.find( 'select[name^="attribute_"]' ).each( function () {
2628			const key = $( this ).attr( 'name' );
2629			selectedData[ key ] = $( this ).val() || '';
2630		} );
2631		return selectedData;
2632	}
2633
2634	// Update data-selected-value when any attribute dropdown changes
2635	$( '.product' ).on( 'change', 'select[name^="attribute_"]', function () {
2636		const $form = $( this ).closest( '.product' );
2637		const selectedData = getSelectedAttributes( $form );
2638		// Update the data-selected-value attribute
2639		$form.attr( 'data-selected-value', JSON.stringify( selectedData ) );
2640	} );
2641} )( jQuery );
2642
2643// move jquery code from the template1 volume discount selection.
2644jQuery( function ( $ ) {
2645	$( document ).on( 'click', '.revx-volume-discount-item', function () {
2646		const $radio = $( this ).find( '.revx-radio-wrapper' );
2647		const $attribute = $( this ).find( '.revx-volume-attributes' );
2648
2649		// deactivate every other option
2650		$( '.revx-radio-wrapper, .revx-volume-attributes' )
2651			.removeClass( 'revx-active' )
2652			.addClass( 'revx-inactive' );
2653
2654		// activate the clicked one
2655		$radio
2656			.add( $attribute )
2657			.addClass( 'revx-active' )
2658			.removeClass( 'revx-inactive' );
2659	} );
2660} );

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.