PageSourceSearch

https://effortless-pixie-04f768.netlify.app/embeddable-form.js

js effortless-pixie-04f768.netlify.app collected 2026-10-03 10:41:04 UTC 156,021 bytes, 3,201 lines download raw bytes

1/**
2 * MultiStepBookingForm - A self-contained form module
3 * Safe for embedding in other websites
4 * Version 1.0.0
5 */
6(function(window, document) {
7    'use strict';
8    
9    // Helper to parse query params
10    function getQueryParams() {
11        var params = {};
12        var search = window.location.search.substring(1);
13        if (!search) return params;
14        search.split('&').forEach(function(pair) {
15            var parts = pair.split('=');
16            params[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1] || '');
17        });
18        return params;
19    }
20
21    // Add a method to fetch jlid data
22    function fetchJLIDData(jlid) {
23        // TODO: Replace with your real API endpoint
24        var url = 'https://your.api/lookup-jlid?jlid=' + encodeURIComponent(jlid);
25        return fetch(url)
26            .then(function(res) { return res.json(); });
27    }
28    
29    // Create a unique namespace
30    var BookingFormApp = {
31        // Initialize the form application
32        init: function(containerId) {
33            var self = this;
34            console.log('Initializing form with container ID:', containerId);
35
36            // Only initialize if the container exists
37            var container = document.getElementById(containerId || 'form-container');
38            if (!container) {
39                console.warn('BookingFormApp: Container element not found');
40                return;
41            }
42
43            // Check if already initialized using a more specific data attribute
44            if (container.getAttribute('data-booking-form-version') === '1.0.0') {
45                console.warn('BookingFormApp: Form already initialized');
46                return;
47            }
48
49            // Mark as initialized with version
50            container.setAttribute('data-booking-form-version', '1.0.0');
51
52            // --- JLID SUPPORT ---
53            var queryParams = getQueryParams();
54            if (queryParams.jlid) {
55                fetchJLIDData(queryParams.jlid)
56                    .then(function(jlidData) {
57                        // Store for later use
58                        self.jlidData = jlidData;
59                        // Continue with country detection and form build
60                        return self.detectCountry();
61                    })
62                    .then(function(countryData) {
63                        self.userCountry = countryData;
64                        return self.loadFontAwesome();
65                    })
66                    .then(function() {
67                        self.injectStyles();
68                        self.buildForm(container);
69                        // After form is built, prefill and auto-progress
70                        self.prefillAndProgressWithJLID(container);
71                        return self.detectCountry();
72                    })
73                    .then(function(countryData) {
74                        self.userCountry = countryData;
75                        self.updateCountryCodeDropdown(countryData);
76                    })
77                    .catch(function(error) {
78                        console.error('BookingFormApp: Error during initialization with jlid', error);
79                    });
80                return;
81            }
82            // --- END JLID SUPPORT ---
83
84            // First detect country, then build form
85            this.detectCountry()
86                .then(function(countryData) {
87                    self.userCountry = countryData;
88                    console.log('Country detected:', countryData);
89
90                    // Now load Font Awesome and build form
91                    return self.loadFontAwesome();
92                })
93                .then(function() {
94                    self.injectStyles();
95                    self.buildForm(container);
96
97                    // Detect country after the form is built
98                    return self.detectCountry();
99                })
100                .then(function(countryData) {
101                    self.userCountry = countryData;
102
103                    // Update the country code dropdown
104                    self.updateCountryCodeDropdown(countryData);
105                })
106                .catch(function(error) {
107                    console.error('BookingFormApp: Error during initialization', error);
108                });
109        },
110        
111        // Check if Font Awesome is loaded
112        isFontAwesomeLoaded: function() {
113            // Try to detect if Font Awesome is available
114            var span = document.createElement('span');
115            span.className = 'fa';
116            span.style.display = 'none';
117            document.body.appendChild(span);
118            
119            var computedStyle = window.getComputedStyle(span);
120            var isFALoaded = computedStyle && computedStyle.fontFamily.indexOf('FontAwesome') !== -1;
121            
122            document.body.removeChild(span);
123            return isFALoaded;
124        },
125        
126        // Load Font Awesome if needed
127        loadFontAwesome: function() {
128            var self = this;
129            return new Promise(function(resolve) {
130                if (document.querySelector('link[href*="font-awesome"]') || self.isFontAwesomeLoaded()) {
131                    // Font Awesome is already loaded
132                    resolve();
133                    return;
134                }
135                
136                // Font Awesome is not loaded, let's add it
137                var link = document.createElement('link');
138                link.rel = 'stylesheet';
139                link.href = 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css';
140                link.onload = function() {
141                    resolve();
142                };
143                link.onerror = function() {
144                    console.warn('BookingFormApp: Failed to load Font Awesome, icons may not display correctly');
145                    resolve(); // Continue anyway
146                };
147                
148                document.head.appendChild(link);
149            });
150        },
151        
152        // Inject scoped CSS styles to avoid conflicts
153        injectStyles: function() {
154            if (document.getElementById('booking-form-styles')) {
155                return; // Already injected
156            }
157            
158            var styles = `
159                /* Booking Form Styles - Scoped to avoid conflicts */
160                #form-container *,
161                [id$="-form-container"] * {
162                  box-sizing: border-box;
163                  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
164                }
165                
166                #form-container,
167                [id$="-form-container"] {
168                  width: 100%;
169                  padding: 0;
170                  margin: 0;
171                }
172                
173                #form-container .booking-container,
174                [id$="-form-container"] .booking-container {
175                  display: flex;
176                  flex-direction: column;
177                  justify-content: center;
178                  align-items: center;
179                  width: 100%;
180                  max-width: 100%;
181                  margin: 0 auto;
182                }
183                
184                #form-container .booking-frame-container,
185                [id$="-form-container"] .booking-frame-container {
186                  width: 100%;
187                }
188                
189                #form-container .booking-section,
190                [id$="-form-container"] .booking-section {
191                  color: #8d959e;
192                  font-size: 14px;
193                  margin-bottom: 10px;
194                  padding-left: 5px;
195                  text-align: center;
196                }
197                
198                #form-container .booking-frame,
199                [id$="-form-container"] .booking-frame {
200                  background-color: white;
201                  border-radius: 15px;
202                  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
203                  padding: 24px;
204                  width: 100%;
205                  min-height: auto;
206                  overflow: hidden;
207                  position: relative;
208                }
209                
210                #form-container .booking-step-content,
211                [id$="-form-container"] .booking-step-content {
212                  display: none;
213                  animation: bookingFormFadeIn 0.3s ease-in-out;
214                  width: 100%;
215                }
216                
217                @keyframes bookingFormFadeIn {
218                  from { opacity: 0; }
219                  to { opacity: 1; }
220                }
221                
222                #form-container .booking-step-content.active,
223                [id$="-form-container"] .booking-step-content.active {
224                  display: block;
225                }
226                
227                #form-container h2,
228                [id$="-form-container"] h2 {
229                  font-size: 20px;
230                  font-weight: 600;
231                  margin-bottom: 20px;
232                  text-align: center;
233                }
234                
235                /* Progress Bar */
236                #form-container .booking-progress-bar,
237                [id$="-form-container"] .booking-progress-bar {
238                  display: flex;
239                  justify-content: center;
240                  gap: 15px;
241                  margin-bottom: 25px;
242                  width: 100%;
243                }
244                
245                #form-container .booking-progress-item,
246                [id$="-form-container"] .booking-progress-item {
247                  height: 5px;
248                  flex: 1;
249                  max-width: 70px;
250                  background-color: #e0e0e0;
251                  border-radius: 3px;
252                }
253                
254                #form-container .booking-progress-item.active,
255                [id$="-form-container"] .booking-progress-item.active {
256                  background-color: #ffcf00;
257                }
258                
259                /* Form Elements */
260                #form-container .booking-form-group,
261                [id$="-form-container"] .booking-form-group {
262                  margin-bottom: 20px;
263                  width: 100%;
264                }
265                
266                #form-container .booking-form-group label,
267                [id$="-form-container"] .booking-form-group label {
268                  display: block;
269                  font-size: 16px;
270                  font-weight: 500;
271                  margin-bottom: 8px;
272                  color: #333;
273                }
274                
275                /* Phone input specific styles - style like the example */
276                #form-container .booking-form-row,
277                [id$="-form-container"] .booking-form-row {
278                  display: flex;
279                  gap: 10px;
280                  width: 100%;
281                  flex-direction: row !important; /* Force row display */
282                  flex-wrap: nowrap !important; /* Prevent wrapping */
283                }
284                
285                /* Fix the phone row to ensure labels align */
286                #form-container .booking-phone-row,
287                [id$="-form-container"] .booking-phone-row {
288                  align-items: stretch; /* Stretch children to equal height */
289                }
290                
291                /* Make sure each column in the phone row is self-contained */
292                #form-container .booking-phone-row > div,
293                [id$="-form-container"] .booking-phone-row > div {
294                  display: flex;
295                  flex-direction: column;
296                }
297                
298                #form-container .booking-country-code,
299                [id$="-form-container"] .booking-country-code {
300                  flex: 0 0 auto;
301                  width: 90px; 
302                  min-width: 90px;
303                }
304                
305                #form-container .booking-mobile-number,
306                [id$="-form-container"] .booking-mobile-number {
307                  flex: 1;
308                  min-width: 0;
309                }
310                
311                #form-container .booking-select-wrapper,
312                [id$="-form-container"] .booking-select-wrapper {
313                  position: relative;
314                  border: 1px solid #ddd;
315                  border-radius: 8px;
316                  background-color: white;
317                  width: 100%;
318                  height: 100%; /* Fill the height of the container */
319                }
320                
321                #form-container .booking-select-wrapper::after,
322                [id$="-form-container"] .booking-select-wrapper::after {
323                  content: '';
324                  position: absolute;
325                  right: 8px;
326                  top: 50%;
327                  transform: translateY(-50%);
328                  width: 0;
329                  height: 0;
330                  border-left: 5px solid transparent;
331                  border-right: 5px solid transparent;
332                  border-top: 5px solid #333;
333                  pointer-events: none;
334                }
335                
336                #form-container select,
337                [id$="-form-container"] select {
338                  width: 100%;
339                  height: 100%; /* Fill the height of the container */
340                  padding: 12px 6px;
341                  border: none;
342                  border-radius: 8px;
343                  background-color: transparent;
344                  appearance: none;
345                  font-size: 14px;
346                  font-weight: 500;
347                  color: #333;
348                  text-overflow: ellipsis;
349                  white-space: nowrap;
350                  overflow: hidden;
351                  cursor: pointer;
352                }
353                
354                #form-container select option,
355                [id$="-form-container"] select option {
356                  font-size: 14px;
357                }
358                
359                #form-container input[type="tel"],
360                #form-container input[type="text"],
361                #form-container input[type="email"],
362                [id$="-form-container"] input[type="tel"],
363                [id$="-form-container"] input[type="text"],
364                [id$="-form-container"] input[type="email"] {
365                  width: 100%;
366                  height: 100%; /* Fill the height of the container */
367                  min-height: 46px; /* Minimum height to match select height */
368                  padding: 12px;
369                  border: 1px solid #ddd;
370                  border-radius: 8px;
371                  font-size: 16px;
372                  color: #333;
373                }
374                
375                #form-container .booking-help-text,
376                [id$="-form-container"] .booking-help-text {
377                  font-size: 12px;
378                  color: #666;
379                  margin: 5px 0 15px;
380                }
381                
382                /* Grade Grid - Responsive */
383                #form-container .booking-grade-grid,
384                [id$="-form-container"] .booking-grade-grid {
385                  display: grid;
386                  grid-template-columns: repeat(4, 1fr);
387                  gap: 10px;
388                  width: 100%;
389                }
390                
391                /* Date Grid - Responsive */
392                #form-container .booking-date-grid,
393                [id$="-form-container"] .booking-date-grid {
394                  display: grid;
395                  grid-template-columns: repeat(3, 1fr);
396                  gap: 10px;
397                  width: 100%;
398                }
399                
400                /* Time Grid - Responsive */
401                #form-container .booking-time-grid,
402                [id$="-form-container"] .booking-time-grid {
403                  display: grid;
404                  grid-template-columns: repeat(4, 1fr);
405                  gap: 10px;
406                  width: 100%;
407                }
408                
409                /* Buttons */
410                #form-container .booking-primary-button,
411                [id$="-form-container"] .booking-primary-button {
412                  width: 100%;
413                  padding: 14px;
414                  background-color: #ffcf00;
415                  color: #333;
416                  border: none;
417                  border-radius: 10px;
418                  font-size: 16px;
419                  font-weight: 600;
420                  cursor: pointer;
421                  display: flex;
422                  align-items: center;
423                  justify-content: center;
424                  gap: 10px;
425                  margin: 15px 0;
426                  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
427                }
428                
429                #form-container .booking-secondary-button,
430                [id$="-form-container"] .booking-secondary-button {
431                  width: 100%;
432                  padding: 12px;
433                  background-color: #f5f5f5;
434                  color: #666;
435                  border: 1px solid #ddd;
436                  border-radius: 10px;
437                  font-size: 14px;
438                  font-weight: 500;
439                  cursor: pointer;
440                  display: flex;
441                  align-items: center;
442                  justify-content: center;
443                  margin-bottom: 15px;
444                }
445                
446                #form-container .booking-grade-btn,
447                [id$="-form-container"] .booking-grade-btn,
448                #form-container .booking-date-btn,
449                [id$="-form-container"] .booking-date-btn,
450                #form-container .booking-time-btn,
451                [id$="-form-container"] .booking-time-btn {
452                  width: 100%;
453                  padding: 10px;
454                  border: 1px solid #ddd;
455                  border-radius: 8px;
456                  background-color: white;
457                  cursor: pointer;
458                }
459                
460                #form-container .booking-back-button,
461                [id$="-form-container"] .booking-back-button {
462                  position: absolute;
463                  left: 24px;
464                  top: 25px;
465                  font-size: 18px;
466                  color: #333;
467                  cursor: pointer;
468                  z-index: 10;
469                }
470                
471                #form-container .booking-option-buttons,
472                [id$="-form-container"] .booking-option-buttons {
473                  display: flex;
474                  flex-wrap: wrap;
475                  gap: 10px;
476                  width: 100%;
477                }
478                
479                #form-container .booking-option-btn,
480                [id$="-form-container"] .booking-option-btn {
481                  padding: 10px 15px;
482                  border: 1px solid #ddd;
483                  border-radius: 30px;
484                  background-color: white;
485                  cursor: pointer;
486                  font-size: 14px;
487                }
488                
489                /* Error messages */
490                #form-container .booking-error-message,
491                [id$="-form-container"] .booking-error-message {
492                  color: #e74c3c;
493                  font-size: 12px;
494                  margin-top: 5px;
495                }
496                
497                /* Mobile Responsiveness */
498                @media (max-width: 576px) {
499                  #form-container .booking-grade-grid,
500                  [id$="-form-container"] .booking-grade-grid {
501                    grid-template-columns: repeat(3, 1fr);
502                  }
503                  
504                  #form-container .booking-date-grid,
505                  [id$="-form-container"] .booking-date-grid {
506                    grid-template-columns: repeat(2, 1fr);
507                  }
508                  
509                  #form-container .booking-time-grid,
510                  [id$="-form-container"] .booking-time-grid {
511                    grid-template-columns: repeat(2, 1fr);
512                    gap: 8px;
513                  }
514                  
515                  #form-container .booking-time-btn,
516                  [id$="-form-container"] .booking-time-btn {
517                    padding: 12px 8px;
518                    font-size: 14px;
519                    white-space: nowrap;
520                    min-height: 45px;
521                    display: flex;
522                    align-items: center;
523                    justify-content: center;
524                  }
525                  
526                  #form-container h2,
527                  [id$="-form-container"] h2 {
528                    font-size: 18px;
529                    padding-right: 15px;
530                    padding-left: 15px;
531                    margin-bottom: 15px;
532                  }
533                  
534                  #form-container .booking-frame,
535                  [id$="-form-container"] .booking-frame {
536                    padding: 16px 12px;
537                    border-radius: 10px;
538                  }
539                  
540                  /* Keep form rows in row direction for phone input */
541                  #form-container .booking-form-row:not(.booking-phone-row),
542                  [id$="-form-container"] .booking-form-row:not(.booking-phone-row) {
543                    flex-direction: column;
544                    gap: 10px;
545                  }
546                  
547                  #form-container .booking-country-code,
548                  [id$="-form-container"] .booking-country-code {
549                    width: 80px;
550                    min-width: 80px;
551                  }
552                }
553                
554                /* Extra small devices */
555                @media (max-width: 360px) {
556                  #form-container .booking-grade-grid,
557                  [id$="-form-container"] .booking-grade-grid,
558                  #form-container .booking-time-grid,
559                  [id$="-form-container"] .booking-time-grid {
560                    grid-template-columns: repeat(2, 1fr);
561                    gap: 6px;
562                  }
563                  
564                  #form-container .booking-time-btn,
565                  [id$="-form-container"] .booking-time-btn {
566                    padding: 10px 6px;
567                    font-size: 13px;
568                  }
569                  
570                  #form-container .boo
570king-country-code,
571                  [id$="-form-container"] .booking-country-code {
572                    width: 70px;
573                    min-width: 70px;
574                  }
575                  
576                  #form-container select,
577                  [id$="-form-container"] select {
578                    padding: 12px 4px;
579                    font-size: 13px;
580                  }
581                }
582            `;
583            
584            var styleSheet = document.createElement('style');
585            styleSheet.id = 'booking-form-styles';
586            styleSheet.textContent = styles;
587            document.head.appendChild(styleSheet);
588        },
589        
590        // Build the form structure
591        buildForm: function(container) {
592            var self = this;
593            
594            // Create the main container
595            var mainContainer = this.createElement('div', { className: 'booking-container' });
596            
597            var frameContainer = this.createElement('div', { className: 'booking-frame-container' });
598            var frame = this.createElement('div', { className: 'booking-frame' });
599            
600            // Append elements
601            mainContainer.appendChild(frameContainer);
602            frameContainer.appendChild(frame);
603            container.appendChild(mainContainer);
604            
605            // Create step 1: Book Now & Get Certified
606            var step1 = this.createStep1(1);
607            frame.appendChild(step1);
608            
609            // Create step 2: Select Date & Time
610            var step2 = this.createStep2(2);
611            frame.appendChild(step2);
612            
613            // Create step 3: Student Details
614            var step3 = this.createStep3(3);
615            frame.appendChild(step3);
616            
617            // Set up event listeners
618            this.setupEventListeners(container);
619        },
620        
621        // Create step 1
622        createStep1: function(stepNumber) {
623            var step = this.createElement('div', {
624                className: 'booking-step-content active',
625                id: 'booking-step1'
626            });
627            
628            // Add title and progress bar
629            var title = this.createElement('h2', {});
630            title.textContent = 'Book Now & Get Certified';
631            step.appendChild(title);
632            
633            var progressBar = this.createProgressBar(stepNumber);
634            step.appendChild(progressBar);
635            
636            // Add the phone input group with required indicator but no asterisk
637            var phoneGroup = this.createPhoneInput(true);
638            step.appendChild(phoneGroup);
639            
640            // Add grade selection with required indicator but no asterisk
641            var gradeGroup = this.createGradeSelection(true);
642            step.appendChild(gradeGroup);
643            
644            // Add action button
645            var actionButton = this.createElement('button', {
646                className: 'booking-primary-button',
647                attributes: { 'data-step': stepNumber.toString() }
648            });
649            actionButton.innerHTML = 'Book a Free Trial Class';
650            step.appendChild(actionButton);
651            
652            // Add terms text
653        
654            
655            return step;
656        },
657        
658        // Create step 2
659        createStep2: function(stepNumber) {
660            var step = this.createElement('div', {
661                className: 'booking-step-content',
662                id: 'booking-step2'
663            });
664            
665            // Add back button
666            var backButton = this.createElement('div', { className: 'booking-back-button' });
667            backButton.innerHTML = '←';
668            backButton.style.fontSize = '18px';
669            step.appendChild(backButton);
670            
671            // Add title and progress bar
672            var title = this.createElement('h2', {});
673            title.textContent = 'Select Date & Time';
674            step.appendChild(title);
675            
676            var progressBar = this.createProgressBar(stepNumber);
677            step.appendChild(progressBar);
678            
679            // Add timezone selection before date selection
680            var timezoneSelect = this.createTimezoneSelect();
681            step.appendChild(timezoneSelect);
682            
683            // Add date selection without asterisk
684            var dateGroup = this.createElement('div', { className: 'booking-form-group' });
685            var dateLabel = this.createElement('label', {});
686            dateLabel.textContent = 'Select Date';
687            dateGroup.appendChild(dateLabel);
688            
689            var dateHelpText = this.createElement('p', { className: 'booking-help-text' });
690            dateHelpText.textContent = 'Your class will be for 1 hour';
691            dateGroup.appendChild(dateHelpText);
692            
693            var dateGrid = this.createElement('div', { className: 'booking-date-grid' });
694            
695            // Get dates for the next 6 days
696            var today = new Date();
697            var dates = [];
698            var daysToCheck = 1; // Start from tomorrow
699            
700            // Dates to skip (format: 'YYYY-MM-DD')
701            var skipDates = [
702                '2025-12-24', // Wednesday, 24 December 2025
703                '2025-12-25', // Thursday, 25 December 2025
704                '2025-12-31', // Wednesday, 31 December 2025
705                '2026-01-01', // Thursday, 1 January 2026
706                '2026-03-30'  // Monday, 30 March 2026 — excluded from booking
707            ];
708            
709            // Helper function to check if date should be skipped
710            function shouldSkipDate(dateObj) {
711                var year = dateObj.getFullYear();
712                var month = String(dateObj.getMonth() + 1).padStart(2, '0');
713                var day = String(dateObj.getDate()).padStart(2, '0');
714                var dateKey = year + '-' + month + '-' + day;
715                return skipDates.indexOf(dateKey) !== -1;
716            }
717            
718            // Continue until we have 6 dates
719            while (dates.length < 6) {
720                var date = new Date(today);
721                date.setDate(today.getDate() + daysToCheck);
722                
723                // Skip this date if it's in the skip list
724                if (shouldSkipDate(date)) {
725                    daysToCheck++;
726                    continue;
727                }
728                
729                var day = daysToCheck === 1 ? 'Tomorrow' : this.getDayName(date.getDay());
730                var dateStr = date.getDate() + ' ' + this.getMonthShortName(date.getMonth());
731                
732                dates.push({
733                    day: day,
734                    date: dateStr,
735                    active: dates.length === 0 // First available date is active by default
736                });
737                
738                daysToCheck++;
739            }
740            
741            var self = this;
742            dates.forEach(function(date) {
743                var dateBtn = self.createElement('button', {
744                    className: 'booking-date-btn' + (date.active ? ' active' : ''),
745                    attributes: { 'type': 'button' }
746                });
747                
748                var dayDiv = self.createElement('div', {});
749                dayDiv.textContent = date.day;
750                
751                var dateDiv = self.createElement('div', {});
752                dateDiv.textContent = date.date;
753                
754                dateBtn.appendChild(dayDiv);
755                dateBtn.appendChild(dateDiv);
756                dateGrid.appendChild(dateBtn);
757            });
758            
759            dateGroup.appendChild(dateGrid);
760            step.appendChild(dateGroup);
761            
762            // Add time selection without asterisk
763            var timeGroup = this.createElement('div', { className: 'booking-form-group' });
764            var timeLabel = this.createElement('label', {});
765            timeLabel.textContent = 'Select Start Time';
766            timeGroup.appendChild(timeLabel);
767            
768            var timeHelpText = this.createElement('p', { className: 'booking-help-text' });
769            timeHelpText.textContent = 'Class slots are limited. Please choose carefully.';
770            timeGroup.appendChild(timeHelpText);
771            
772            // Get tomorrow's date to check if it's a weekend
773            var tomorrow = new Date();
774            tomorrow.setDate(tomorrow.getDate() + 1);
775            // Special case: Dec 30, 2025 (tomorrow) should have all slots open like a weekend
776            var isTomorrowSpecialDay = tomorrow.getDate() === 30 && tomorrow.getMonth() === 11 && tomorrow.getFullYear() === 2025;
777            var isWeekend = tomorrow.getDay() === 0 || tomorrow.getDay() === 6 || isTomorrowSpecialDay;
778
779            // Create time grid based on country and whether tomorrow is a weekend
780            var timeGrid = this.createElement('div', { className: 'booking-time-grid' });
781            
782            // Define time slots based on country and day
783            var timeSlots;
784            if (this.userCountry && this.userCountry.isIndia) {
785                if (isWeekend) {
786                    // Weekend slots for India: 10:30 AM to 7:30 PM
787                    timeSlots = [
788                        '10:30 AM', '11:30 AM', '12:30 PM',
789                        '1:30 PM', '2:30 PM', '3:30 PM',
790                        '4:30 PM', '5:30 PM', '6:30 PM',
791                        '7:30 PM'
792                    ];
793                } else {
794                    // Weekday slots for India: 4:30 PM to 7:30 PM
795                    timeSlots = [
796                        '4:30 PM', '5:30 PM', '6:30 PM', '7:30 PM'
797                    ];
798                }
799            } else {
800                if (isWeekend) {
801                    // Weekend slots for ROW: 8:00 AM to 8:00 PM
802                    timeSlots = [
803                        '8:00 AM', '9:00 AM', '10:00 AM', '11:00 AM',
804                        '12:00 PM', '1:00 PM', '2:00 PM', '3:00 PM',
805                        '4:00 PM', '5:00 PM', '6:00 PM', '7:00 PM',
806                        '8:00 PM'
807                    ];
808                } else {
809                    // Weekday slots for ROW: 5:00 PM to 8:00 PM
810                    timeSlots = [
811                        '5:00 PM', '6:00 PM', '7:00 PM', '8:00 PM'
812                    ];
813                }
814            }
815            
816            timeSlots.forEach(function(time) {
817                var timeBtn = self.createElement('button', {
818                    className: 'booking-time-btn',
819                    attributes: { 'type': 'button' }
820                });
821                timeBtn.textContent = time;
822                timeGrid.appendChild(timeBtn);
823            });
824            
825            timeGroup.appendChild(timeGrid);
826            step.appendChild(timeGroup);
827            
828            // Add action buttons
829            var actionButton = this.createElement('button', {
830                className: 'booking-primary-button',
831                attributes: { 'data-step': stepNumber.toString() }
832            });
833            actionButton.textContent = 'Confirm Class Time';
834            step.appendChild(actionButton);
835            
836            return step;
837        },
838        
839        // Create step 3
840        createStep3: function(stepNumber) {
841            var step = this.createElement('div', {
842                className: 'booking-step-content',
843                id: 'booking-step3'
844            });
845            
846            // Add back button
847            var backButton = this.createElement('div', { className: 'booking-back-button' });
848            backButton.innerHTML = '←';
849            backButton.style.fontSize = '18px';
850            step.appendChild(backButton);
851            
852            // Add title and progress bar
853            var title = this.createElement('h2', {});
854            title.textContent = 'Student Details';
855            step.appendChild(title);
856            
857            var progressBar = this.createProgressBar(stepNumber);
858            step.appendChild(progressBar);
859            
860            // Add help text
861            var helpText = this.createElement('p', { className: 'booking-help-text' });
862            helpText.textContent = 'Please enter the following details correctly for the accreditation certificate.';
863            step.appendChild(helpText);
864            
865            // Child's name field without asterisk
866            var childNameGroup = this.createFormField(
867                'Child\'s Name', 
868                'text', 
869                'Enter Child\'s Name', 
870                'This will be used on your child\'s certificate',
871                true,
872                'child-name-input'  // Add specific ID
873            );
874            step.appendChild(childNameGroup);
875            
876            // Parent's name field without asterisk
877            var parentNameGroup = this.createFormField(
878                'Parent\'s Name', 
879                'text', 
880                'Enter Parent\'s Name', 
881                '',
882                true,
883                'parent-name-input'  // Add specific ID
884            );
885            step.appendChild(parentNameGroup);
886            
887            // Email field without asterisk
888            var emailGroup = this.createFormField(
889                'Email ID', 
890                'email', 
891                'Enter Email ID',
892                null,
893                true
894            );
895            step.appendChild(emailGroup);
896            
897            // Add action buttons
898            var actionButton = this.createElement('button', {
899                className: 'booking-primary-button',
900                attributes: { 'data-step': stepNumber.toString() }
901            });
902            actionButton.textContent = 'Confirm Booking';
903            step.appendChild(actionButton);
904            
905       
906            
907            return step;
908        },
909        
910        // Create step 4
911        createStep4: function(stepNumber) {
912            var step = this.createElement('div', {
913                className: 'booking-step-content',
914                id: 'booking-step4'
915            });
916            
917            // Add back button
918            var backButton = this.createElement('div', { className: 'booking-back-button' });
919            backButton.innerHTML = '←';
920            backButton.style.fontSize = '18px';
921            step.appendChild(backButton);
922            
923            // Add title and progress bar
924            var title = this.createElement('h2', {});
925            title.textContent = 'Help us customize your experience';
926            step.appendChild(title);
927            
928            var progressBar = this.createProgressBar(stepNumber);
929            step.appendChild(progressBar);
930            
931            // Who are you?
932            var roleGroup = this.createElement('div', { className: 'booking-form-group' });
933            var roleLabel = this.createElement('label', {});
934            roleLabel.textContent = 'Who are you?';
935            roleGroup.appendChild(roleLabel);
936            
937            var roleButtons = this.createElement('div', { className: 'booking-option-buttons' });
938            roleButtons.style.display = 'flex';
939            roleButtons.style.flexWrap = 'wrap';
940            roleButtons.style.gap = '10px';
941            
942            var roleOptions = [
943                { text: 'Parent', active: true },
944                { text: 'Student' },
945                { text: 'Guardian' }
946            ];
947            
948            roleOptions.forEach(function(option) {
949                var btn = this.createElement('button', {
950                    className: 'booking-option-btn' + (option.active ? ' active' : ''),
951                    attributes: { 'type': 'button' }
952                });
953                btn.style.padding = '10px 15px';
954                btn.style.border = option.active ? '1px solid #ffcf00' : '1px solid #ddd';
955                btn.style.borderRadius = '30px';
956                btn.style.backgroundColor = option.active ? 'rgba(255, 207, 0, 0.1)' : 'white';
957                btn.style.cursor = 'pointer';
958                btn.style.fontSize = '14px';
959                
960                btn.textContent = option.text;
961                roleButtons.appendChild(btn);
962            }, this);
963            
964            roleGroup.appendChild(roleButtons);
965            step.appendChild(roleGroup);
966            
967            // Why booking?
968            var reasonGroup = this.createElement('div', { className: 'booking-form-group' });
969            var reasonLabel = this.createElement('label', {});
970            reasonLabel.textContent = 'Why are you booking this demo class?';
971            reasonGroup.appendChild(reasonLabel);
972            
973            var reasonButtons = this.createElement('div', { className: 'booking-option-buttons' });
974            reasonButtons.style.display = 'flex';
975            reasonButtons.style.flexWrap = 'wrap';
976            reasonButtons.style.gap = '10px';
977            
978            var reasonOptions = [
979                { text: 'Want to buy course', active: true },
980                { text: 'Just want the free demo class' }
981            ];
982            
983            reasonOptions.forEach(function(option) {
984                var btn = this.createElement('button', {
985                    className: 'booking-option-btn' + (option.active ? ' active' : ''),
986                    attributes: { 'type': 'button' }
987                });
988                btn.style.padding = '10px 15px';
989                btn.style.border = option.active ? '1px solid #ffcf00' : '1px solid #ddd';
990                btn.style.borderRadius = '30px';
991                btn.style.backgroundColor = option.active ? 'rgba(255, 207, 0, 0.1)' : 'white';
992                btn.style.cursor = 'pointer';
993                btn.style.fontSize = '14px';
994                
995                btn.textContent = option.text;
996                reasonButtons.appendChild(btn);
997            }, this);
998            
999            reasonGroup.appendChild(reasonButtons);
1000            step.appendChild(reasonGroup);
1001            
1002            // When planning to buy?
1003            var timelineGroup = this.createElement('div', { className: 'booking-form-group' });
1004            var timelineLabel = this.createElement('label', {});
1005            timelineLabel.textContent = 'When are you planning to buy the course?';
1006            timelineGroup.appendChild(timelineLabel);
1007            
1008            var timelineButtons = this.createElement('div', { className: 'booking-option-buttons' });
1009            timelineButtons.style.display = 'flex';
1010            timelineButtons.style.flexWrap = 'wrap';
1011            timelineButtons.style.gap = '10px';
1012            
1013            var timelineOptions = [
1014                { text: 'After the demo', active: true },
1015                { text: 'This week' },
1016                { text: 'This month' },
1017                { text: 'Just exploring' }
1018            ];
1019            
1020            timelineOptions.forEach(function(option) {
1021                var btn = this.createElement('button', {
1022                    className: 'booking-option-btn' + (option.active ? ' active' : ''),
1023                    attributes: { 'type': 'button' }
1024                });
1025                btn.style.padding = '10px 15px';
1026                btn.style.border = option.active ? '1px solid #ffcf00' : '1px solid #ddd';
1027                btn.style.borderRadius = '30px';
1028                btn.style.backgroundColor = option.active ? 'rgba(255, 207, 0, 0.1)' : 'white';
1029                btn.style.cursor = 'pointer';
1030                btn.style.fontSize = '14px';
1031                
1032                btn.textContent = option.text;
1033                timelineButtons.appendChild(btn);
1034            }, this);
1035            
1036            timelineGroup.appendChild(timelineButtons);
1037            step.appendChild(timelineGroup);
1038            
1039            // Add action buttons
1040            var actionButton = this.createElement('button', {
1041                className: 'booking-primary-button booking-submit-btn',
1042                attributes: { 'data-step': stepNumber.toString() }
1043            });
1044            actionButton.innerHTML = '✓ Submit';
1045            actionButton.style.marginTop = '30px';
1046            step.appendChild(actionButton);
1047            
1048          
1049            
1050            return step;
1051        },
1052        
1053        // Helper functions to create form elements
1054        createProgressBar: function(currentStep) {
1055            var progressBar = this.createElement('div', { className: 'booking-progress-bar' });
1056            
1057            for (var i = 1; i <= 3; i++) {
1058                progressBar.appendChild(
1059                    this.createElement('div', { 
1060                        className: 'booking-progress-item' + (i <= currentStep ? ' active' : '') 
1061                    })
1062                );
1063            }
1064            
1065            return progressBar;
1066        },
1067        
1068        createPhoneInput: function(required) {
1069            var self = this;
1070            var formGroup = this.createElement('div', { className: 'booking-form-group' });
1071
1072            // Create form row for phone input with labels on the same line
1073            var labelRow = this.createElement('div', { className: 'booking-form-row' });
1074
1075            // Country code label
1076            var countryCodeLabelDiv = this.createElement('div', { className: 'booking-country-code' });
1077            var countryCodeLabel = this.createElement('label', {});
1078            countryCodeLabel.textContent = 'Country Code';
1079            countryCodeLabelDiv.appendChild(countryCodeLabel);
1080
1081            // Mobile number label
1082            var mobileNumberLabelDiv = this.createElement('div', { className: 'booking-mobile-number' });
1083            var mobileLabel = this.createElement('label', {});
1084            mobileLabel.textContent = 'Mobile Number';
1085            mobileNumberLabelDiv.appendChild(mobileLabel);
1086
1087            // Add labels to the label row
1088            labelRow.appendChild(countryCodeLabelDiv);
1089            labelRow.appendChild(mobileNumberLabelDiv);
1090            formGroup.appendChild(labelRow);
1091
1092            // Create input row for the actual input fields
1093            var inputRow = this.createElement('div', { className: 'booking-form-row booking-phone-row' });
1094
1095            // Country code input
1096            var countryCodeDiv = this.createElement('div', { className: 'booking-country-code' });
1097            var selectWrapper = this.createElement('div', { className: 'booking-select-wrapper' });
1098            var select = this.createElement('select', {});
1099
1100            // Add all countries to the dropdown
1101            this.countriesList.forEach(function(country) {
1102                var option = self.createElement('option', {
1103                    attributes: {
1104                        value: country.code,
1105                        selected: self.userCountry && country.code === self.userCountry.code ? 'selected' : null
1106                    }
1107                });
1108                option.textContent = country.dial_code;
1109                select.appendChild(option);
1110            });
1111
1112            selectWrapper.appendChild(select);
1113            countryCodeDiv.appendChild(selectWrapper);
1114
1115            // Mobile number input
1116            var mobileNumberDiv = this.createElement('div', { className: 'booking-mobile-number' });
1117            var mobileInput = this.createElement('input', {
1118                attributes: {
1119                    type: 'tel',
1120                    placeholder: 'Enter Mobile Number',
1121                    required: required ? 'required' : null
1122                }
1123            });
1124
1125            // Add input validation to allow only digits
1126            mobileInput.addEventListener('input', function(e) {
1127                e.target.value = e.target.value.replace(/\D/g, ''); // Remove non-digit characters
1128            });
1129
1130            mobileNumberDiv.appendChild(mobileInput);
1131
1132            // Add error message container (hidden by default)
1133            var errorMessage = this.createElement('div', { className: 'booking-error-message' });
1134            errorMessage.style.color = '#e74c3c';
1135            errorMessage.style.fontSize = '12px';
1136            errorMessage.style.marginTop = '5px';
1137            errorMessage.style.display = 'none';
1138            mobileNumberDiv.appendChild(errorMessage);
1139
1140            // Assemble the input row
1141            inputRow.appendChild(countryCodeDiv);
1142            inputRow.appendChild(mobileNumberDiv);
1143            formGroup.appendChild(inputRow);
1144
1145            // Add help text
1146            var helpText = this.createElement('p', { className: 'booking-help-text' });
1147            helpText.textContent = 'Please share the number that you use for WhatsApp';
1148            formGroup.appendChild(helpText);
1149
1150            return formGroup;
1151        },
1152        
1153        // Update createGradeSelection method to show ages instead of grades
1154        createGradeSelection: function(required) {
1155            var formGroup = this.createElement('div', { className: 'booking-form-group' });
1156            
1157            // Add label without asterisk
1158            var label = this.createElement('label', {});
1159            label.textContent = 'Select Child\'s Age';
1160            formGroup.appendChild(label);
1161            
1162            // Create grade grid
1163            var gradeGrid = this.createElement('div', { className: 'booking-grade-grid' });
1164            
1165            // Add age buttons (starting from age 5, which corresponds to Grade 1)
1166            for (var i = 1; i <= 12; i++) {
1167                var ageValue = i + 4; // Grade 1 = Age 5, Grade 2 = Age 6, etc.
1168                var gradeBtn = this.createElement('button', { 
1169                    className: 'booking-grade-btn',
1170                    attributes: { 
1171                        'type': 'button', 
1172                        'data-grade': i.toString(), // Keep original grade value for backend
1173                        'data-age': ageValue.toString() // Add age data attribute
1174                    }
1175                });
1176                
1177                var ageText = this.createElement('span', {});
1178                ageText.textContent = 'Age ';
1179                
1180                var ageNumber = this.createElement('span', {});
1181                ageNumber.textContent = ageValue.toString();
1182                
1183                gradeBtn.appendChild(ageText);
1184                gradeBtn.appendChild(ageNumber);
1185                gradeGrid.appendChild(gradeBtn);
1186            }
1187            
1188            formGroup.appendChild(gradeGrid);
1189            return formGroup;
1190        },
1191        
1192        // Add method to create form fields with error support
1193        createFormField: function(labelText, inputType, placeholder, note, required, inputId) {
1194            var formGroup = this.createElement('div', { className: 'booking-form-group' });
1195            
1196            // Create label without asterisk
1197            var label = this.createElement('label', {});
1198            label.textContent = labelText;
1199            formGroup.appendChild(label);
1200            
1201            // Create input with ID if provided
1202            var input = this.createElement('input', {
1203                attributes: {
1204                    type: inputType,
1205                    placeholder: placeholder || ('Enter ' + labelText),
1206                    required: required ? 'required' : null,
1207                    id: inputId || null  // Add ID if provided
1208                }
1209            });
1210            formGroup.appendChild(input);
1211            
1212            // Add note if provided
1213            if (note) {
1214                var noteElement = this.createElement('small', {});
1215                noteElement.textContent = note;
1216                noteElement.style.display = 'block';
1217                noteElement.style.fontSize = '12px';
1218                noteElement.style.color = '#666';
1219                noteElement.style.marginTop = '5px';
1220                formGroup.appendChild(noteElement);
1221            }
1222            
1223            // Add error message container (hidden by default)
1224            var errorMessage = this.createElement('div', { className: 'booking-error-message' });
1225            errorMessage.style.color = '#e74c3c';
1226            errorMessage.style.fontSize = '12px';
1227            errorMessage.style.marginTop = '5px';
1228            errorMessage.style.display = 'none';
1229            formGroup.appendChild(errorMessage);
1230            
1231            return formGroup;
1232        },
1233        
1234        // Helper method to show error
1235        showError: function(container, field, message) {
1236            // Find the error message container in the field's parent
1237            var errorContainer = field.parentNode.querySelector('.booking-error-message');
1238            if (errorContainer) {
1239                errorContainer.textContent = message;
1240                errorContainer.style.display = 'block';
1241                
1242                // Highlight the field
1243                field.style.borderColor = '#e74c3c';
1244            }
1245            return false; // For convenience in validation chains
1246        },
1247        
1248        // Helper method to clear error
1249        clearError: function(field) {
1250            if (!field) return;
1251            
1252            // Find the error message container in the field's parent
1253            var errorContainer = field.parentNode.querySelector('.booking-error-message');
1254            if (errorContainer) {
1255                errorContainer.textContent = '';
1256                errorContainer.style.display = 'none';
1257            }
1258            
1259            // Reset field styling
1260            field.style.borderColor = '#ddd';
1261        },
1262        
1263        // Helper method to clear all errors in a container
1264        clearAllErrors: function(container) {
1265            var errorContainers = container.querySelectorAll('.booking-error-message');
1266            errorContainers.forEach(function(errorContainer) {
1267                errorContainer.textContent = '';
1268                errorContainer.style.display = 'none';
1269            });
1270            
1271            var fields = container.querySelectorAll('input, select');
1272            fields.forEach(function(field) {
1273                field.style.borderColor = '#ddd';
1274            });
1275        },
1276        
1277        // Update setupEventListeners to handle age selection error messages
1278        setupEventListeners: function(container) {
1279            var self = this;
1280
1281            // Handle navigation between steps
1282            var primaryButtons = container.querySelectorAll('.booking-primary-button');
1283            primaryButtons.forEach(function(button) {
1284                button.addEventListener('click', function() {
1285                    var stepNumber = parseInt(this.getAttribute('data-step'));
1286                    var nextStepNumber = stepNumber + 1;
1287                    var currentStep = container.querySelector('#booking-step' + stepNumber);
1288
1289                    // Clear all previous errors
1290                    self.clearAllErrors(currentStep);
1291
1292                    // Basic validation
1293                    var isValid = true;
1294                    if (stepNumber === 1) {
1295                        var mobileInput = container.querySelector('input[type="tel"]');
1296                        var gradeSelected = container.querySelector('.booking-grade-btn.active');
1297                        if (!mobileInput || !mobileInput.value) {
1298                            isValid = self.showError(currentStep, mobileInput, 'Please enter your mobile number (required)');
1299                        }
1300                        if (!gradeSelected) {
1301                            var gradeGrid = container.querySelector('.booking-grade-grid');
1302                            if (gradeGrid) {
1303                                var errorMessage = self.createElement('div', { className: 'booking-error-message' });
1304                                errorMessage.style.color = '#e74c3c';
1305                                errorMessage.style.fontSize = '12px';
1306                                errorMessage.style.marginTop = '5px';
1307                                errorMessage.textContent = 'Please select an age (required)';
1308                                var existingError = gradeGrid.nextElementSibling;
1309                                if (existingError && existingError.classList.contains('booking-error-message')) {
1310                                    existingError.remove();
1311                                }
1312                                gradeGrid.parentNode.insertBefore(errorMessage, gradeGrid.nextSibling);
1313                                isValid = false;
1314                            }
1315                        }
1316                    } else if (stepNumber === 2) {
1317                        var dateSelected = container.querySelector('.booking-date-btn.active');
1318                        var timeSelected = container.querySelector('.booking-time-btn.active');
1319                        if (!dateSelected) {
1320                            var dateGrid = container.querySelector('.booking-date-grid');
1321                            if (dateGrid) {
1322                                var errorMessage = self.createElement('div', { className: 'booking-error-message' });
1323                                errorMessage.style.color = '#e74c3c';
1324                                errorMessage.style.fontSize = '12px';
1325                                errorMessage.style.marginTop = '5px';
1326                                errorMessage.textContent = 'Please select a date (required)';
1327                                var existingError = dateGrid.nextElementSibling;
1328                                if (existingError && existingError.classList.contains('booking-error-message')) {
1329                                    existingError.remove();
1330                                }
1331                                dateGrid.parentNode.insertBefore(errorMessage, dateGrid.nextSibling);
1332                                isValid = false;
1333                            }
1334                        }
1335                        if (!timeSelected) {
1336                            var timeGrid = container.querySelector('.booking-time-grid');
1337                            if (timeGrid) {
1338                                var errorMessage = self.createElement('div', { className: 'booking-error-message' });
1339                                errorMessage.style.color = '#e74c3c';
1340                                errorMessage.style.fontSize = '12px';
1341                                errorMessage.style.marginTop = '5px';
1342                                errorMessage.textContent = 'Please select a time (required)';
1343                                var existingError = timeGrid.nextElementSibling;
1344                                if (existingError && existingError.classList.contains('booking-error-message')) {
1345                                    existingError.remove();
1346                                }
1347                                timeGrid.parentNode.insertBefore(errorMessage, timeGrid.nextSibling);
1348                                isValid = false;
1349                            }
1350                        }
1351                    } else if (stepNumber === 3) {
1352                        var childName = container.querySelector('#child-name-input');
1353                        var parentName = container.querySelector('#parent-name-input');
1354                        var emailId = container.querySelector('input[type="email"]');
1355                        if (!childName || !childName.value) {
1356                            isValid = self.showError(currentStep, childName, 'Please enter child\'s name (required)');
1357                        }
1358                        if (!parentName || !parentName.value) {
1359                            isValid = self.showError(currentStep, parentName, 'Please enter parent\'s name (required)');
1360                        }
1361                        if (!emailId || !emailId.value) {
1362                            isValid = self.showError(currentStep, emailId, 'Please enter email ID (required)');
1363                        } else if (!/^\S+@\S+\.\S+$/.test(emailId.value)) {
1364                            isValid = self.showError(currentStep, emailId, 'Please enter a valid email address');
1365                        }
1366                    }
1367
1368                    if (!isValid) return;
1369
1370                    // Collect form data for the current step
1371                    var formData = self.collectFormData(container);
1372
1373                    // Make the API call but don't wait for it to complete
1374                    self.submitStepData(stepNumber, formData)
1375                        .catch(function(error) {
1376                            console.error('Error submitting step data:', error);
1377                            // Log the error but don't show it to the user
1378                            console.log('Error details:', {
1379                                step: stepNumber,
1380                                data: formData,
1381                                error: error
1382                            });
1383                        });
1384
1385                    if (stepNumber === 3) {
1386                        // Step 3 is the final step - submit the form and redirect
1387                        self.submitForm(container);
1388                        return;
1389                    }
1390
1391                    // Proceed to next step immediately without waiting for API response
1392                    var nextStep = container.querySelector('#booking-step' + nextStepNumber);
1393                    if (currentStep && nextStep) {
1394                        currentStep.classList.remove('active');
1395                        nextStep.classList.add('active');
1396                    }
1397                });
1398            });
1399
1400            // Handle input events to clear errors when user starts typing
1401            container.addEventListener('input', function(e) {
1402                if (e.target.tagName === 'INPUT') {
1403                    self.clearError(e.target);
1404                }
1405            });
1406
1407            // Handle back buttons
1408            var backButtons = container.querySelectorAll('.booking-back-button, .booking-back-btn');
1409            backButtons.forEach(function(button) {
1410                button.addEventListener('click', function() {
1411                    var stepNumber;
1412                    
1413                    if (this.classList.contains('booking-back-btn')) {
1414                        stepNumber = parseInt(this.getAttribute('data-step'));
1415                    } else {
1416                        var currentStep = container.querySelector('.booking-step-content.active');
1417                        var allSteps = container.querySelectorAll('.booking-step-content');
1418                        stepNumber = Array.from(allSteps).indexOf(currentStep) + 1;
1419                    }
1420                    
1421                    var prevStepNumber = stepNumber - 1;
1422                    
1423                    if (prevStepNumber > 0) {
1424                        var currentStep = container.querySelector('#booking-step' + stepNumber);
1425                        var prevStep = container.querySelector('#booking-step' + prevStepNumber);
1426                        
1427                        if (currentStep && prevStep) {
1428                            currentStep.classList.remove('active');
1429                            prevStep.classList.add('active');
1430                        }
1431                    }
1432                });
1433            });
1434
1435            // Handle grade (now age) selection
1436            container.addEventListener('click', function(e) {
1437                if (e.target.closest('.booking-grade-btn')) {
1438                    var gradeBtn = e.target.closest('.booking-grade-btn');
1439                    var gradeBtns = container.querySelectorAll('.booking-grade-btn');
1440                    
1441                    gradeBtns.forEach(function(btn) {
1442                        btn.classList.remove('active');
1443                        btn.style.border = '1px solid #ddd';
1444                        btn.style.backgroundColor = 'white';
1445                    });
1446                    
1447                    gradeBtn.classList.add('active');
1448                    gradeBtn.style.border = '1px solid #ffcf00';
1449                    gradeBtn.style.backgroundColor = 'rgba(255, 207, 0, 0.1)';
1450                    
1451                    // Clear any error messages
1452                    var gradeGrid = container.querySelector('.booking-grade-grid');
1453                    if (gradeGrid) {
1454                        var errorMessage = gradeGrid.nextElementSibling;
1455                        if (errorMessage && errorMessage.classList.contains('booking-error-message')) {
1456                            errorMessage.remove();
1457                        }
1458                    }
1459                }
1460            });
1461
1462            // Handle date selection
1463            container.addEventListener('click', function(e) {
1464                if (e.target.closest('.booking-date-btn')) {
1465                    var dateBtn = e.target.closest('.booking-date-btn');
1466                    var dateBtns = container.querySelectorAll('.booking-date-btn');
1467                    
1468                    dateBtns.forEach(function(btn) {
1469                        btn.classList.remove('active');
1470                        btn.style.border = '1px solid #ddd';
1471                        btn.style.backgroundColor = 'white';
1472                    });
1473                    
1474                    dateBtn.classList.add('active');
1475                    dateBtn.style.border = '1px solid #ffcf00';
1476                    dateBtn.style.backgroundColor = 'rgba(255, 207, 0, 0.1)';
1477                    
1478                    // Clear any error messages
1479                    var dateGrid = container.querySelector('.booking-date-grid');
1480                    if (dateGrid) {
1481                        var errorMessage = dateGrid.nextElementSibling;
1482                        if (errorMessage && errorMessage.classList.contains('booking-error-message')) {
1483                            errorMessage.remove();
1484                        }
1485                    }
1486
1487                    // Get the selected date and check if it's a weekend
1488                    var dayText = dateBtn.querySelector('div:first-child').textContent;
1489                    // Special case: Tuesday Dec 30, 2025 should have all slots open like a weekend
1490                    var isWeekend = dayText === 'Saturday' || dayText === 'Sunday' || dayText === 'Tuesday';
1491
1492                    // Get the current timezone
1493                    var timezoneSelect = container.querySelector('.booking-timezone-select');
1494                    var currentTimezone = timezoneSelect ? timezoneSelect.value : 'Asia/Kolkata';
1495
1496                    // Update time slots based on both timezone and weekend status
1497                    self.updateTimeSlotsBasedOnTimezone(currentTimezone);
1498                }
1499            });
1500
1501            // Handle time selection
1502            container.addEventListener('click', function(e) {
1503                if (e.target.closest('.booking-time-btn')) {
1504                    var timeBtn = e.target.closest('.booking-time-btn');
1505                    var timeBtns = container.querySelectorAll('.booking-time-btn');
1506                    
1507                    timeBtns.forEach(function(btn) {
1508                        btn.classList.remove('active');
1509                        btn.style.border = '1px solid #ddd';
1510                        btn.style.backgroundColor = 'white';
1511                    });
1512                    
1513                    timeBtn.classList.add('active');
1514                    timeBtn.style.border = '1px solid #ffcf00';
1515                    timeBtn.style.backgroundColor = 'rgba(255, 207, 0, 0.1)';
1516                    
1517                    // Clear any error messages
1518                    var timeGrid = container.querySelector('.booking-time-grid');
1519                    if (timeGrid) {
1520                        var errorMessage = timeGrid.nextElementSibling;
1521                        if (errorMessage && errorMessage.classList.contains('booking-error-message')) {
1522                            errorMessage.remove();
1523                        }
1524                    }
1525                }
1526            });
1527
1528            // Handle option buttons
1529            container.addEventListener('click', function(e) {
1530                if (e.target.closest('.booking-option-btn')) {
1531                    var optionBtn = e.target.closest('.booking-option-btn');
1532                    var optionGroup = optionBtn.closest('.booking-option-buttons');
1533                    var optionBtns = optionGroup.querySelectorAll('.booking-option-btn');
1534                    
1535                    optionBtns.forEach(function(btn) {
1536                        btn.classList.remove('active');
1537                        btn.style.border = '1px solid #ddd';
1538                        btn.style.backgroundColor = 'white';
1539                    });
1540                    
1541                    optionBtn.classList.add('active');
1542                    optionBtn.style.border = '1px solid #ffcf00';
1543                    optionBtn.style.backgroundColor = 'rgba(255, 207, 0, 0.1)';
1544                }
1545            });
1546        },
1547
1548        // Helper function to collect device and browser information
1549        getDeviceBrowserData: function() {
1550            var data = {
1551                // Browser information
1552                user_agent: navigator.userAgent || '',
1553                browser_language: navigator.language || navigator.userLanguage || '',
1554                browser_languages: navigator.languages ? navigator.languages.join(',') : '',
1555                platform: navigator.platform || '',
1556                vendor: navigator.vendor || '',
1557                cookies_enabled: navigator.cookieEnabled,
1558                do_not_track: navigator.doNotTrack || window.doNotTrack || navigator.msDoNotTrack || '',
1559                online: navigator.onLine,
1560                
1561                // Screen information
1562                screen_width: screen.width || 0,
1563                screen_height: screen.height || 0,
1564                screen_avail_width: screen.availWidth || 0,
1565                screen_avail_height: screen.availHeight || 0,
1566                screen_color_depth: screen.colorDepth || 0,
1567                screen_pixel_ratio: window.devicePixelRatio || 1,
1568                
1569                // Window/viewport information
1570                viewport_width: window.innerWidth || document.documentElement.clientWidth || 0,
1571                viewport_height: window.innerHeight || document.documentElement.clientHeight || 0,
1572                
1573                // Timezone information
1574                timezone_offset: new Date().getTimezoneOffset(),
1575                timezone_name: Intl.DateTimeFormat().resolvedOptions().timeZone || '',
1576                
1577                // Connection information (if available)
1578                connection_type: (navigator.connection && navigator.connection.effectiveType) || '',
1579                connection_downlink: (navigator.connection && navigator.connection.downlink) || '',
1580                
1581                // Device memory (if available)
1582                device_memory: navigator.deviceMemory || '',
1583                hardware_concurrency: navigator.hardwareConcurrency || '',
1584                
1585                // Touch capability
1586                touch_support: ('ontouchstart' in window) || (navigator.maxTouchPoints > 0),
1587                max_touch_points: navigator.maxTouchPoints || 0,
1588                
1589                // Referrer information
1590                referrer: document.referrer || '',
1591                
1592                // Local storage data
1593                local_storage_available: (function() {
1594                    try {
1595                        localStorage.setItem('test', 'test');
1596                        localStorage.removeItem('test');
1597                        return true;
1598                    } catch(e) {
1599                        return false;
1600                    }
1601                })(),
1602                session_storage_available: (function() {
1603                    try {
1604                        sessionStorage.setItem('test', 'test');
1605                        sessionStorage.removeItem('test');
1606                        return true;
1607                    } catch(e) {
1608                        return false;
1609                    }
1610                })()
1611            };
1612            
1613            // Collect relevant localStorage items (excluding sensitive data)
1614            var localStorageData = {};
1615            try {
1616                if (data.local_storage_available) {
1617                    for (var i = 0; i < localStorage.length; i++) {
1618                        var key = localStorage.key(i);
1619                        // Only collect booking/form related data, exclude sensitive items
1620                        if (key && (key.indexOf('booking') !== -1 || key.indexOf('form') !== -1 || key.indexOf('utm') !== -1 || key.indexOf('ref') !== -1)) {
1621                            localStorageData[key] = localStorage.getItem(key);
1622                        }
1623                    }
1624                }
1625            } catch(e) {
1626                console.log('Error reading localStorage:', e);
1627            }
1628            data.local_storage_data = localStorageData;
1629            
1630            // Collect relevant sessionStorage items
1631            var sessionStorageData = {};
1632            try {
1633                if (data.session_storage_available) {
1634                    for (var i = 0; i < sessionStorage.length; i++) {
1635                        var key = sessionStorage.key(i);
1636                        // Only collect booking/form related data
1637                        if (key && (key.indexOf('booking') !== -1 || key.indexOf('form') !== -1 || key.indexOf('utm') !== -1 || key.indexOf('ref') !== -1)) {
1638                            sessionStorageData[key] = sessionStorage.getItem(key);
1639                        }
1640                    }
1641                }
1642            } catch(e) {
1643                console.log('Error reading sessionStorage:', e);
1644            }
1645            data.session_storage_data = sessionStorageData;
1646            
1647            // Parse URL parameters for UTM tracking
1648            var urlParams = {};
1649            try {
1650                var searchParams = new URLSearchParams(window.location.search);
1651                searchParams.forEach(function(value, key) {
1652                    urlParams[key] = value;
1653                });
1654            } catch(e) {
1655                console.log('Error parsing URL params:', e);
1656            }
1657            data.url_params = urlParams;
1658            
1659            return data;
1660        },
1661
1662        // Add a method to send step data to the server
1663        submitStepData: function(stepNumber, formData) {
1664            console.log('Starting submitStepData for step:', stepNumber);
1665            console.log('Initial formData:', formData);
1666
1667            // Format the data according to the required structure based on available data
1668            var formattedData = {
1669                step: stepNumber,
1670                page_url: window.location.href // Add page URL to API request
1671            };
1672
1673            // Get timezone based on country code from step 1
1674            if (stepNumber >= 1) {
1675                var countrySelect = document.querySelector('.booking-country-code select');
1676                if (countrySelect) {
1677                    var countryCode = countrySelect.value;
1678                    formattedData.timezone = this.getDefaultTimezone(countryCode);
1679                    console.log('Using timezone from country code:', formattedData.timezone);
1680                }
1681            }
1682
1683            // Add IP address to the request
1684            if (stepNumber >= 1) {
1685                formattedData.ip_address = this.userCountry?.ip || '';
1686            }
1687
1688            // Add device and browser data for step 1
1689            if (stepNumber === 1) {
1690                var deviceBrowserData = this.getDeviceBrowserData();
1691                // Add IP address to device data
1692                deviceBrowserData.ip_address = this.userCountry?.ip || formattedData.ip_address || '';
1693                formattedData.device_data = deviceBrowserData;
1694                console.log('Device and browser data collected:', deviceBrowserData);
1695            }
1696
1697            // Override timezone with user selection in step 2
1698            if (stepNumber >= 2) {
1699                var timezoneSelect = document.querySelector('.booking-timezone-select');
1700                if (timezoneSelect && timezoneSelect.value) {
1701                    formattedData.timezone = timezoneSelect.value;
1702                    console.log('Using user selected timezone:', formattedData.timezone);
1703                }
1704            }
1705
1706            // Step 1: Phone and Age
1707            if (stepNumber >= 1) {
1708                console.log('Processing Step 1 data...');
1709                var countrySelect = document.querySelector('.booking-country-code select');
1710                var phoneInput = document.querySelector('input[type="tel"]');
1711                console.log('Country select element:', countrySelect);
1712                console.log('Phone input element:', phoneInput);
1713
1714                // Check if phone number exists in formData first
1715                if (formData.phone_number) {
1716                    formattedData.phone_number = formData.phone_number;
1717                    console.log('Using phone number from formData:', formattedData.phone_number);
1718                }
1719                // If not in formData, try to get from input elements
1720                else if (countrySelect && phoneInput && phoneInput.value) {
1721                    var countryCode = countrySelect.value;
1722                    var phoneNumber = phoneInput.value;
1723                    console.log('Country code:', countryCode);
1724                    console.log('Phone number:', phoneNumber);
1725
1726                    // Find the country dial code from the countriesList
1727                    var country = this.countriesList.find(function(c) {
1728                        return c.code.toLowerCase() === countryCode.toLowerCase();
1729                    });
1730                    console.log('Found country:', country);
1731
1732                    // Format phone number with proper dial code
1733                    if (country) {
1734                        // Remove any existing country code from the phone number
1735                        var cleanPhoneNumber = phoneNumber.replace(/^\+\d+/, '').replace(/\D/g, '');
1736                        formattedData.phone_number = country.dial_code + cleanPhoneNumber;
1737                    } else {
1738                        formattedData.phone_number = phoneNumber;
1739                    }
1740                    console.log('Formatted phone number:', formattedData.phone_number);
1741                }
1742
1743                // Get age from the selected grade button
1744                var selectedGrade = document.querySelector('.booking-grade-btn.active');
1745                if (selectedGrade) {
1746                    formattedData.age = selectedGrade.getAttribute('data-age');
1747                    console.log('Age:', formattedData.age);
1748                }
1749            }
1750
1751            // Step 2: Date and Time
1752            if (stepNumber >= 2) {
1753                console.log('Processing Step 2 data...');
1754                if (formData.selectedDate) {
1755                    formattedData.trial_date = formData.selectedDate;
1756                    console.log('Trial date:', formattedData.trial_date);
1757                }
1758                if (formData.selectedTime) {
1759                    formattedData.trial_time = formData.selectedTime;
1760                    console.log('Trial time:', formattedData.trial_time);
1761                }
1762            }
1763
1764            // Step 3: Child and Parent Details
1765            if (stepNumber >= 3) {
1766                console.log('Processing Step 3 data...');
1767                if (formData.childName) {
1768                    formattedData.child_name = formData.childName;
1769                    console.log('Child name:', formattedData.child_name);
1770                }
1771                if (formData.parentName) {
1772                    formattedData.parent_name = formData.parentName;
1773                    console.log('Parent name:', formattedData.parent_name);
1774                }
1775                if (formData.emailId) {
1776                    formattedData.email = formData.emailId;
1777                    console.log('Email:', formattedData.email);
1778                }
1779            }
1780
1781            // Step 4: Additional Information
1782            if (stepNumber >= 4) {
1783                console.log('Processing Step 4 data...');
1784                formattedData.booked_by = formData.userRole || 'Parent';
1785                formattedData.booking_reason = formData.bookingReason || 'Want to buy course';
1786                formattedData.purchase_plan = formData.purchaseTiming || 'This week';
1787                console.log('Step 4 data:', {
1788                    booked_by: formattedData.booked_by,
1789                    booking_reason: formattedData.booking_reason,
1790                    purchase_plan: formattedData.purchase_plan,
1791                    timezone: formattedData.timezone
1792                });
1793            }
1794
1795            console.log('Final formatted data:', formattedData);
1796
1797            // Only make the API call if we have the required data
1798            if (stepNumber === 1 && !formattedData.phone_number) {
1799                console.error('Phone number is required for step 1');
1800                return Promise.reject(new Error('Phone number is required'));
1801            }
1802
1803            // Only make the API call if we have some data to send
1804            if (Object.keys(formattedData).length > 2) { // More than just step and timezone
1805                console.log('Making API call to submit form data...');
1806                console.log('Request URL:', 'https://live.jetlearn.com/hooks/submit-form/');
1807                console.log('Request headers:', {
1808                    'Content-Type': 'application/json',
1809                    'Accept': 'application/json'
1810                });
1811                console.log('Request body:', JSON.stringify(formattedData, null, 2));
1812
1813                return fetch('https://live.jetlearn.com/hooks/submit-form/', {
1814                method: 'POST',
1815                    mode: 'cors',
1816                headers: {
1817                        'Content-Type': 'application/json',
1818                        'Accept': 'application/json'
1819                },
1820                    body: JSON.stringify(formattedData)
1821            })
1822            .then(function(response) {
1823                    console.log('Received API response:', {
1824                        status: response.status,
1825                        statusText: response.statusText,
1826                        headers: Object.fromEntries(response.headers.entries())
1827                    });
1828
1829                    return response.json().then(function(data) {
1830                        console.log('API response data:', data);
1831                        if (!response.ok || (data && data.status === 'error')) {
1832                            throw new Error(data.message || 'Failed to submit form data');
1833                        }
1834                        return data;
1835                    });
1836            })
1837            .catch(function(error) {
1838                    console.error('Error submitting form data:', error);
1839                    console.log('Error details:', {
1840                        step: stepNumber,
1841                        data: formattedData,
1842                        error: error.message,
1843                        stack: error.stack
1844                    });
1845                    throw error;
1846                });
1847            } else {
1848                console.log('No data to send, resolving promise');
1849                return Promise.resolve();
1850            }
1851        },
1852        
1853        // Helper function to create DOM elements
1854        createElement: function(tagName, options) {
1855            options = options || {};
1856            
1857            var element = document.createElement(tagName);
1858            
1859            if (options.className) {
1860                element.className = options.className;
1861            }
1862            
1863            if (options.id) {
1864                element.id = options.id;
1865            }
1866            
1867            if (options.attributes) {
1868                for (var key in options.attributes) {
1869                    if (options.attributes.hasOwnProperty(key)) {
1870                        element.setAttribute(key, options.attributes[key]);
1871                    }
1872                }
1873            }
1874            
1875            return element;
1876        },
1877        
1878        // Add country detection using IP
1879        detectCountry: function() {
1880            var self = this;
1881            
1882            // Try to get cached country data from sessionStorage
1883            var cachedCountry = sessionStorage.getItem('bookingFormCountry');
1884            if (cachedCountry) {
1885                console.log('Using cached country data');
1886                var countryData = JSON.parse(cachedCountry);
1887                self.updateCountryCodeDropdown(countryData);
1888                return Promise.resolve(countryData);
1889            }
1890
1891            // Default country data (India as default for faster loading)
1892            var defaultCountry = {
1893                code: 'in',
1894                dial_code: '+91',
1895                name: 'India',
1896                isIndia: true,
1897                timezone: 'Asia/Kolkata'
1898            };
1899
1900            // First set default country for immediate UI update
1901            self.updateCountryCodeDropdown(defaultCountry);
1902
1903            // Then fetch actual country and timezone in background
1904            return fetch('https://ipapi.co/json/?key=BZEnvu2Wh5giJT7yIUyoNpU95yPxX6QKXGfrmgLSzVCm9Rjiu7')
1905                .then(function(response) { 
1906                    if (!response.ok) {
1907                        throw new Error('Network response was not ok');
1908                    }
1909                    return response.json(); 
1910                })
1911                .then(function(data) {
1912                    console.log('IP API Response:', data);
1913                    
1914                    if (data && data.country_code) {
1915                        var countryCode = data.country_code.toLowerCase();
1916                        var country = self.findCountryByCode(countryCode);
1917                        var isIndia = countryCode === 'in';
1918
1919                        // Ensure we have a valid timezone
1920                        var timezone = data.timezone;
1921                        if (!timezone || timezone.trim() === '') {
1922                            timezone = self.getDefaultTimezone(countryCode);
1923                            console.log('Using default timezone for country:', timezone);
1924                        }
1925
1926                        // Store the IP address
1927                        var detectedCountry = {
1928                            code: countryCode,
1929                            dial_code: country.dial_code,
1930                            name: country.name,
1931                            isIndia: isIndia,
1932                            timezone: timezone,
1933                            ip: data.ip
1934                        };
1935
1936                        // Cache the country data
1937                        sessionStorage.setItem('bookingFormCountry', JSON.stringify(detectedCountry));
1938                        self.userCountry = detectedCountry;
1939                        self.updateCountryCodeDropdown(detectedCountry);
1940                        return Promise.resolve(detectedCountry);
1941                    }
1942                    console.log('Using default country data');
1943                    return defaultCountry;
1944                })
1945                .catch(function(error) {
1946                    console.error('Error during country detection:', error);
1947                    console.log('Using default country data due to error');
1948                    return defaultCountry;
1949                });
1950        },
1951
1952        // Add a new method to update the country code dropdown
1953        updateCountryCodeDropdown: function(country) {
1954            console.log('Updating country code dropdown with:', country);
1955            var countrySelect = document.querySelector('.booking-country-code select');
1956            if (countrySelect) {
1957                countrySelect.value = country.code;
1958
1959                // Trigger the change event to update related UI (e.g., time slots)
1960                var event = new Event('change');
1961                countrySelect.dispatchEvent(event);
1962                console.log('Country code dropdown updated successfully');
1963            } else {
1964                console.warn('Country code dropdown not found');
1965            }
1966        },
1967        
1968        // Find country by code in countries list
1969        findCountryByCode: function(code) {
1970            return this.countriesList.find(function(country) {
1971                return country.code.toLowerCase() === code.toLowerCase();
1972            });
1973        },
1974        
1975        // Add a countries list
1976        countriesList: [
1977            { name: 'Afghanistan', dial_code: '+93', code: 'af' },
1978            { name: 'Albania', dial_code: '+355', code: 'al' },
1979            { name: 'Algeria', dial_code: '+213', code: 'dz' },
1980            { name: 'American Samoa', dial_code: '+1-684', code: 'as' },
1981            { name: 'Andorra', dial_code: '+376', code: 'ad' },
1982            { name: 'Angola', dial_code: '+244', code: 'ao' },
1983            { name: 'Anguilla', dial_code: '+1-264', code: 'ai' },
1984            { name: 'Antarctica', dial_code: '+672', code: 'aq' },
1985            { name: 'Antigua and Barbuda', dial_code: '+1-268', code: 'ag' },
1986            { name: 'Argentina', dial_code: '+54', code: 'ar' },
1987            { name: 'Armenia', dial_code: '+374', code: 'am' },
1988            { name: 'Aruba', dial_code: '+297', code: 'aw' },
1989            { name: 'Australia', dial_code: '+61', code: 'au' },
1990            { name: 'Austria', dial_code: '+43', code: 'at' },
1991            { name: 'Azerbaijan', dial_code: '+994', code: 'az' },
1992            { name: 'Bahamas', dial_code: '+1-242', code: 'bs' },
1993            { name: 'Bahrain', dial_code: '+973', code: 'bh' },
1994            { name: 'Bangladesh', dial_code: '+880', code: 'bd' },
1995            { name: 'Barbados', dial_code: '+1-246', code: 'bb' },
1996            { name: 'Belarus', dial_code: '+375', code: 'by' },
1997            { name: 'Belgium', dial_code: '+32', code: 'be' },
1998            { name: 'Belize', dial_code: '+501', code: 'bz' },
1999            { name: 'Benin', dial_code: '+229', code: 'bj' },
2000            { name: 'Bermuda', dial_code: '+1-441', code: 'bm' },
2001            { name: 'Bhutan', dial_code: '+975', code: 'bt' },
2002            { name: 'Bolivia', dial_code: '+591', code: 'bo' },
2003            { name: 'Bosnia and Herzegovina', dial_code: '+387', code: 'ba' },
2004            { name: 'Botswana', dial_code: '+267', code: 'bw' },
2005            { name: 'Brazil', dial_code: '+55', code: 'br' },
2006            { name: 'British Indian Ocean Territory', dial_code: '+246', code: 'io' },
2007            { name: 'Brunei', dial_code: '+673', code: 'bn' },
2008            { name: 'Bulgaria', dial_code: '+359', code: 'bg' },
2009            { name: 'Burkina Faso', dial_code: '+226', code: 'bf' },
2010            { name: 'Burundi', dial_code: '+257', code: 'bi' },
2011            { name: 'Cambodia', dial_code: '+855', code: 'kh' },
2012            { name: 'Cameroon', dial_code: '+237', code: 'cm' },
2013            { name: 'Canada', dial_code: '+1', code: 'ca' },
2014            { name: 'Cape Verde', dial_code: '+238', code: 'cv' },
2015            { name: 'Cayman Islands', dial_code: '+1-345', code: 'ky' },
2016            { name: 'Central African Republic', dial_code: '+236', code: 'cf' },
2017            { name: 'Chad', dial_code: '+235', code: 'td' },
2018            { name: 'Chile', dial_code: '+56', code: 'cl' },
2019            { name: 'China', dial_code: '+86', code: 'cn' },
2020            { name: 'Christmas Island', dial_code: '+61', code: 'cx' },
2021            { name: 'Cocos (Keeling) Islands', dial_code: '+61', code: 'cc' },
2022            { name: 'Colombia', dial_code: '+57', code: 'co' },
2023            { name: 'Comoros', dial_code: '+269', code: 'km' },
2024            { name: 'Congo', dial_code: '+242', code: 'cg' },
2025            { name: 'Congo (Democratic Republic)', dial_code: '+243', code: 'cd' },
2026            { name: 'Cook Islands', dial_code: '+682', code: 'ck' },
2027            { name: 'Costa Rica', dial_code: '+506', code: 'cr' },
2028            { name: 'Côte d\'Ivoire', dial_code: '+225', code: 'ci' },
2029            { name: 'Croatia', dial_code: '+385', code: 'hr' },
2030            { name: 'Cuba', dial_code: '+53', code: 'cu' },
2031            { name: 'Curaçao', dial_code: '+599', code: 'cw' },
2032            { name: 'Cyprus', dial_code: '+357', code: 'cy' },
2033            { name: 'Czech Republic', dial_code: '+420', code: 'cz' },
2034            { name: 'Denmark', dial_code: '+45', code: 'dk' },
2035            { name: 'Djibouti', dial_code: '+253', code: 'dj' },
2036            { name: 'Dominica', dial_code: '+1-767', code: 'dm' },
2037            { name: 'Dominican Republic', dial_code: '+1-809', code: 'do' },
2038            { name: 'Ecuador', dial_code: '+593', code: 'ec' },
2039            { name: 'Egypt', dial_code: '+20', code: 'eg' },
2040            { name: 'El Salvador', dial_code: '+503', code: 'sv' },
2041            { name: 'Equatorial Guinea', dial_code: '+240', code: 'gq' },
2042            { name: 'Eritrea', dial_code: '+291', code: 'er' },
2043            { name: 'Estonia', dial_code: '+372', code: 'ee' },
2044            { name: 'Eswatini', dial_code: '+268', code: 'sz' },
2045            { name: 'Ethiopia', dial_code: '+251', code: 'et' },
2046            { name: 'Falkland Islands', dial_code: '+500', code: 'fk' },
2047            { name: 'Faroe Islands', dial_code: '+298', code: 'fo' },
2048            { name: 'Fiji', dial_code: '+679', code: 'fj' },
2049            { name: 'Finland', dial_code: '+358', code: 'fi' },
2050            { name: 'France', dial_code: '+33', code: 'fr' },
2051            { name: 'French Guiana', dial_code: '+594', code: 'gf' },
2052            { name: 'French Polynesia', dial_code: '+689', code: 'pf' },
2053            { name: 'French Southern Territories', dial_code: '', code: 'tf' },
2054            { name: 'Gabon', dial_code: '+241', code: 'ga' },
2055            { name: 'Gambia', dial_code: '+220', code: 'gm' },
2056            { name: 'Georgia', dial_code: '+995', code: 'ge' },
2057            { name: 'Germany', dial_code: '+49', code: 'de' },
2058            { name: 'Ghana', dial_code: '+233', code: 'gh' },
2059            { name: 'Gibraltar', dial_code: '+350', code: 'gi' },
2060            { name: 'Greece', dial_code: '+30', code: 'gr' },
2061            { name: 'Greenland', dial_code: '+299', code: 'gl' },
2062            { name: 'Grenada', dial_code: '+1-473', code: 'gd' },
2063            { name: 'Guadeloupe', dial_code: '+590', code: 'gp' },
2064            { name: 'Guam', dial_code: '+1-671', code: 'gu' },
2065            { name: 'Guatemala', dial_code: '+502', code: 'gt' },
2066            { name: 'Guernsey', dial_code: '+44', code: 'gg' },
2067            { name: 'Guinea', dial_code: '+224', code: 'gn' },
2068            { name: 'Guinea-Bissau', dial_code: '+245', code: 'gw' },
2069            { name: 'Guyana', dial_code: '+592', code: 'gy' },
2070            { name: 'Haiti', dial_code: '+509', code: 'ht' },
2071            { name: 'Heard Island and McDonald Islands', dial_code: '', code: 'hm' },
2072            { name: 'Holy See (Vatican City State)', dial_code: '+379', code: 'va' },
2073            { name: 'Honduras', dial_code: '+504', code: 'hn' },
2074            { name: 'Hong Kong', dial_code: '+852', code: 'hk' },
2075            { name: 'Hungary', dial_code: '+36', code: 'hu' },
2076            { name: 'Iceland', dial_code: '+354', code: 'is' },
2077            { name: 'India', dial_code: '+91', code: 'in' },
2078            { name: 'Indonesia', dial_code: '+62', code: 'id' },
2079            { name: 'Iran', dial_code: '+98', code: 'ir' },
2080            { name: 'Iraq', dial_code: '+964', code: 'iq' },
2081            { name: 'Ireland', dial_code: '+353', code: 'ie' },
2082            { name: 'Isle of Man', dial_code: '+44', code: 'im' },
2083            { name: 'Israel', dial_code: '+972', code: 'il' },
2084            { name: 'Italy', dial_code: '+39', code: 'it' },
2085            { name: 'Jamaica', dial_code: '+1-876', code: 'jm' },
2086            { name: 'Japan', dial_code: '+81', code: 'jp' },
2087            { name: 'Jersey', dial_code: '+44', code: 'je' },
2088            { name: 'Jordan', dial_code: '+962', code: 'jo' },
2089            { name: 'Kazakhstan', dial_code: '+7', code: 'kz' },
2090            { name: 'Kenya', dial_code: '+254', code: 'ke' },
2091            { name: 'Kiribati', dial_code: '+686', code: 'ki' },
2092            { name: 'North Korea', dial_code: '+850', code: 'kp' },
2093            { name: 'South Korea', dial_code: '+82', code: 'kr' },
2094            { name: 'Kuwait', dial_code: '+965', code: 'kw' },
2095            { name: 'Kyrgyzstan', dial_code: '+996', code: 'kg' },
2096            { name: 'Laos', dial_code: '+856', code: 'la' },
2097            { name: 'Latvia', dial_code: '+371', code: 'lv' },
2098            { name: 'Lebanon', dial_code: '+961', code: 'lb' },
2099            { name: 'Lesotho', dial_code: '+266', code: 'ls' },
2100            { name: 'Liberia', dial_code: '+231', code: 'lr' },
2101            { name: 'Libya', dial_code: '+218', code: 'ly' },
2102            { name: 'Liechtenstein', dial_code: '+423', code: 'li' },
2103            { name: 'Lithuania', dial_code: '+370', code: 'lt' },
2104            { name: 'Luxembourg', dial_code: '+352', code: 'lu' },
2105            { name: 'Macao', dial_code: '+853', code: 'mo' },
2106            { name: 'Madagascar', dial_code: '+261', code: 'mg' },
2107            { name: 'Malawi', dial_code: '+265', code: 'mw' },
2108            { name: 'Malaysia', dial_code: '+60', code: 'my' },
2109            { name: 'Maldives', dial_code: '+960', code: 'mv' },
2110            { name: 'Mali', dial_code: '+223', code: 'ml' },
2111            { name: 'Malta', dial_code: '+356', code: 'mt' },
2112            { name: 'Marshall Islands', dial_code: '+692', code: 'mh' },
2113            { name: 'Martinique', dial_code: '+596', code: 'mq' },
2114            { name: 'Mauritania', dial_code: '+222', code: 'mr' },
2115            { name: 'Mauritius', dial_code: '+230', code: 'mu' },
2116            { name: 'Mayotte', dial_code: '+262', code: 'yt' },
2117            { name: 'Mexico', dial_code: '+52', code: 'mx' },
2118            { name: 'Micronesia', dial_code: '+691', code: 'fm' },
2119            { name: 'Moldova', dial_code: '+373', code: 'md' },
2120            { name: 'Monaco', dial_code: '+377', code: 'mc' },
2121            { name: 'Mongolia', dial_code: '+976', code: 'mn' },
2122            { name: 'Montenegro', dial_code: '+382', code: 'me' },
2123            { name: 'Montserrat', dial_code: '+1-664', code: 'ms' },
2124            { name: 'Morocco', dial_code: '+212', code: 'ma' },
2125            { name: 'Mozambique', dial_code: '+258', code: 'mz' },
2126            { name: 'Myanmar', dial_code: '+95', code: 'mm' },
2127            { name: 'Namibia', dial_code: '+264', code: 'na' },
2128            { name: 'Nauru', dial_code: '+674', code: 'nr' },
2129            { name: 'Nepal', dial_code: '+977', code: 'np' },
2130            { name: 'Netherlands', dial_code: '+31', code: 'nl' },
2131            { name: 'New Caledonia', dial_code: '+687', code: 'nc' },
2132            { name: 'New Zealand', dial_code: '+64', code: 'nz' },
2133            { name: 'Nicaragua', dial_code: '+505', code: 'ni' },
2134            { name: 'Niger', dial_code: '+227', code: 'ne' },
2135            { name: 'Nigeria', dial_code: '+234', code: 'ng' },
2136            { name: 'Niue', dial_code: '+683', code: 'nu' },
2137            { name: 'Norfolk Island', dial_code: '+672', code: 'nf' },
2138            { name: 'North Macedonia', dial_code: '+389', code: 'mk' },
2139            { name: 'Northern Mariana Islands', dial_code: '+1-670', code: 'mp' },
2140            { name: 'Norway', dial_code: '+47', code: 'no' },
2141            { name: 'Oman', dial_code: '+968', code: 'om' },
2142            { name: 'Pakistan', dial_code: '+92', code: 'pk' },
2143            { name: 'Palau', dial_code: '+680', code: 'pw' },
2144            { name: 'Palestine', dial_code: '+970', code: 'ps' },
2145            { name: 'Panama', dial_code: '+507', code: 'pa' },
2146            { name: 'Papua New Guinea', dial_code: '+675', code: 'pg' },
2147            { name: 'Paraguay', dial_code: '+595', code: 'py' },
2148            { name: 'Peru', dial_code: '+51', code: 'pe' },
2149            { name: 'Philippines', dial_code: '+63', code: 'ph' },
2150            { name: 'Pitcairn', dial_code: '+64', code: 'pn' },
2151            { name: 'Poland', dial_code: '+48', code: 'pl' },
2152            { name: 'Portugal', dial_code: '+351', code: 'pt' },
2153            { name: 'Puerto Rico', dial_code: '+1-787', code: 'pr' },
2154            { name: 'Qatar', dial_code: '+974', code: 'qa' },
2155            { name: 'Réunion', dial_code: '+262', code: 're' },
2156            { name: 'Romania', dial_code: '+40', code: 'ro' },
2157            { name: 'Russia', dial_code: '+7', code: 'ru' },
2158            { name: 'Rwanda', dial_code: '+250', code: 'rw' },
2159            { name: 'Saint Barthélemy', dial_code: '+590', code: 'bl' },
2160            { name: 'Saint Helena, Ascension and Tristan da Cunha', dial_code: '+290', code: 'sh' },
2161            { name: 'Saint Kitts and Nevis', dial_code: '+1-869', code: 'kn' },
2162            { name: 'Saint Lucia', dial_code: '+1-758', code: 'lc' },
2163            { name: 'Saint Martin', dial_code: '+590', code: 'mf' },
2164            { name: 'Saint Pierre and Miquelon', dial_code: '+508', code: 'pm' },
2165            { name: 'Saint Vincent and the Grenadines', dial_code: '+1-784', code: 'vc' },
2166            { name: 'Samoa', dial_code: '+685', code: 'ws' },
2167            { name: 'San Marino', dial_code: '+378', code: 'sm' },
2168            { name: 'Sao Tome and Principe', dial_code: '+239', code: 'st' },
2169            { name: 'Saudi Arabia', dial_code: '+966', code: 'sa' },
2170            { name: 'Senegal', dial_code: '+221', code: 'sn' },
2171            { name: 'Serbia', dial_code: '+381', code: 'rs' },
2172            { name: 'Seychelles', dial_code: '+248', code: 'sc' },
2173            { name: 'Sierra Leone', dial_code: '+232', code: 'sl' },
2174            { name: 'Singapore', dial_code: '+65', code: 'sg' },
2175            { name: 'Sint Maarten', dial_code: '+1-721', code: 'sx' },
2176            { name: 'Slovakia', dial_code: '+421', code: 'sk' },
2177            { name: 'Slovenia', dial_code: '+386', code: 'si' },
2178            { name: 'Solomon Islands', dial_code: '+677', code: 'sb' },
2179            { name: 'Somalia', dial_code: '+252', code: 'so' },
2180            { name: 'South Africa', dial_code: '+27', code: 'za' },
2181            { name: 'South Georgia and the South Sandwich Islands', dial_code: '+500', code: 'gs' },
2182            { name: 'South Sudan', dial_code: '+211', code: 'ss' },
2183            { name: 'Spain', dial_code: '+34', code: 'es' },
2184            { name: 'Sri Lanka', dial_code: '+94', code: 'lk' },
2185            { name: 'Sudan', dial_code: '+249', code: 'sd' },
2186            { name: 'Suriname', dial_code: '+597', code: 'sr' },
2187            { name: 'Svalbard and Jan Mayen', dial_code: '+47', code: 'sj' },
2188            { name: 'Sweden', dial_code: '+46', code: 'se' },
2189            { name: 'Switzerland', dial_code: '+41', code: 'ch' },
2190            { name: 'Syria', dial_code: '+963', code: 'sy' },
2191            { name: 'Taiwan', dial_code: '+886', code: 'tw' },
2192            { name: 'Tajikistan', dial_code: '+992', code: 'tj' },
2193            { name: 'Tanzania', dial_code: '+255', code: 'tz' },
2194            { name: 'Thailand', dial_code: '+66', code: 'th' },
2195            { name: 'Timor-Leste', dial_code: '+670', code: 'tl' },
2196            { name: 'Togo', dial_code: '+228', code: 'tg' },
2197            { name: 'Tokelau', dial_code: '+690', code: 'tk' },
2198            { name: 'Tonga', dial_code: '+676', code: 'to' },
2199            { name: 'Trinidad and Tobago', dial_code: '+1-868', code: 'tt' },
2200            { name: 'Tunisia', dial_code: '+216', code: 'tn' },
2201            { name: 'Turkey', dial_code: '+90', code: 'tr' },
2202            { name: 'Turkmenistan', dial_code: '+993', code: 'tm' },
2203            { name: 'Turks and Caicos Islands', dial_code: '+1-649', code: 'tc' },
2204            { name: 'Tuvalu', dial_code: '+688', code: 'tv' },
2205            { name: 'Uganda', dial_code: '+256', code: 'ug' },
2206            { name: 'Ukraine', dial_code: '+380', code: 'ua' },
2207            { name: 'United Arab Emirates', dial_code: '+971', code: 'ae' },
2208            { name: 'United Kingdom', dial_code: '+44', code: 'gb' },
2209            { name: 'United States', dial_code: '+1', code: 'us' },
2210            { name: 'Uruguay', dial_code: '+598', code: 'uy' },
2211            { name: 'Uzbekistan', dial_code: '+998', code: 'uz' },
2212            { name: 'Vanuatu', dial_code: '+678', code: 'vu' },
2213            { name: 'Vatican City', dial_code: '+379', code: 'va' },
2214            { name: 'Venezuela', dial_code: '+58', code: 've' },
2215            { name: 'Vietnam', dial_code: '+84', code: 'vn' },
2216            { name: 'Virgin Islands (British)', dial_code: '+1-284', code: 'vg' },
2217            { name: 'Virgin Islands (U.S.)', dial_code: '+1-340', code: 'vi' },
2218            { name: 'Wallis and Futuna', dial_code: '+681', code: 'wf' },
2219            { name: 'Western Sahara', dial_code: '+212', code: 'eh' },
2220            { name: 'Yemen', dial_code: '+967', code: 'ye' },
2221            { name: 'Zambia', dial_code: '+260', code: 'zm' },
2222            { name: 'Zimbabwe', dial_code: '+263', code: 'zw' },
2223            { name: 'Åland Islands', dial_code: '+358', code: 'ax' }
2224        ],
2225        
2226        // Add timezone list with common timezones
2227        timezonesList: [
2228            { name: 'UTC', value: 'UTC' },
2229            { name: 'Africa/Abidjan', value: 'Africa/Abidjan' },
2230            { name: 'Africa/Accra', value: 'Africa/Accra' },
2231            { name: 'Africa/Addis Ababa', value: 'Africa/Addis_Ababa' },
2232            { name: 'Africa/Algiers', value: 'Africa/Algiers' },
2233            { name: 'Africa/Asmara', value: 'Africa/Asmara' },
2234            { name: 'Africa/Bamako', value: 'Africa/Bamako' },
2235            { name: 'Africa/Bangui', value: 'Africa/Bangui' },
2236            { name: 'Africa/Banjul', value: 'Africa/Banjul' },
2237            { name: 'Africa/Bissau', value: 'Africa/Bissau' },
2238            { name: 'Africa/Blantyre', value: 'Africa/Blantyre' },
2239            { name: 'Africa/Brazzaville', value: 'Africa/Brazzaville' },
2240            { name: 'Africa/Bujumbura', value: 'Africa/Bujumbura' },
2241            { name: 'Africa/Cairo', value: 'Africa/Cairo' },
2242            { name: 'Africa/Casablanca', value: 'Africa/Casablanca' },
2243            { name: 'Africa/Ceuta', value: 'Africa/Ceuta' },
2244            { name: 'Africa/Conakry', value: 'Africa/Conakry' },
2245            { name: 'Africa/Dakar', value: 'Africa/Dakar' },
2246            { name: 'Africa/Dar es Salaam', value: 'Africa/Dar_es_Salaam' },
2247            { name: 'Africa/Djibouti', value: 'Africa/Djibouti' },
2248            { name: 'Africa/Douala', value: 'Africa/Douala' },
2249            { name: 'Africa/El Aaiun', value: 'Africa/El_Aaiun' },
2250            { name: 'Africa/Freetown', value: 'Africa/Freetown' },
2251            { name: 'Africa/Gaborone', value: 'Africa/Gaborone' },
2252            { name: 'Africa/Harare', value: 'Africa/Harare' },
2253            { name: 'Africa/Johannesburg', value: 'Africa/Johannesburg' },
2254            { name: 'Africa/Juba', value: 'Africa/Juba' },
2255            { name: 'Africa/Kampala', value: 'Africa/Kampala' },
2256            { name: 'Africa/Khartoum', value: 'Africa/Khartoum' },
2257            { name: 'Africa/Kigali', value: 'Africa/Kigali' },
2258            { name: 'Africa/Kinshasa', value: 'Africa/Kinshasa' },
2259            { name: 'Africa/Lagos', value: 'Africa/Lagos' },
2260            { name: 'Africa/Libreville', value: 'Africa/Libreville' },
2261            { name: 'Africa/Lome', value: 'Africa/Lome' },
2262            { name: 'Africa/Luanda', value: 'Africa/Luanda' },
2263            { name: 'Africa/Lubumbashi', value: 'Africa/Lubumbashi' },
2264            { name: 'Africa/Lusaka', value: 'Africa/Lusaka' },
2265            { name: 'Africa/Malabo', value: 'Africa/Malabo' },
2266            { name: 'Africa/Maputo', value: 'Africa/Maputo' },
2267            { name: 'Africa/Maseru', value: 'Africa/Maseru' },
2268            { name: 'Africa/Mbabane', value: 'Africa/Mbabane' },
2269            { name: 'Africa/Mogadishu', value: 'Africa/Mogadishu' },
2270            { name: 'Africa/Monrovia', value: 'Africa/Monrovia' },
2271            { name: 'Africa/Nairobi', value: 'Africa/Nairobi' },
2272            { name: 'Africa/Ndjamena', value: 'Africa/Ndjamena' },
2273            { name: 'Africa/Niamey', value: 'Africa/Niamey' },
2274            { name: 'Africa/Nouakchott', value: 'Africa/Nouakchott' },
2275            { name: 'Africa/Ouagadougou', value: 'Africa/Ouagadougou' },
2276            { name: 'Africa/Porto-Novo', value: 'Africa/Porto-Novo' },
2277            { name: 'Africa/Sao Tome', value: 'Africa/Sao_Tome' },
2278            { name: 'Africa/Tripoli', value: 'Africa/Tripoli' },
2279            { name: 'Africa/Tunis', value: 'Africa/Tunis' },
2280            { name: 'Africa/Windhoek', value: 'Africa/Windhoek' },
2281            { name: 'America/Adak', value: 'America/Adak' },
2282            { name: 'America/Anchorage', value: 'America/Anchorage' },
2283            { name: 'America/Anguilla', value: 'America/Anguilla' },
2284            { name: 'America/Antigua', value: 'America/Antigua' },
2285            { name: 'America/Araguaina', value: 'America/Araguaina' },
2286            { name: 'America/Argentina/Buenos Aires', value: 'America/Argentina/Buenos_Aires' },
2287            { name: 'America/Argentina/Catamarca', value: 'America/Argentina/Catamarca' },
2288            { name: 'America/Argentina/Cordoba', value: 'America/Argentina/Cordoba' },
2289            { name: 'America/Argentina/Jujuy', value: 'America/Argentina/Jujuy' },
2290            { name: 'America/Argentina/La Rioja', value: 'America/Argentina/La_Rioja' },
2291            { name: 'America/Argentina/Mendoza', value: 'America/Argentina/Mendoza' },
2292            { name: 'America/Argentina/Rio Gallegos', value: 'America/Argentina/Rio_Gallegos' },
2293            { name: 'America/Argentina/Salta', value: 'America/Argentina/Salta' },
2294            { name: 'America/Argentina/San Juan', value: 'America/Argentina/San_Juan' },
2295            { name: 'America/Argentina/San Luis', value: 'America/Argentina/San_Luis' },
2296            { name: 'America/Argentina/Tucuman', value: 'America/Argentina/Tucuman' },
2297            { name: 'America/Argentina/Ushuaia', value: 'America/Argentina/Ushuaia' },
2298            { name: 'America/Aruba', value: 'America/Aruba' },
2299            { name: 'America/Asuncion', value: 'America/Asuncion' },
2300            { name: 'America/Atikokan', value: 'America/Atikokan' },
2301            { name: 'America/Bahia', value: 'America/Bahia' },
2302            { name: 'America/Bahia Banderas', value: 'America/Bahia_Banderas' },
2303            { name: 'America/Barbados', value: 'America/Barbados' },
2304            { name: 'America/Belem', value: 'America/Belem' },
2305            { name: 'America/Belize', value: 'America/Belize' },
2306            { name: 'America/Blanc-Sablon', value: 'America/Blanc-Sablon' },
2307            { name: 'America/Boa Vista', value: 'America/Boa_Vista' },
2308            { name: 'America/Bogota', value: 'America/Bogota' },
2309            { name: 'America/Boise', value: 'America/Boise' },
2310            { name: 'America/Cambridge Bay', value: 'America/Cambridge_Bay' },
2311            { name: 'America/Campo Grande', value: 'America/Campo_Grande' },
2312            { name: 'America/Cancun', value: 'America/Cancun' },
2313            { name: 'America/Caracas', value: 'America/Caracas' },
2314            { name: 'America/Cayenne', value: 'America/Cayenne' },
2315            { name: 'America/Cayman', value: 'America/Cayman' },
2316            { name: 'America/Chicago', value: 'America/Chicago' },
2317            { name: 'America/Chihuahua', value: 'America/Chihuahua' },
2318            { name: 'America/Costa Rica', value: 'America/Costa_Rica' },
2319            { name: 'America/Creston', value: 'America/Creston' },
2320            { name: 'America/Cuiaba', value: 'America/Cuiaba' },
2321            { name: 'America/Curacao', value: 'America/Curacao' },
2322            { name: 'America/Danmarkshavn', value: 'America/Danmarkshavn' },
2323            { name: 'America/Dawson', value: 'America/Dawson' },
2324            { name: 'America/Dawson Creek', value: 'America/Dawson_Creek' },
2325            { name: 'America/Denver', value: 'America/Denver' },
2326            { name: 'America/Detroit', value: 'America/Detroit' },
2327            { name: 'America/Dominica', value: 'America/Dominica' },
2328            { name: 'America/Edmonton', value: 'America/Edmonton' },
2329            { name: 'America/Eirunepe', value: 'America/Eirunepe' },
2330            { name: 'America/El Salvador', value: 'America/El_Salvador' },
2331            { name: 'America/Fort Nelson', value: 'America/Fort_Nelson' },
2332            { name: 'America/Fortaleza', value: 'America/Fortaleza' },
2333            { name: 'America/Glace Bay', value: 'America/Glace_Bay' },
2334            { name: 'America/Godthab', value: 'America/Godthab' },
2335            { name: 'America/Goose Bay', value: 'America/Goose_Bay' },
2336            { name: 'America/Grand Turk', value: 'America/Grand_Turk' },
2337            { name: 'America/Grenada', value: 'America/Grenada' },
2338            { name: 'America/Guadeloupe', value: 'America/Guadeloupe' },
2339            { name: 'America/Guatemala', value: 'America/Guatemala' },
2340            { name: 'America/Guayaquil', value: 'America/Guayaquil' },
2341            { name: 'America/Guyana', value: 'America/Guyana' },
2342            { name: 'America/Halifax', value: 'America/Halifax' },
2343            { name: 'America/Havana', value: 'America/Havana' },
2344            { name: 'America/Hermosillo', value: 'America/Hermosillo' },
2345            { name: 'America/Indiana/Indianapolis', value: 'America/Indiana/Indianapolis' },
2346            { name: 'America/Indiana/Knox', value: 'America/Indiana/Knox' },
2347            { name: 'America/Indiana/Marengo', value: 'America/Indiana/Marengo' },
2348            { name: 'America/Indiana/Petersburg', value: 'America/Indiana/Petersburg' },
2349            { name: 'America/Indiana/Tell City', value: 'America/Indiana/Tell_City' },
2350            { name: 'America/Indiana/Vevay', value: 'America/Indiana/Vevay' },
2351            { name: 'America/Indiana/Vincennes', value: 'America/Indiana/Vincennes' },
2352            { name: 'America/Indiana/Winamac', value: 'America/Indiana/Winamac' },
2353            { name: 'America/Inuvik', value: 'America/Inuvik' },
2354            { name: 'America/Iqaluit', value: 'America/Iqaluit' },
2355            { name: 'America/Jamaica', value: 'America/Jamaica' },
2356            { name: 'America/Juneau', value: 'America/Juneau' },
2357            { name: 'America/Kentucky/Louisville', value: 'America/Kentucky/Louisville' },
2358            { name: 'America/Kentucky/Monticello', value: 'America/Kentucky/Monticello' },
2359            { name: 'America/Kralendijk', value: 'America/Kralendijk' },
2360            { name: 'America/La Paz', value: 'America/La_Paz' },
2361            { name: 'America/Lima', value: 'America/Lima' },
2362            { name: 'America/Los Angeles', value: 'America/Los_Angeles' },
2363            { name: 'America/Lower Princes', value: 'America/Lower_Princes' },
2364            { name: 'America/Maceio', value: 'America/Maceio' },
2365            { name: 'America/Managua', value: 'America/Managua' },
2366            { name: 'America/Manaus', value: 'America/Manaus' },
2367            { name: 'America/Marigot', value: 'America/Marigot' },
2368            { name: 'America/Martinique', value: 'America/Martinique' },
2369            { name: 'America/Matamoros', value: 'America/Matamoros' },
2370            { name: 'America/Mazatlan', value: 'America/Mazatlan' },
2371            { name: 'America/Menominee', value: 'America/Menominee' },
2372            { name: 'America/Merida', value: 'America/Merida' },
2373            { name: 'America/Metlakatla', value: 'America/Metlakatla' },
2374            { name: 'America/Mexico City', value: 'America/Mexico_City' },
2375            { name: 'America/Miquelon', value: 'America/Miquelon' },
2376            { name: 'America/Moncton', value: 'America/Moncton' },
2377            { name: 'America/Monterrey', value: 'America/Monterrey' },
2378            { name: 'America/Montevideo', value: 'America/Montevideo' },
2379            { name: 'America/Montserrat', value: 'America/Montserrat' },
2380            { name: 'America/Nassau', value: 'America/Nassau' },
2381            { name: 'America/New York', value: 'America/New_York' },
2382            { name: 'America/Nipigon', value: 'America/Nipigon' },
2383            { name: 'America/Nome', value: 'America/Nome' },
2384            { name: 'America/Noronha', value: 'America/Noronha' },
2385            { name: 'America/North Dakota/Beulah', value: 'America/North_Dakota/Beulah' },
2386            { name: 'America/North Dakota/Center', value: 'America/North_Dakota/Center' },
2387            { name: 'America/North Dakota/New Salem', value: 'America/North_Dakota/New_Salem' },
2388            { name: 'America/Ojinaga', value: 'America/Ojinaga' },
2389            { name: 'America/Panama', value: 'America/Panama' },
2390            { name: 'America/Pangnirtung', value: 'America/Pangnirtung' },
2391            { name: 'America/Paramaribo', value: 'America/Paramaribo' },
2392            { name: 'America/Phoenix', value: 'America/Phoenix' },
2393            { name: 'America/Port-au-Prince', value: 'America/Port-au-Prince' },
2394            { name: 'America/Port of Spain', value: 'America/Port_of_Spain' },
2395            { name: 'America/Porto Velho', value: 'America/Porto_Velho' },
2396            { name: 'America/Puerto Rico', value: 'America/Puerto_Rico' },
2397            { name: 'America/Punta Arenas', value: 'America/Punta_Arenas' },
2398            { name: 'America/Rainy River', value: 'America/Rainy_River' },
2399            { name: 'America/Rankin Inlet', value: 'America/Rankin_Inlet' },
2400            { name: 'America/Recife', value: 'America/Recife' },
2401            { name: 'America/Regina', value: 'America/Regina' },
2402            { name: 'America/Resolute', value: 'America/Resolute' },
2403            { name: 'America/Rio Branco', value: 'America/Rio_Branco' },
2404            { name: 'America/Santarem', value: 'America/Santarem' },
2405            { name: 'America/Santiago', value: 'America/Santiago' },
2406            { name: 'America/Santo Domingo', value: 'America/Santo_Domingo' },
2407            { name: 'America/Sao Paulo', value: 'America/Sao_Paulo' },
2408            { name: 'America/Scoresbysund', value: 'America/Scoresbysund' },
2409            { name: 'America/Sitka', value: 'America/Sitka' },
2410            { name: 'America/St Barthelemy', value: 'America/St_Barthelemy' },
2411            { name: 'America/St Johns', value: 'America/St_Johns' },
2412            { name: 'America/St Kitts', value: 'America/St_Kitts' },
2413            { name: 'America/St Lucia', value: 'America/St_Lucia' },
2414            { name: 'America/St Thomas', value: 'America/St_Thomas' },
2415            { name: 'America/St Vincent', value: 'America/St_Vincent' },
2416            { name: 'America/Swift Current', value: 'America/Swift_Current' },
2417            { name: 'America/Tegucigalpa', value: 'America/Tegucigalpa' },
2418            { name: 'America/Thule', value: 'America/Thule' },
2419            { name: 'America/Thunder Bay', value: 'America/Thunder_Bay' },
2420            { name: 'America/Tijuana', value: 'America/Tijuana' },
2421            { name: 'America/Toronto', value: 'America/Toronto' },
2422            { name: 'America/Tortola', value: 'America/Tortola' },
2423            { name: 'America/Vancouver', value: 'America/Vancouver' },
2424            { name: 'America/Whitehorse', value: 'America/Whitehorse' },
2425            { name: 'America/Winnipeg', value: 'America/Winnipeg' },
2426            { name: 'America/Yakutat', value: 'America/Yakutat' },
2427            { name: 'America/Yellowknife', value: 'America/Yellowknife' },
2428            { name: 'Antarctica/Casey', value: 'Antarctica/Casey' },
2429            { name: 'Antarctica/Davis', value: 'Antarctica/Davis' },
2430            { name: 'Antarctica/DumontDUrville', value: 'Antarctica/DumontDUrville' },
2431            { name: 'Antarctica/Macquarie', value: 'Antarctica/Macquarie' },
2432            { name: 'Antarctica/Mawson', value: 'Antarctica/Mawson' },
2433            { name: 'Antarctica/McMurdo', value: 'Antarctica/McMurdo' },
2434            { name: 'Antarctica/Palmer', value: 'Antarctica/Palmer' },
2435            { name: 'Antarctica/Rothera', value: 'Antarctica/Rothera' },
2436            { name: 'Antarctica/Syowa', value: 'Antarctica/Syowa' },
2437            { name: 'Antarctica/Troll', value: 'Antarctica/Troll' },
2438            { name: 'Antarctica/Vostok', value: 'Antarctica/Vostok' },
2439            { name: 'Arctic/Longyearbyen', value: 'Arctic/Longyearbyen' },
2440            { name: 'Asia/Aden', value: 'Asia/Aden' },
2441            { name: 'Asia/Almaty', value: 'Asia/Almaty' },
2442            { name: 'Asia/Amman', value: 'Asia/Amman' },
2443            { name: 'Asia/Anadyr', value: 'Asia/Anadyr' },
2444            { name: 'Asia/Aqtau', value: 'Asia/Aqtau' },
2445            { name: 'Asia/Aqtobe', value: 'Asia/Aqtobe' },
2446            { name: 'Asia/Ashgabat', value: 'Asia/Ashgabat' },
2447            { name: 'Asia/Atyrau', value: 'Asia/Atyrau' },
2448            { name: 'Asia/Baghdad', value: 'Asia/Baghdad' },
2449            { name: 'Asia/Bahrain', value: 'Asia/Bahrain' },
2450            { name: 'Asia/Baku', value: 'Asia/Baku' },
2451            { name: 'Asia/Bangkok', value: 'Asia/Bangkok' },
2452            { name: 'Asia/Barnaul', value: 'Asia/Barnaul' },
2453            { name: 'Asia/Beirut', value: 'Asia/Beirut' },
2454            { name: 'Asia/Bishkek', value: 'Asia/Bishkek' },
2455            { name: 'Asia/Brunei', value: 'Asia/Brunei' },
2456            { name: 'Asia/Chita', value: 'Asia/Chita' },
2457            { name: 'Asia/Choibalsan', value: 'Asia/Choibalsan' },
2458            { name: 'Asia/Colombo', value: 'Asia/Colombo' },
2459            { name: 'Asia/Damascus', value: 'Asia/Damascus' },
2460            { name: 'Asia/Dhaka', value: 'Asia/Dhaka' },
2461            { name: 'Asia/Dili', value: 'Asia/Dili' },
2462            { name: 'Asia/Dubai', value: 'Asia/Dubai' },
2463            { name: 'Asia/Dushanbe', value: 'Asia/Dushanbe' },
2464            { name: 'Asia/Famagusta', value: 'Asia/Famagusta' },
2465            { name: 'Asia/Gaza', value: 'Asia/Gaza' },
2466            { name: 'Asia/Hebron', value: 'Asia/Hebron' },
2467            { name: 'Asia/Ho Chi Minh', value: 'Asia/Ho_Chi_Minh' },
2468            { name: 'Asia/Hong Kong', value: 'Asia/Hong_Kong' },
2469            { name: 'Asia/Hovd', value: 'Asia/Hovd' },
2470            { name: 'Asia/Irkutsk', value: 'Asia/Irkutsk' },
2471            { name: 'Asia/Jakarta', value: 'Asia/Jakarta' },
2472            { name: 'Asia/Jayapura', value: 'Asia/Jayapura' },
2473            { name: 'Asia/Jerusalem', value: 'Asia/Jerusalem' },
2474            { name: 'Asia/Kabul', value: 'Asia/Kabul' },
2475            { name: 'Asia/Kamchatka', value: 'Asia/Kamchatka' },
2476            { name: 'Asia/Karachi', value: 'Asia/Karachi' },
2477            { name: 'Asia/Kathmandu', value: 'Asia/Kathmandu' },
2478            { name: 'Asia/Khandyga', value: 'Asia/Khandyga' },
2479            { name: 'Asia/Kolkata', value: 'Asia/Kolkata' },
2480            { name: 'Asia/Krasnoyarsk', value: 'Asia/Krasnoyarsk' },
2481            { name: 'Asia/Kuala Lumpur', value: 'Asia/Kuala_Lumpur' },
2482            { name: 'Asia/Kuching', value: 'Asia/Kuching' },
2483            { name: 'Asia/Kuwait', value: 'Asia/Kuwait' },
2484            { name: 'Asia/Macau', value: 'Asia/Macau' },
2485            { name: 'Asia/Magadan', value: 'Asia/Magadan' },
2486            { name: 'Asia/Makassar', value: 'Asia/Makassar' },
2487            { name: 'Asia/Manila', value: 'Asia/Manila' },
2488            { name: 'Asia/Muscat', value: 'Asia/Muscat' },
2489            { name: 'Asia/Nicosia', value: 'Asia/Nicosia' },
2490            { name: 'Asia/Novokuznetsk', value: 'Asia/Novokuznetsk' },
2491            { name: 'Asia/Novosibirsk', value: 'Asia/Novosibirsk' },
2492            { name: 'Asia/Omsk', value: 'Asia/Omsk' },
2493            { name: 'Asia/Oral', value: 'Asia/Oral' },
2494            { name: 'Asia/Phnom Penh', value: 'Asia/Phnom_Penh' },
2495            { name: 'Asia/Pontianak', value: 'Asia/Pontianak' },
2496            { name: 'Asia/Pyongyang', value: 'Asia/Pyongyang' },
2497            { name: 'Asia/Qatar', value: 'Asia/Qatar' },
2498            { name: 'Asia/Qostanay', value: 'Asia/Qostanay' },
2499            { name: 'Asia/Qyzylorda', value: 'Asia/Qyzylorda' },
2500            { name: 'Asia/Riyadh', value: 'Asia/Riyadh' },
2501            { name: 'Asia/Sakhalin', value: 'Asia/Sakhalin' },
2502            { name: 'Asia/Samarkand', value: 'Asia/Samarkand' },
2503            { name: 'Asia/Seoul', value: 'Asia/Seoul' },
2504            { name: 'Asia/Shanghai', value: 'Asia/Shanghai' },
2505            { name: 'Asia/Singapore', value: 'Asia/Singapore' },
2506            { name: 'Asia/Srednekolymsk', value: 'Asia/Srednekolymsk' },
2507            { name: 'Asia/Taipei', value: 'Asia/Taipei' },
2508            { name: 'Asia/Tashkent', value: 'Asia/Tashkent' },
2509            { name: 'Asia/Tbilisi', value: 'Asia/Tbilisi' },
2510            { name: 'Asia/Tehran', value: 'Asia/Tehran' },
2511            { name: 'Asia/Thimphu', value: 'Asia/Thimphu' },
2512            { name: 'Asia/Tokyo', value: 'Asia/Tokyo' },
2513            { name: 'Asia/Tomsk', value: 'Asia/Tomsk' },
2514            { name: 'Asia/Ulaanbaatar', value: 'Asia/Ulaanbaatar' },
2515            { name: 'Asia/Urumqi', value: 'Asia/Urumqi' },
2516            { name: 'Asia/Ust-Nera', value: 'Asia/Ust-Nera' },
2517            { name: 'Asia/Vientiane', value: 'Asia/Vientiane' },
2518            { name: 'Asia/Vladivostok', value: 'Asia/Vladivostok' },
2519            { name: 'Asia/Yakutsk', value: 'Asia/Yakutsk' },
2520            { name: 'Asia/Yangon', value: 'Asia/Yangon' },
2521            { name: 'Asia/Yekaterinburg', value: 'Asia/Yekaterinburg' },
2522            { name: 'Asia/Yerevan', value: 'Asia/Yerevan' },
2523            { name: 'Atlantic/Azores', value: 'Atlantic/Azores' },
2524            { name: 'Atlantic/Bermuda', value: 'Atlantic/Bermuda' },
2525            { name: 'Atlantic/Canary', value: 'Atlantic/Canary' },
2526            { name: 'Atlantic/Cape Verde', value: 'Atlantic/Cape_Verde' },
2527            { name: 'Atlantic/Faroe', value: 'Atlantic/Faroe' },
2528            { name: 'Atlantic/Madeira', value: 'Atlantic/Madeira' },
2529            { name: 'Atlantic/Reykjavik', value: 'Atlantic/Reykjavik' },
2530            { name: 'Atlantic/South Georgia', value: 'Atlantic/South_Georgia' },
2531            { name: 'Atlantic/St Helena', value: 'Atlantic/St_Helena' },
2532            { name: 'Atlantic/Stanley', value: 'Atlantic/Stanley' },
2533            { name: 'Australia/Adelaide', value: 'Australia/Adelaide' },
2534            { name: 'Australia/Brisbane', value: 'Australia/Brisbane' },
2535            { name: 'Australia/Broken Hill', value: 'Australia/Broken_Hill' },
2536            { name: 'Australia/Currie', value: 'Australia/Currie' },
2537            { name: 'Australia/Darwin', value: 'Australia/Darwin' },
2538            { name: 'Australia/Eucla', value: 'Australia/Eucla' },
2539            { name: 'Australia/Hobart', value: 'Australia/Hobart' },
2540            { name: 'Australia/Lindeman', value: 'Australia/Lindeman' },
2541            { name: 'Australia/Lord Howe', value: 'Australia/Lord_Howe' },
2542            { name: 'Australia/Melbourne', value: 'Australia/Melbourne' },
2543            { name: 'Australia/Perth', value: 'Australia/Perth' },
2544            { name: 'Australia/Sydney', value: 'Australia/Sydney' },
2545            { name: 'Europe/Amsterdam', value: 'Europe/Amsterdam' },
2546            { name: 'Europe/Andorra', value: 'Europe/Andorra' },
2547            { name: 'Europe/Astrakhan', value: 'Europe/Astrakhan' },
2548            { name: 'Europe/Athens', value: 'Europe/Athens' },
2549            { name: 'Europe/Belgrade', value: 'Europe/Belgrade' },
2550            { name: 'Europe/Berlin', value: 'Europe/Berlin' },
2551            { name: 'Europe/Bratislava', value: 'Europe/Bratislava' },
2552            { name: 'Europe/Brussels', value: 'Europe/Brussels' },
2553            { name: 'Europe/Bucharest', value: 'Europe/Bucharest' },
2554            { name: 'Europe/Budapest', value: 'Europe/Budapest' },
2555            { name: 'Europe/Busingen', value: 'Europe/Busingen' },
2556            { name: 'Europe/Chisinau', value: 'Europe/Chisinau' },
2557            { name: 'Europe/Copenhagen', value: 'Europe/Copenhagen' },
2558            { name: 'Europe/Dublin', value: 'Europe/Dublin' },
2559            { name: 'Europe/Gibraltar', value: 'Europe/Gibraltar' },
2560            { name: 'Europe/Guernsey', value: 'Europe/Guernsey' },
2561            { name: 'Europe/Helsinki', value: 'Europe/Helsinki' },
2562            { name: 'Europe/Isle of Man', value: 'Europe/Isle_of_Man' },
2563            { name: 'Europe/Istanbul', value: 'Europe/Istanbul' },
2564            { name: 'Europe/Jersey', value: 'Europe/Jersey' },
2565            { name: 'Europe/Kaliningrad', value: 'Europe/Kaliningrad' },
2566            { name: 'Europe/Kiev', value: 'Europe/Kiev' },
2567            { name: 'Europe/Kirov', value: 'Europe/Kirov' },
2568            { name: 'Europe/Lisbon', value: 'Europe/Lisbon' },
2569            { name: 'Europe/Ljubljana', value: 'Europe/Ljubljana' },
2570            { name: 'Europe/London', value: 'Europe/London' },
2571            { name: 'Europe/Luxembourg', value: 'Europe/Luxembourg' },
2572            { name: 'Europe/Madrid', value: 'Europe/Madrid' },
2573            { name: 'Europe/Malta', value: 'Europe/Malta' },
2574            { name: 'Europe/Mariehamn', value: 'Europe/Mariehamn' },
2575            { name: 'Europe/Minsk', value: 'Europe/Minsk' },
2576            { name: 'Europe/Monaco', value: 'Europe/Monaco' },
2577            { name: 'Europe/Moscow', value: 'Europe/Moscow' },
2578            { name: 'Europe/Oslo', value: 'Europe/Oslo' },
2579            { name: 'Europe/Paris', value: 'Europe/Paris' },
2580            { name: 'Europe/Podgorica', value: 'Europe/Podgorica' },
2581            { name: 'Europe/Prague', value: 'Europe/Prague' },
2582            { name: 'Europe/Riga', value: 'Europe/Riga' },
2583            { name: 'Europe/Rome', value: 'Europe/Rome' },
2584            { name: 'Europe/Samara', value: 'Europe/Samara' },
2585            { name: 'Europe/San Marino', value: 'Europe/San_Marino' },
2586            { name: 'Europe/Sarajevo', value: 'Europe/Sarajevo' },
2587            { name: 'Europe/Saratov', value: 'Europe/Saratov' },
2588            { name: 'Europe/Simferopol', value: 'Europe/Simferopol' },
2589            { name: 'Europe/Skopje', value: 'Europe/Skopje' },
2590            { name: 'Europe/Sofia', value: 'Europe/Sofia' },
2591            { name: 'Europe/Stockholm', value: 'Europe/Stockholm' },
2592            { name: 'Europe/Tallinn', value: 'Europe/Tallinn' },
2593            { name: 'Europe/Tirane', value: 'Europe/Tirane' },
2594            { name: 'Europe/Ulyanovsk', value: 'Europe/Ulyanovsk' },
2595            { name: 'Europe/Uzhgorod', value: 'Europe/Uzhgorod' },
2596            { name: 'Europe/Vaduz', value: 'Europe/Vaduz' },
2597            { name: 'Europe/Vatican', value: 'Europe/Vatican' },
2598            { name: 'Europe/Vienna', value: 'Europe/Vienna' },
2599            { name: 'Europe/Vilnius', value: 'Europe/Vilnius' },
2600            { name: 'Europe/Volgograd', value: 'Europe/Volgograd' },
2601            { name: 'Europe/Warsaw', value: 'Europe/Warsaw' },
2602            { name: 'Europe/Zagreb', value: 'Europe/Zagreb' },
2603            { name: 'Europe/Zaporozhye', value: 'Europe/Zaporozhye' },
2604            { name: 'Europe/Zurich', value: 'Europe/Zurich' },
2605            { name: 'Indian/Antananarivo', value: 'Indian/Antananarivo' },
2606            { name: 'Indian/Chagos', value: 'Indian/Chagos' },
2607            { name: 'Indian/Christmas', value: 'Indian/Christmas' },
2608            { name: 'Indian/Cocos', value: 'Indian/Cocos' },
2609            { name: 'Indian/Comoro', value: 'Indian/Comoro' },
2610            { name: 'Indian/Kerguelen', value: 'Indian/Kerguelen' },
2611            { name: 'Indian/Mahe', value: 'Indian/Mahe' },
2612            { name: 'Indian/Maldives', value: 'Indian/Maldives' },
2613            { name: 'Indian/Mauritius', value: 'Indian/Mauritius' },
2614            { name: 'Indian/Mayotte', value: 'Indian/Mayotte' },
2615            { name: 'Indian/Reunion', value: 'Indian/Reunion' },
2616            { name: 'Pacific/Apia', value: 'Pacific/Apia' },
2617            { name: 'Pacific/Auckland', value: 'Pacific/Auckland' },
2618            { name: 'Pacific/Bougainville', value: 'Pacific/Bougainville' },
2619            { name: 'Pacific/Chatham', value: 'Pacific/Chatham' },
2620            { name: 'Pacific/Chuuk', value: 'Pacific/Chuuk' },
2621            { name: 'Pacific/Easter', value: 'Pacific/Easter' },
2622            { name: 'Pacific/Efate', value: 'Pacific/Efate' },
2623            { name: 'Pacific/Enderbury', value: 'Pacific/Enderbury' },
2624            { name: 'Pacific/Fakaofo', value: 'Pacific/Fakaofo' },
2625            { name: 'Pacific/Fiji', value: 'Pacific/Fiji' },
2626            { name: 'Pacific/Funafuti', value: 'Pacific/Funafuti' },
2627            { name: 'Pacific/Galapagos',
2627 value: 'Pacific/Galapagos' },
2628            { name: 'Pacific/Gambier', value: 'Pacific/Gambier' },
2629            { name: 'Pacific/Guadalcanal', value: 'Pacific/Guadalcanal' },
2630            { name: 'Pacific/Guam', value: 'Pacific/Guam' },
2631            { name: 'Pacific/Honolulu', value: 'Pacific/Honolulu' },
2632            { name: 'Pacific/Kanton', value: 'Pacific/Kanton' },
2633            { name: 'Pacific/Kiritimati', value: 'Pacific/Kiritimati' },
2634            { name: 'Pacific/Kosrae', value: 'Pacific/Kosrae' },
2635            { name: 'Pacific/Kwajalein', value: 'Pacific/Kwajalein' },
2636            { name: 'Pacific/Majuro', value: 'Pacific/Majuro' },
2637            { name: 'Pacific/Marquesas', value: 'Pacific/Marquesas' },
2638            { name: 'Pacific/Midway', value: 'Pacific/Midway' },
2639            { name: 'Pacific/Nauru', value: 'Pacific/Nauru' },
2640            { name: 'Pacific/Niue', value: 'Pacific/Niue' },
2641            { name: 'Pacific/Norfolk', value: 'Pacific/Norfolk' },
2642            { name: 'Pacific/Noumea', value: 'Pacific/Noumea' },
2643            { name: 'Pacific/Pago Pago', value: 'Pacific/Pago_Pago' },
2644            { name: 'Pacific/Palau', value: 'Pacific/Palau' },
2645            { name: 'Pacific/Pitcairn', value: 'Pacific/Pitcairn' },
2646            { name: 'Pacific/Pohnpei', value: 'Pacific/Pohnpei' },
2647            { name: 'Pacific/Port Moresby', value: 'Pacific/Port_Moresby' },
2648            { name: 'Pacific/Rarotonga', value: 'Pacific/Rarotonga' },
2649            { name: 'Pacific/Saipan', value: 'Pacific/Saipan' },
2650            { name: 'Pacific/Tahiti', value: 'Pacific/Tahiti' },
2651            { name: 'Pacific/Tarawa', value: 'Pacific/Tarawa' },
2652            { name: 'Pacific/Tongatapu', value: 'Pacific/Tongatapu' },
2653            { name: 'Pacific/Wake', value: 'Pacific/Wake' },
2654            { name: 'Pacific/Wallis', value: 'Pacific/Wallis' }
2655        ],
2656
2657        // Get default timezone based on country code
2658        getDefaultTimezone: function(countryCode) {
2659            var timezoneMap = {
2660                'in': 'Asia/Kolkata',
2661                'ae': 'Asia/Dubai',
2662                'sa': 'Asia/Riyadh',
2663                'qa': 'Asia/Qatar',
2664                'kw': 'Asia/Kuwait',
2665                'bh': 'Asia/Bahrain',
2666                'om': 'Asia/Muscat',
2667                'gb': 'Europe/London',
2668                'us': 'America/New_York',
2669                // Default European timezone
2670                'de': 'Europe/Berlin',
2671                'fr': 'Europe/Paris',
2672                'it': 'Europe/Rome',
2673                'es': 'Europe/Madrid',
2674                'nl': 'Europe/Amsterdam',
2675                'ch': 'Europe/Zurich',
2676                'be': 'Europe/Brussels',
2677                'se': 'Europe/Stockholm',
2678                'no': 'Europe/Oslo',
2679                'dk': 'Europe/Copenhagen',
2680                'fi': 'Europe/Helsinki',
2681                'ie': 'Europe/Dublin',
2682                'at': 'Europe/Vienna',
2683                'pt': 'Europe/Lisbon'
2684            };
2685            return timezoneMap[countryCode.toLowerCase()] || 'UTC';
2686        },
2687
2688
2689        // Create timezone dropdown
2690        createTimezoneSelect: function() {
2691            var self = this;
2692            var container = this.createElement('div', { className: 'booking-form-group' });
2693            
2694            var label = this.createElement('label', {});
2695            label.textContent = 'Your Time Zone';
2696            container.appendChild(label);
2697            
2698            var selectWrapper = this.createElement('div', { className: 'booking-select-wrapper' });
2699            
2700            var select = this.createElement('select', {
2701                className: 'booking-timezone-select',
2702                attributes: {
2703                    required: 'required'
2704                }
2705            });
2706
2707            // Add default option
2708            var defaultOption = this.createElement('option', {
2709                attributes: { value: '' }
2710            });
2711            defaultOption.textContent = 'Select timezone...';
2712            select.appendChild(defaultOption);
2713            
2714            // Add timezones to select
2715            this.timezonesList.forEach(function(tz) {
2716                var option = self.createElement('option', {
2717                    attributes: { value: tz.value }
2718                });
2719                option.textContent = tz.name;
2720                select.appendChild(option);
2721            });
2722            
2723            // Set timezone based on IP API response
2724            if (this.userCountry && this.userCountry.timezone) {
2725                var timezone = this.userCountry.timezone;
2726                console.log('Setting timezone from IP API:', timezone);
2727
2728                // Find the matching timezone in our list
2729                var matchingTimezone = this.timezonesList.find(function(tz) {
2730                    return tz.value === timezone;
2731                });
2732
2733                if (matchingTimezone) {
2734                    select.value = timezone;
2735                    console.log('Found exact timezone match:', timezone);
2736                } else {
2737                    // If exact match not found, try to find a similar timezone
2738                    var similarTimezone = this.timezonesList.find(function(tz) {
2739                        return tz.value.includes(timezone.split('/')[0]);
2740                    });
2741                    if (similarTimezone) {
2742                        select.value = similarTimezone.value;
2743                        console.log('Found similar timezone:', similarTimezone.value);
2744                    } else {
2745                        // If no match found, use the default timezone for the country
2746                        var defaultTimezone = this.getDefaultTimezone(this.userCountry.code);
2747                        select.value = defaultTimezone;
2748                        console.log('Using default timezone for country:', defaultTimezone);
2749                    }
2750                }
2751            } else {
2752                // If no timezone from IP API, use default
2753                var defaultTimezone = this.getDefaultTimezone('in'); // Default to India
2754                select.value = defaultTimezone;
2755                console.log('Using default timezone:', defaultTimezone);
2756            }
2757            
2758            selectWrapper.appendChild(select);
2759            container.appendChild(selectWrapper);
2760
2761            // Add help text
2762            var helpText = this.createElement('p', { className: 'booking-help-text' });
2763            helpText.textContent = 'All class times are shown in your local time zone';
2764            container.appendChild(helpText);
2765            
2766            // Update timezone when country changes
2767            var countrySelect = document.querySelector('.booking-country-code select');
2768            if (countrySelect) {
2769                countrySelect.addEventListener('change', function() {
2770                    // When country changes, update timezone based on IP API data
2771                    if (self.userCountry && self.userCountry.timezone) {
2772                        select.value = self.userCountry.timezone;
2773                        console.log('Timezone updated based on IP API:', self.userCountry.timezone);
2774                        self.updateTimeSlotsBasedOnTimezone(self.userCountry.timezone);
2775                    }
2776                });
2777            }
2778
2779            // Add event listener for timezone changes
2780            select.addEventListener('change', function() {
2781                var selectedTimezone = this.value;
2782                console.log('Timezone changed to:', selectedTimezone);
2783                self.updateTimeSlotsBasedOnTimezone(selectedTimezone);
2784            });
2785
2786            // Style the select
2787            select.style.width = '100%';
2788            select.style.padding = '12px';
2789            select.style.border = '1px solid #ddd';
2790            select.style.borderRadius = '8px';
2791            select.style.appearance = 'none';
2792            select.style.backgroundColor = 'white';
2793            select.style.cursor = 'pointer';
2794            select.style.fontSize = '14px';
2795            
2796            return container;
2797        },
2798
2799        // Add new method to update time slots based on timezone
2800        updateTimeSlotsBasedOnTimezone: function(timezone) {
2801            var container = document.querySelector('.booking-frame');
2802            if (!container) return;
2803
2804            // Get the selected date to determine if it's a weekend
2805            var selectedDate = container.querySelector('.booking-date-btn.active');
2806            var isWeekend = false;
2807            
2808            if (selectedDate) {
2809                var dayText = selectedDate.querySelector('div:first-child').textContent;
2810                // Special case: Tuesday Dec 30, 2025 should have all slots open like a weekend
2811                isWeekend = dayText === 'Saturday' || dayText === 'Sunday' || dayText === 'Tuesday';
2812            }
2813
2814            // Get the time grid
2815            var timeGrid = container.querySelector('.booking-time-grid');
2816            if (!timeGrid) return;
2817
2818            // Clear existing time slots
2819            while (timeGrid.firstChild) {
2820                timeGrid.removeChild(timeGrid.firstChild);
2821            }
2822
2823            // Create new time slots based on timezone and weekend status
2824            var timeSlots;
2825            if (timezone === 'Asia/Kolkata') {
2826                // India time slots
2827                if (isWeekend) {
2828                timeSlots = [
2829                        '10:30 AM', '11:30 AM', '12:30 PM',
2830                        '1:30 PM', '2:30 PM', '3:30 PM',
2831                        '4:30 PM', '5:30 PM', '6:30 PM',
2832                        '7:30 PM'
2833                ];
2834            } else {
2835                timeSlots = [
2836                        '4:30 PM', '5:30 PM', '6:30 PM', '7:30 PM'
2837                    ];
2838                }
2839            } else {
2840                // Rest of the world time slots
2841                if (isWeekend) {
2842                    timeSlots = [
2843                        '8:00 AM', '9:00 AM', '10:00 AM', '11:00 AM',
2844                        '12:00 PM', '1:00 PM', '2:00 PM', '3:00 PM',
2845                        '4:00 PM', '5:00 PM', '6:00 PM', '7:00 PM',
2846                        '8:00 PM'
2847                    ];
2848                } else {
2849                    timeSlots = [
2850                        '5:00 PM', '6:00 PM', '7:00 PM', '8:00 PM'
2851                    ];
2852                }
2853            }
2854
2855            // Add new time slots to the grid
2856            var self = this;
2857            timeSlots.forEach(function(time) {
2858                var timeBtn = self.createElement('button', {
2859                    className: 'booking-time-btn',
2860                    attributes: { 'type': 'button' }
2861                });
2862                timeBtn.textContent = time;
2863                timeGrid.appendChild(timeBtn);
2864            });
2865        },
2866        
2867        // Helper methods for date formatting
2868        getDayName: function(dayIndex) {
2869            var days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
2870            return days[dayIndex];
2871        },
2872        
2873        getMonthShortName: function(monthIndex) {
2874            var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
2875            return months[monthIndex];
2876        },
2877        
2878        // Add form submission and redirect method
2879        submitForm: function(container) {
2880            // Get form data
2881            var formData = this.collectFormData(container);
2882            
2883            // Log the form data
2884            console.log('Form submitted with data:', formData);
2885            
2886            // Redirect to JetLearn confirmation page
2887            window.location.href = 'https://www.jetlearn.com/thanks-for-registering';
2888        },
2889        
2890        // Update collectFormData to collect all required fields
2891        collectFormData: function(container) {
2892            var formData = {};
2893            
2894            // Add page URL to form data
2895            formData.page_url = window.location.href;
2896            
2897            // Get selected country and phone number
2898            var countrySelect = container.querySelector('select');
2899            var phoneInput = container.querySelector('input[type="tel"]');
2900            if (countrySelect && phoneInput) {
2901                var countryCode = countrySelect.value;
2902                var phoneNumber = phoneInput.value;
2903                // Find the country dial code from the countriesList
2904                var country = this.countriesList.find(function(c) {
2905                    return c.code.toLowerCase() === countryCode.toLowerCase();
2906                });
2907                // Format phone number with proper dial code
2908                formData.phone_number = country ? (country.dial_co
2908de + phoneNumber).replace(/\s+/g, '') : phoneNumber;
2909            }
2910            
2911            // Get selected grade
2912            var selectedGrade = container.querySelector('.booking-grade-btn.active');
2913            if (selectedGrade) {
2914                formData.grade = selectedGrade.getAttribute('data-grade');
2915            }
2916            
2917            // Get selected date and time
2918            var selectedDate = container.querySelector('.booking-date-btn.active');
2919            if (selectedDate) {
2920                var dayText = selectedDate.querySelector('div:first-child').textContent;
2921                var dateText = selectedDate.querySelector('div:last-child').textContent;
2922                
2923                // Parse the date from the selected button
2924                var date = new Date();
2925                if (dayText === 'Tomorrow') {
2926                    date.setDate(date.getDate() + 1);
2927                } else {
2928                    // Find the day index (0-6) for the selected day
2929                    var days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
2930                    var dayIndex = days.indexOf(dayText);
2931                    if (dayIndex !== -1) {
2932                        // Calculate days to add to reach the selected day
2933                        var currentDay = date.getDay();
2934                        var daysToAdd = (dayIndex - currentDay + 7) % 7;
2935                        date.setDate(date.getDate() + daysToAdd);
2936                    }
2937                }
2938                
2939                // Format date as YYYY-MM-DD
2940                formData.selectedDate = date.toISOString().split('T')[0];
2941                console.log('Selected date:', {
2942                    dayText: dayText,
2943                    dateText: dateText,
2944                    calculatedDate: formData.selectedDate
2945                });
2946            }
2947            
2948            var selectedTime = container.querySelector('.booking-time-btn.active');
2949            if (selectedTime) {
2950                // Format time as HH:MM
2951                var timeText = selectedTime.textContent;
2952                var timeMatch = timeText.match(/(\d+):(\d+)\s*(AM|PM)/i);
2953                if (timeMatch) {
2954                    var hours = parseInt(timeMatch[1]);
2955                    var minutes = timeMatch[2];
2956                    var period = timeMatch[3].toUpperCase();
2957                    
2958                    if (period === 'PM' && hours !== 12) {
2959                        hours += 12;
2960                    } else if (period === 'AM' && hours === 12) {
2961                        hours = 0;
2962                    }
2963                    
2964                    formData.selectedTime = hours.toString().padStart(2, '0') + ':' + minutes;
2965                }
2966            }
2967            
2968            // Get student details
2969            var childName = container.querySelector('#child-name-input');
2970            var parentName = container.querySelector('#parent-name-input');
2971            var emailId = container.querySelector('input[type="email"]');
2972            
2973            if (childName) formData.childName = childName.value;
2974            if (parentName) formData.parentName = parentName.value;
2975            if (emailId) formData.emailId = emailId.value;
2976            
2977            // Get optional survey responses from step 4
2978            var optionGroups = container.querySelectorAll('#booking-step4 .booking-option-buttons');
2979            optionGroups.forEach(function(group, index) {
2980                var selectedOption = group.querySelector('.booking-option-btn.active');
2981                if (selectedOption) {
2982                    switch(index) {
2983                        case 0:
2984                            formData.userRole = selectedOption.textContent;
2985                            break;
2986                        case 1:
2987                            formData.bookingReason = selectedOption.textContent;
2988                            break;
2989                        case 2:
2990                            formData.purchaseTiming = selectedOption.textContent;
2991                            break;
2992                    }
2993                }
2994            });
2995            
2996            return formData;
2997        },
2998
2999        // Add method to update time slots based on timezone
3000        updateTimeSlots: function(container, timezone) {
3001            var timeGrid = container.querySelector('.booking-time-grid');
3002            if (!timeGrid) return;
3003
3004            var dateBtn = container.querySelector('.booking-date-btn.active');
3005            if (!dateBtn) return;
3006
3007            var dayText = dateBtn.querySelector('div:first-child').textContent;
3008            // Special case: Tuesday Dec 30, 2025 should have all slots open like a weekend
3009            var isWeekend = dayText === 'Saturday' || dayText === 'Sunday' || dayText === 'Tuesday';
3010
3011            // Clear existing time slots
3012            while (timeGrid.firstChild) {
3013                timeGrid.removeChild(timeGrid.firstChild);
3014            }
3015
3016            // Get time slots based on country and day
3017            var timeSlots;
3018            if (this.userCountry && this.userCountry.isIndia) {
3019                if (isWeekend) {
3020                    timeSlots = ['10:30', '11:30', '12:30', '13:30', '14:30', '15:30', '16:30', '17:30', '18:30', '19:30'];
3021                } else {
3022                    timeSlots = ['16:30', '17:30', '18:30', '19:30'];
3023                }
3024            } else {
3025                if (isWeekend) {
3026                    timeSlots = ['08:00', '09:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00', '19:00', '20:00'];
3027                } else {
3028                    timeSlots = ['17:00', '18:00', '19:00', '20:00'];
3029                }
3030            }
3031
3032            // Create time buttons with converted times
3033            var self = this;
3034            timeSlots.forEach(function(time) {
3035                var timeBtn = self.createElement('button', {
3036                    className: 'booking-time-btn',
3037                    attributes: { 'type': 'button' }
3038                });
3039                
3040                // Convert time to selected timezone
3041                var localTime = self.convertTime(time, timezone);
3042                timeBtn.textContent = localTime;
3043                timeGrid.appendChild(timeBtn);
3044            });
3045        },
3046
3047        // Add method to convert time to selected timezone
3048        convertTime: function(time, timezone) {
3049            try {
3050                var today = new Date();
3051                var [hours, minutes] = time.split(':');
3052                today.setHours(parseInt(hours), parseInt(minutes), 0);
3053                
3054                var options = {
3055                    hour: 'numeric',
3056                    minute: 'numeric',
3057                    timeZone: timezone,
3058                    hour12: true
3059                };
3060                
3061                return new Intl.DateTimeFormat('en-US', options).format(today);
3062            } catch (error) {
3063                console.error('Error converting time:', error);
3064                return time;
3065            }
3066        },
3067
3068        // Update createTimeGrid to use fixed slots
3069        createTimeGrid: function(isWeekend) {
3070            var timeGrid = this.createElement('div', { className: 'booking-time-grid' });
3071            
3072            // Define time slots based on country and day
3073            var timeSlots;
3074            if (this.userCountry && this.userCountry.isIndia) {
3075                if (isWeekend) {
3076                    // Weekend slots for India: 10:30 AM to 7:30 PM
3077                    timeSlots = [
3078                        '10:30 AM', '11:30 AM', '12:30 PM',
3079                        '1:30 PM', '2:30 PM', '3:30 PM',
3080                        '4:30 PM', '5:30 PM', '6:30 PM',
3081                        '7:30 PM'
3082                    ];
3083                } else {
3084                    // Weekday slots for India: 4:30 PM to 7:30 PM
3085                    timeSlots = [
3086                        '4:30 PM', '5:30 PM', '6:30 PM', '7:30 PM'
3087                    ];
3088                }
3089            } else {
3090                if (isWeekend) {
3091                    // Weekend slots for ROW: 8:00 AM to 8:00 PM
3092                    timeSlots = [
3093                        '8:00 AM', '9:00 AM', '10:00 AM', '11:00 AM',
3094                        '12:00 PM', '1:00 PM', '2:00 PM', '3:00 PM',
3095                        '4:00 PM', '5:00 PM', '6:00 PM', '7:00 PM',
3096                        '8:00 PM'
3097                    ];
3098                } else {
3099                    // Weekday slots for ROW: 5:00 PM to 8:00 PM
3100                    timeSlots = [
3101                        '5:00 PM', '6:00 PM', '7:00 PM', '8:00 PM'
3102                    ];
3103                }
3104            }
3105            
3106            var self = this;
3107            timeSlots.forEach(function(time) {
3108                var timeBtn = self.createElement('button', {
3109                    className: 'booking-time-btn',
3110                    attributes: { 'type': 'button' }
3111                });
3112                timeBtn.textContent = time;
3113                timeGrid.appendChild(timeBtn);
3114            });
3115            
3116            return timeGrid;
3117        },
3118
3119        // Add a method to prefill and auto-progress with JLID data
3120        prefillAndProgressWithJLID: function(container) {
3121            var data = this.jlidData || {};
3122            // Step 1: phone and grade
3123            if (data.phone && data.grade) {
3124                // Prefill phone
3125                var phoneInput = container.querySelector('input[type="tel"]');
3126                if (phoneInput) phoneInput.value = data.phone.replace(/\D/g, '');
3127                // Prefill grade (age)
3128                var gradeBtn = container.querySelector('.booking-grade-btn[data-grade="' + data.grade + '"]');
3129                if (gradeBtn) {
3130                    gradeBtn.classList.add('active');
3131                    gradeBtn.style.border = '1px solid #ffcf00';
3132                    gradeBtn.style.backgroundColor = 'rgba(255, 207, 0, 0.1)';
3133                }
3134                // Go to step 2
3135                var step1 = container.querySelector('#booking-step1');
3136                var step2 = container.querySelector('#booking-step2');
3137                if (step1 && step2) {
3138                    step1.classList.remove('active');
3139                    step2.classList.add('active');
3140                }
3141            }
3142            // Step 2: date and time
3143            if (data.date && data.time) {
3144                // Prefill date
3145                var dateBtns = container.querySelectorAll('.booking-date-btn');
3146                dateBtns.forEach(function(btn) {
3147                    var dateDiv = btn.querySelector('div:last-child');
3148                    if (dateDiv && dateDiv.textContent && data.date) {
3149                        // Try to match by date string (e.g., '12 Jun')
3150                        if (dateDiv.textContent.trim() === data.date.trim()) {
3151                            btn.classList.add('active');
3152                            btn.style.border = '1px solid #ffcf00';
3153                            btn.style.backgroundColor = 'rgba(255, 207, 0, 0.1)';
3154                        } else {
3155                            btn.classList.remove('active');
3156                            btn.style.border = '1px solid #ddd';
3157                            btn.style.backgroundColor = 'white';
3158                        }
3159                    }
3160                });
3161                // Prefill time
3162                var timeBtns = container.querySelectorAll('.booking-time-btn');
3163                timeBtns.forEach(function(btn) {
3164                    if (btn.textContent.trim() === data.time.trim()) {
3165                        btn.classList.add('active');
3166                        btn.style.border = '1px solid #ffcf00';
3167                        btn.style.backgroundColor = 'rgba(255, 207, 0, 0.1)';
3168                    } else {
3169                        btn.classList.remove('active');
3170                        btn.style.border = '1px solid #ddd';
3171                        btn.style.backgroundColor = 'white';
3172                    }
3173                });
3174                // Go to step 3
3175                var step2 = container.querySelector('#booking-step2');
3176                var step3 = container.querySelector('#booking-step3');
3177                if (step2 && step3) {
3178                    step2.classList.remove('active');
3179                    step3.classList.add('active');
3180                }
3181            }
3182        }
3183    };
3184    
3185    // Make the form available globally with a unique name
3186    window.MultiStepBookingForm = {
3187        init: function(containerId) {
3188            BookingFormApp.init(containerId);
3189        }
3190    };
3191    
3192    // Auto-initialize when the DOM is ready
3193    if (document.readyState === 'loading') {
3194        document.addEventListener('DOMContentLoaded', function() {
3195            BookingFormApp.init();
3196        });
3197    } else {
3198        BookingFormApp.init();
3199    }
3200    
3201})(window, document);

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.