PageSourceSearch

https://rezervacijos.goda.lt/Assets/Web/js/coupon-purchase.js?v=6ac7b3528440d

js goda.lt collected 2026-10-08 15:15:07 UTC 12,166 bytes, 421 lines download raw bytes

1/**
2 * Coupon Purchase Form Handler
3 * Handles amount selection, custom input toggle, and form validation
4 */
5
6window._couponTurnstileVerified = false;
7window.onCouponTurnstileSuccess = function(token) { window._couponTurnstileVerified = true; $('#coupon-turnstile-error').hide(); };
8window.onCouponTurnstileExpired = function() { window._couponTurnstileVerified = false; };
9window.onCouponTurnstileError = function() { window._couponTurnstileVerified = false; };
10
11$(document).ready(function() {
12	// Only run if we're on the coupon page
13	if (!$('#couponForm').length) return;
14
15	// Sticky Steps Navigation Handler
16	const stepsBar = $('#stepsSummaryBar');
17	const stepsBarOffset = stepsBar.length ? stepsBar.offset().top : 0;
18	const stepsBarHeight = stepsBar.length ? stepsBar.outerHeight() : 0;
19	const infoSidebar = $('.coupon-info-sidebar');
20	let currentStep = 1;
21	let stickyPlaceholder = null;
22
23	// Handle scroll for sticky navigation
24	function handleStickySteps() {
25		if (!stepsBar.length) return;
26
27		const scrollTop = $(window).scrollTop();
28
29		if (scrollTop > stepsBarOffset) {
30			if (!stepsBar.hasClass('sticky')) {
31				stepsBar.addClass('sticky');
32
33				// Create placeholder to prevent content jump
34				if (!stickyPlaceholder) {
35					stickyPlaceholder = $('<div class="sticky-placeholder"></div>');
36					stickyPlaceholder.css('height', stepsBarHeight + 'px');
37					stepsBar.after(stickyPlaceholder);
38				}
39
40				// Adjust sidebar top position to account for sticky bar
41				if (infoSidebar.length) {
42					const stickyBarHeight = stepsBar.outerHeight();
43					infoSidebar.css('top', (stickyBarHeight + 20) + 'px');
44				}
45			}
46		} else {
47			stepsBar.removeClass('sticky');
48
49			// Remove placeholder
50			if (stickyPlaceholder) {
51				stickyPlaceholder.remove();
52				stickyPlaceholder = null;
53			}
54
55			// Reset sidebar top position
56			if (infoSidebar.length) {
57				infoSidebar.css('top', '20px');
58			}
59		}
60	}
61
62	// Update step progress based on scroll position
63	function updateStepProgress() {
64		const scrollTop = $(window).scrollTop();
65		const windowHeight = $(window).height();
66
67		// Find which step is currently in view
68		$('.step-number-circle').each(function(index) {
69			const stepElement = $(this).closest('.mb-4');
70			if (stepElement.length) {
71				const stepTop = stepElement.offset().top;
72				const stepBottom = stepTop + stepElement.outerHeight();
73				const viewportMiddle = scrollTop + (windowHeight / 3);
74
75				if (viewportMiddle >= stepTop && viewportMiddle < stepBottom) {
76					const newStep = index + 1;
77					if (newStep !== currentStep) {
78						currentStep = newStep;
79						markStepAsActive(currentStep);
80					}
81				}
82			}
83		});
84	}
85
86	// Mark step as active and previous steps as completed
87	function markStepAsActive(stepNumber) {
88		$('.summary-item').each(function() {
89			const itemStep = parseInt($(this).data('step'));
90
91			$(this).removeClass('active completed');
92
93			if (itemStep < stepNumber) {
94				$(this).addClass('completed');
95			} else if (itemStep === stepNumber) {
96				$(this).addClass('active');
97			}
98		});
99	}
100
101	// Initialize on page load
102	handleStickySteps();
103	updateStepProgress();
104
105	// Handle scroll events
106	$(window).on('scroll', function() {
107		handleStickySteps();
108		updateStepProgress();
109	});
110
111	// Gift checkbox toggle - show/hide receiver section
112	const isGiftCheckbox = $('#is_gift');
113	const receiverSection = $('#receiverSection');
114	const customerNameInput = $('#customer_name');
115	const customerEmailInput = $('#customer_email');
116
117	if (isGiftCheckbox.length && receiverSection.length) {
118		// Set initial state immediately (no animation)
119		if (isGiftCheckbox.prop('checked')) {
120			receiverSection.show();
121			customerNameInput.attr('required', 'required');
122			customerEmailInput.attr('required', 'required');
123		} else {
124			receiverSection.hide();
125			customerNameInput.removeAttr('required');
126			customerEmailInput.removeAttr('required');
127		}
128
129		// Handle checkbox change with animation
130		isGiftCheckbox.on('change', function() {
131			if ($(this).prop('checked')) {
132				receiverSection.slideDown(300);
133				customerNameInput.attr('required', 'required');
134				customerEmailInput.attr('required', 'required');
135			} else {
136				receiverSection.slideUp(300);
137				customerNameInput.removeAttr('required');
138				customerEmailInput.removeAttr('required');
139			}
140		});
141	}
142
143	const customAmountWrapper = $('.custom-amount-input-wrapper');
144	const customAmountInput = $('.custom-amount-input');
145	const amountInfoBox = $('#amountInfoBox');
146	const selectedAmountDisplay = $('#selectedAmountDisplay');
147	
148	// Function to show/hide custom amount input
149	function toggleCustomInput(show) {
150		if (show) {
151			customAmountWrapper.show();
152			setTimeout(function() {
153				customAmountInput.focus();
154			}, 300);
155		} else {
156			customAmountWrapper.hide();
157		}
158	}
159
160	// Function to update amount info box
161	function updateAmountInfoBox(amount) {
162		if (amount > 0) {
163			selectedAmountDisplay.text('€' + amount);
164			amountInfoBox.css('display', 'flex');
165		} else {
166			amountInfoBox.hide();
167		}
168	}
169	
170	// Handle amount type selection
171	$('.amount-type-radio').on('change', function() {
172		const amountType = $(this).val();
173		
174		if (amountType === 'custom') {
175			// Uncheck all preset radios and re-enable them for future selection
176			$('.amount-type-radio[value="preset"]').each(function() {
177				$(this).prop('checked', false).prop('disabled', false);
178			});
179			
180			toggleCustomInput(true);
181			
182			// If custom amount is already filled, show info box
183			const customValue = customAmountInput.val();
184			if (customValue) {
185				updateAmountInfoBox(parseFloat(customValue));
186			} else {
187				updateAmountInfoBox(0);
188			}
189			
190			// Disable all preset amount inputs
191			$('.preset-amount-input').prop('disabled', true);
192		} else {
193			// Uncheck custom radio and re-enable it for future selection
194			$('.amount-type-radio[value="custom"]').prop('checked', false).prop('disabled', false);
195			
196			toggleCustomInput(false);
197			
198			// Clear custom amount value when switching to preset
199			customAmountInput.val('');
200			
201			// Show info box with preset amount
202			const amount = $(this).data('amount');
203			if (amount) {
204				updateAmountInfoBox(parseFloat(amount));
205			}
206			
207			// Update hidden preset amount inputs - enable only the selected one
208			$('.preset-amount-input').each(function() {
209				$(this).prop('disabled', $(this).val() != amount);
210			});
211		}
212	});
213
214	// Handle custom amount input changes
215	customAmountInput.on('input', function() {
216		const amount = parseFloat($(this).val());
217		if (amount > 0) {
218			updateAmountInfoBox(amount);
219		} else {
220			updateAmountInfoBox(0);
221		}
222	});
223
224	customAmountInput.on('focus', function() {
225		// Only auto-select custom if not already selected
226		if (!$('.amount-type-radio[value="custom"]').prop('checked')) {
227			// Uncheck all preset radios and re-enable them
228			$('.amount-type-radio[value="preset"]').each(function() {
229				$(this).prop('checked', false).prop('disabled', false);
230			});
231			// Check custom radio
232			$('.amount-type-radio[value="custom"]').prop('checked', true);
233			// Disable all preset inputs
234			$('.preset-amount-input').prop('disabled', true);
235			toggleCustomInput(true);
236		}
237	});
238
239	// Handle clicking on amount cards to ensure proper radio selection
240	$('.amount-option').on('click', function(e) {
241		const radio = $(this).find('.amount-type-radio');
242		if (radio.length) {
243			// Trigger the radio button if not already checked
244			if (!radio.prop('checked')) {
245				radio.prop('checked', true).trigger('change');
246			}
247		}
248	});
249
250	// Handle clicking on custom amount link
251	$('.custom-amount-link-wrapper').on('click', function(e) {
252		e.preventDefault();
253		const radio = $(this).find('.amount-type-radio');
254		if (radio.length && !radio.prop('checked')) {
255			radio.prop('checked', true).trigger('change');
256		}
257	});
258
259	// Custom Country Code Dropdown Functionality
260	const countryDropdown = {
261		init: function() {
262			const trigger = $('.country-code-trigger');
263			const menu = $('.country-code-menu');
264			const search = $('.country-search');
265			const items = $('.country-item');
266			const hiddenInput = $('#phone_country_code');
267			
268			// Toggle dropdown - use mousedown to prevent form control focus issues
269			trigger.on('mousedown', function(e) {
270				e.preventDefault();
271				e.stopPropagation();
272			});
273			
274			trigger.on('click', function(e) {
275				e.preventDefault();
276				e.stopPropagation();
277				const isOpen = menu.hasClass('show');
278				
279				if (isOpen) {
280					countryDropdown.close();
281				} else {
282					countryDropdown.open();
283				}
284			});
285			
286			// Search functionality
287			search.on('input', function() {
288				const searchTerm = $(this).val().toLowerCase();
289				
290				items.each(function() {
291					const countryName = $(this).find('.country-name').text().toLowerCase();
292					const countryCode = $(this).find('.country-code').text().toLowerCase();
293					
294					if (countryName.includes(searchTerm) || countryCode.includes(searchTerm)) {
295						$(this).removeClass('hidden');
296					} else {
297						$(this).addClass('hidden');
298					}
299				});
300			});
301			
302			// Select country
303			items.on('click', function(e) {
304				e.preventDefault();
305				e.stopPropagation();
306				
307				const code = $(this).data('code');
308				const iso = $(this).data('iso');
309				
310				// Update hidden input
311				hiddenInput.val(code);
312				
313				// Update trigger button
314				trigger.find('img.flag').attr('class', 'flag flag-' + iso);
315				trigger.find('.country-code-value').text(code);
316				
317				// Update active state
318				items.removeClass('active');
319				$(this).addClass('active');
320				
321				// Close dropdown
322				countryDropdown.close();
323				
324				// Focus phone number input
325				$('#customer_phone_number').focus();
326			});
327			
328			// Close on outside click
329			$(document).on('click', function(e) {
330				if (!$(e.target).closest('.country-code-dropdown').length) {
331					countryDropdown.close();
332				}
333			});
334			
335			// Close on escape key
336			$(document).on('keydown', function(e) {
337				if (e.key === 'Escape') {
338					countryDropdown.close();
339				}
340			});
341			
342			// Prevent dropdown from closing when clicking inside
343			menu.on('click', function(e) {
344				e.stopPropagation();
345			});
346		},
347		
348		open: function() {
349			const trigger = $('.country-code-trigger');
350			const menu = $('.country-code-menu');
351			const search = $('.country-search');
352			
353			console.log('Opening dropdown, menu element:', menu);
354			console.log('Has show class before:', menu.hasClass('show'));
355			menu.addClass('show');
356			console.log('Has show class after:', menu.hasClass('show'));
357			console.log('Menu display:', menu.css('display'));
358			trigger.attr('aria-expanded', 'true');
359			
360			// Focus search input
361			setTimeout(function() {
362				search.focus();
363			}, 100);
364		},
365		
366		close: function() {
367			const trigger = $('.country-code-trigger');
368			const menu = $('.country-code-menu');
369			const search = $('.country-search');
370			
371			menu.removeClass('show');
372			trigger.attr('aria-expanded', 'false');
373			
374			// Clear search
375			search.val('');
376			$('.country-item').removeClass('hidden');
377		}
378	};
379	
380	// Initialize country dropdown
381	countryDropdown.init();
382
383	// Format phone number input
384	$('#customer_phone_number').on('input', function() {
385		let value = $(this).val().replace(/[^\d\s\-]/g, '');
386		$(this).val(value);
387	});
388
389	// Form validation
390	$('#couponForm').on('submit', function(e) {
391		const amountType = $('.amount-type-radio:checked');
392		
393		if (!amountType.length) {
394			e.preventDefault();
395			alert('Prašome pasirinkti kortelės sumą');
396			return false;
397		}
398
399		if (!window._couponTurnstileVerified) {
400			e.preventDefault();
401			$('#coupon-turnstile-error').show();
402			return false;
403		}
404
405		if (amountType.val() === 'custom') {
406			const customAmount = parseFloat(customAmountInput.val());
407			const minAmount = parseFloat(customAmountInput.attr('min'));
408			const maxAmount = parseFloat(customAmountInput.attr('max'));
409
410			if (!customAmount || customAmount < minAmount || customAmount > maxAmount) {
411				e.preventDefault();
412				alert(`Suma turi būti nuo €${minAmount} iki €${maxAmount}`);
413				return false;
414			}
415		}
416
417		// Show loading state
418		const submitBtn = $(this).find('button[type="submit"]');
419		submitBtn.prop('disabled', true).html('<i class="fas fa-spinner fa-spin me-2"></i>Kraunama...');
420	});
421});

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.