PageSourceSearch

https://harimaumalaya.com.my/wp-content/plugins/hmfl-registration/assets/js/registration.js?ver=1.0.5

js harimaumalaya.com.my collected 2026-10-10 02:27:31 UTC 25,266 bytes, 604 lines download raw bytes

1jQuery(document).ready(function($) {
2    'use strict';
3    
4    // Variables
5    let otpVerified = false;
6    let currentMobile = '';
7    
8    // Send OTP button click
9    $('#send-otp-btn').on('click', function(e) {
10        e.preventDefault();
11        
12        const mobile = $('#mobile').val().trim();
13        const $mobileField = $('#mobile');
14        const $mobileGroup = $mobileField.closest('.form-group');
15        
16        // Clear previous error
17        $mobileField.removeClass('error');
18        $mobileGroup.find('.field-error').remove();
19        
20        if (!mobile) {
21            $mobileField.addClass('error');
22            $mobileGroup.append('<div class="field-error">Please enter your mobile number.</div>');
23            return;
24        }
25        
26        // Validate Malaysian mobile number format (9-11 digits without +60)
27        if (!/^[0-9]{9,11}$/.test(mobile)) {
28            $mobileField.addClass('error');
29            $mobileGroup.append('<div class="field-error">Please enter a valid 9-11 digit mobile number (e.g., 123456789).</div>');
30            return;
31        }
32        
33        // Format full mobile number with +60 prefix for backend
34        // Remove leading 0 if present (Malaysian numbers don't have leading 0 after +60)
35        let formattedMobile = mobile;
36        if (mobile.startsWith('0')) {
37            formattedMobile = mobile.substring(1);
38            console.log('HMFL: Removed leading 0 from mobile number:', mobile, '->', formattedMobile);
39        }
40        const fullMobileNumber = '+60' + formattedMobile;
41        
42        // Debug logging
43        console.log('HMFL: Original mobile input:', mobile);
44        console.log('HMFL: Formatted mobile for backend:', fullMobileNumber);
45        console.log('HMFL: Mobile number validation passed');
46        
47        // Disable button and show loading text (without transparent effect)
48        const $btn = $(this);
49        const originalText = $btn.text();
50        $btn.prop('disabled', true).text('Sending...').addClass('sending');
51        
52        // Send AJAX request
53        console.log('HMFL: Sending AJAX request with mobile:', fullMobileNumber);
54        $.ajax({
55            url: hmfl_ajax.ajax_url,
56            type: 'POST',
57            data: {
58                action: 'hmfl_send_otp',
59                mobile: fullMobileNumber,
60                nonce: hmfl_ajax.nonce
61            },
62            success: function(response) {
63                console.log('HMFL: AJAX response:', response);
64                if (response.success) {
65                    // Show success message below mobile field
66                    const $mobileField = $('#mobile');
67                    const $mobileGroup = $mobileField.closest('.form-group');
68                    
69                    // Clear any previous error
70                    $mobileField.removeClass('error');
71                    $mobileGroup.find('.field-error').remove();
72                    
73                    // Add success message
74                    $mobileGroup.append('<div class="field-success">OTP sent successfully!</div>');
75                    
76                    currentMobile = fullMobileNumber;
77                    $('.otp-section').show();
78                    $('#mobile').prop('readonly', true);
79                    $('#send-otp-btn').hide();
80                    startOtpTimer();
81                } else {
82                    console.log('HMFL: AJAX error:', response.data.message);
83                    // Show error message directly below mobile field
84                    const $mobileField = $('#mobile');
85                    const $mobileGroup = $mobileField.closest('.form-group');
86                    
87                    // Clear any previous success message
88                    $mobileField.removeClass('error');
89                    $mobileGroup.find('.field-success').remove();
90                    
91                    // Add error message below mobile field
92                    $mobileGroup.append('<div class="field-error">' + response.data.message + '</div>');
93                    
94                    // Reset button state
95                    $btn.prop('disabled', false).text(originalText).removeClass('sending');
96                }
97            },
98            error: function(xhr, status, error) {
99                console.log('HMFL: AJAX error - Status:', status, 'Error:', error, 'Response:', xhr.responseText);
100                // Try to parse error response
101                let errorMessage = hmfl_ajax.messages.error;
102                try {
103                    const response = JSON.parse(xhr.responseText);
104                    if (response.data && response.data.message) {
105                        errorMessage = response.data.message;
106                    }
107                } catch (e) {
108                    console.log('HMFL: Could not parse error response');
109                }
110                
111                // Show error message directly below mobile field
112                const $mobileField = $('#mobile');
113                const $mobileGroup = $mobileField.closest('.form-group');
114                
115                // Clear any previous success message
116                $mobileField.removeClass('error');
117                $mobileGroup.find('.field-success').remove();
118                
119                // Add error message below mobile field
120                $mobileGroup.append('<div class="field-error">' + errorMessage + '</div>');
121                
122                $btn.prop('disabled', false).text(originalText).removeClass('sending');
123            }
124        });
125    });
126    
127    // Verify OTP button click
128    $('#verify-otp-btn').on('click', function(e) {
129        e.preventDefault();
130        
131        const otp = $('#otp_code').val().trim();
132        const $otpField = $('#otp_code');
133        const $otpGroup = $otpField.closest('.form-group');
134        
135        // Clear previous error
136        $otpField.removeClass('error');
137        $otpGroup.find('.field-error').remove();
138        
139        if (!otp) {
140            $otpField.addClass('error');
141            $otpGroup.append('<div class="field-error">Please enter the OTP code.</div>');
142            return;
143        }
144        
145        if (!/^[0-9]{6}$/.test(otp)) {
146            $otpField.addClass('error');
147            $otpGroup.append('<div class="field-error">
147Please enter a valid 6-digit OTP code.</div>');
148            return;
149        }
150        
151        // Disable button and show loading text (without transparent effect)
152        const $btn = $(this);
153        const originalText = $btn.text();
154        $btn.prop('disabled', true).text('Verifying...').addClass('verifying');
155        
156        // Send AJAX request
157        $.ajax({
158            url: hmfl_ajax.ajax_url,
159            type: 'POST',
160            data: {
161                action: 'hmfl_verify_otp',
162                mobile: currentMobile,
163                otp: otp,
164                nonce: hmfl_ajax.nonce
165            },
166            success: function(response) {
167                if (response.success) {
168                    // Show success message below OTP field
169                    const $otpField = $('#otp_code');
170                    const $otpGroup = $otpField.closest('.form-group');
171                    
172                    // Clear any previous error
173                    $otpField.removeClass('error');
174                    $otpGroup.find('.field-error').remove();
175                    
176                    // Add success message
177                    $otpGroup.append('<div class="field-success">OTP verified successfully!</div>');
178                    
179                    otpVerified = true;
180                    $('#otp_code').prop('readonly', true);
181                    // Keep button disabled and show "Verified" with checkmark
182                    $btn.prop('disabled', true).text('✓ Verified').removeClass('verifying').addClass('verified');
183                    checkFormValidity();
184                } else {
185                    showMessage(response.data.message, 'error');
186                    // Reset button on error
187                    $btn.prop('disabled', false).text(originalText).removeClass('verifying');
188                }
189            },
190            error: function(xhr, status, error) {
191                console.log('HMFL: OTP verification AJAX error - Status:', status, 'Error:', error, 'Response:', xhr.responseText);
192                // Try to parse error response
193                let errorMessage = hmfl_ajax.messages.error;
194                try {
195                    const response = JSON.parse(xhr.responseText);
196                    if (response.data && response.data.message) {
197                        errorMessage = response.data.message;
198                    }
199                } catch (e) {
200                    console.log('HMFL: Could not parse OTP verification error response');
201                }
202                showMessage(errorMessage, 'error');
203                // Reset button on error
204                $btn.prop('disabled', false).text(originalText).removeClass('verifying');
205            }
206        });
207    });
208    
209    // Form submission
210    $('#hmfl-registration-form').on('submit', function(e) {
211        e.preventDefault();
212        
213        // Validate form with field-specific errors
214        if (!validateForm()) {
215            return;
216        }
217        
218        // Disable submit button
219        const $submitBtn = $('#submit-registration');
220        const originalText = $submitBtn.text();
221        $submitBtn.prop('disabled', true).text('Submitting...').addClass('submitting');
222        
223        // Collect form data
224        const formData = {
225            action: 'hmfl_submit_registration',
226            nonce: hmfl_ajax.nonce,
227            full_name: $('#full_name').val().trim(),
228            gender: $('#gender').val(),
229            year_of_birth: $('#year_of_birth').val(),
230            state: $('#state').val(),
231            email: $('#email').val().trim(),
232            mobile: currentMobile,
233            fpl_team_name: $('#fpl_team_name').val().trim(),
234            consent_1: $('#consent_1').is(':checked'),
235            consent_2: $('#consent_2').is(':checked'),
236            consent_3: $('#consent_3').is(':checked')
237        };
238        
239        // Send AJAX request
240        $.ajax({
241            url: hmfl_ajax.ajax_url,
242            type: 'POST',
243            data: formData,
244            success: function(response) {
245                if (response.success) {
246                    // Reset submit button to normal state immediately
247                    $submitBtn.prop('disabled', false).text(originalText).removeClass('submitting');
248                    
249                    // Show success message with better styling
250                    const $messages = $('#hmfl-messages');
251                    $messages.html('<div class="message success">' + response.data.message + '<br><small>Page will reload in 3 seconds...</small></div>');
252                    
253                    // Reset form completely
254                    $('#hmfl-registration-form')[0].reset();
255                    resetForm();
256                    
257                    // Reload page after 3 seconds to show fresh form
258                    setTimeout(function() {
259                        window.location.reload();
260                    }, 3000);
261                } else {
262                    // Check if it's a mobile-related error
263                    const errorMessage = response.data.message;
264                    if (errorMessage.includes('mobile') || errorMessage.includes('Mobile')) {
265                        // Show mobile-related errors below mobile field
266                        const $mobileField = $('#mobile');
267                        const $mobileGroup = $mobileField.closest('.form-group');
268                        
269                        // Clear any previous messages
270                        $mobileField.removeClass('error');
271                        $mobileGroup.find('.field-error, .field-success').remove();
272                        
273                        // Add error message below mobile field
274                        $mobileGroup.append('<div class="field-error">' + errorMessage + '</div>');
275                    } else {
276                        // Show other errors in the general message area
277                        showMessage(errorMessage, 'error');
278                    }
279                    $submitBtn.prop('disabled', false).text(originalText).removeClass('submitting');
280                }
281            },
282            error: function(xhr, status, error) {
283                console.log('HMFL: Registration AJAX error - Status:', status, 'Error:', error, 'Response:', xhr.responseText);
284                // Try to parse error response
285                let errorMessage = hmfl_ajax.messages.error;
286                try {
287                    const response = JSON.parse(xhr.responseText);
288                    if (response.data && response.data.message) {
289                        errorMessage = response.data.message;
290                    }
291                } catch (e) {
292                    console.log('HMFL: Could not parse registration error response');
293                }
294                
295                // Check if it's a mobile-related error
296                if (errorMessage.includes('mobile') || errorMessage.includes('Mobile')) {
297                    // Show mobile-related errors below mobile field
298                    const $mobileField = $('#mobile');
299                    const $mobileGroup = $mobileField.closest('.form-group');
300                    
301                    // Clear any previous messages
302                    $mobileField.removeClass('error');
303                    $mobileGroup.find('.field-error, .field-success').remove();
304                    
305                    // Add error message below mobile field
306                    $mobileGroup.append('<div class="field-error">' + errorMessage + '</div>');
307                } else {
308                    // Show other errors in the general message area
309                    showMessage(errorMessage, 'error');
310                }
311                $submitBtn.prop('disabled', false).text(originalText).removeClass('submitting');
312            }
313        });
314    });
315    
316    // Real-time form validation
317    $('#hmfl-registration-form input, #hmfl-registration-form select').on('change keyup', function() {
318        const $field = $(this);
319        const $fieldGroup = $field.closest('.form-group');
320        
321        // Remove existing error for this field
322        $field.removeClass('error');
323        $fieldGroup.find('.field-error').remove();
324        
325        // Validate specific field
326        if ($field.attr('id') === 'email') {
327            const email = $field.val();
328            if (email && !isValidEmail(email)) {
329                $field.addClass('error');
330                $fieldGroup.append('<div class="field-error">Please enter a valid email address.</div>');
331            }
332        } else if ($field.attr('id') === 'mobile') {
333            const mobile = $field.val().trim();
334            if (mobile && !/^[0-9]{9,11}$/.test(mobile)) {
335                $field.addClass('error');
336                $fieldGroup.append('<div class="field-error">Please enter a valid 9-11 digit mobile number (e.g., 123456789).</div>');
337            }
338        } else if ($field.attr('id') === 'otp_code') {
339            if (!otpVerified && $field.val()) {
340                $field.addClass('error');
341                $fieldGroup.append('<div class="field-error">Please verify your mobile number with OTP.</div>');
342            }
343        }
344        
345        checkFormValidity();
346    });
347    
348    // Checkboxes change
349    $('#consent_1, #consent_2, #consent_3').on('change', function() {
350        const $consent1 = $('#consent_1');
351        const $consent2 = $('#consent_2');
352        const $consent3 = $('#consent_3');
353        const $consentGroup = $consent1.closest('.form-group');
354        
355        // Remove existing error
356        $consent1.removeClass('error');
357        $consent2.removeClass('error');
358        $consent3.removeClass('error');
359        $consentGroup.find('.field-error').remove();
360        
361        // Check if all three consents are checked
362        if (!$consent1.is(':checked') || !$consent2.is(':checked') || !$consent3.is(':checked')) {
363            $consent1.addClass('error');
364            $consent2.addClass('error');
365            $consent3.addClass('error');
366            $consentGroup.append('<div class="field-error">Please agree to all consent terms.</div>');
367        }
368        
369        checkFormValidity();
370    });
371    
372    // Mobile number input validation
373    $('#mobile').on('input', function() {
374        const value = $(this).val();
375        // Only allow numbers
376        $(this).val(value.replace(/[^0-9]/g, ''));
377        
378        // Enable/disable send OTP button
379        if (value.length >= 9) {
380            $('#send-otp-btn').prop('disabled', false);
381        } else {
382            $('#send-otp-btn').prop('disabled', true);
383        }
384    });
385    
386    // OTP input validation
387    $('#otp_code').on('input', function() {
388        const value = $(this).val();
389        // Only allow numbers
390        $(this).val(value.replace(/[^0-9]/g, ''));
391    });
392    
393    // Functions
394    function validateForm() {
395        const requiredFields = ['#full_name', '#gender', '#year_of_birth', '#state', '#email', '#fpl_team_name'];
396        let isValid = true;
397        
398        // Clear all previous error messages
399        $('.field-error').remove();
400        
401        // Check required fields
402        requiredFields.forEach(function(field) {
403            const $field = $(field);
404            const $fieldGroup = $field.closest('.form-group');
405            
406            if (!$field.val()) {
407                $field.addClass('error');
408                $fieldGroup.append('<div class="field-error">This field is required.</div>');
409                isValid = false;
410            } else {
411                $field.removeClass('error');
412            }
413        });
414        
415        // Check email format
416        const email = $('#email').val();
417        const $emailField = $('#email');
418        const $emailGroup = $emailField.closest('.form-group');
419        
420        if (email && !isValidEmail(email)) {
421            $emailField.addClass('error');
422            $emailGroup.append('<div class="field-error">Please enter a valid email address.</div>');
423            isValid = false;
424        } else if (email) {
425            $emailField.removeClass('error');
426        }
427        
428        // Check mobile number
429        const mobile = $('#mobile').val().trim();
430        const $mobileField = $('#mobile');
431        const $mobileGroup = $mobileField.closest('.form-group');
432        
433        if (!mobile) {
434            $mobileField.addClass('error');
435            $mobileGroup.append('<div class="field-error">Please enter your mobile number.</div>');
436            isValid = false;
437        } else if (!/^[0-9]{9,11}$/.test(mobile)) {
438            $mobileField.addClass('error');
439            $mobileGroup.append('<div class="field-error">Please enter a valid 9-11 digit mobile number (e.g., 123456789).</div>');
440            isValid = false;
441        } else {
442            $mobileField.removeClass('error');
443        }
444        
445        // Check OTP verification
446        if (!otpVerified) {
447            const $otpField = $('#otp_code');
448            const $otpGroup = $otpField.closest('.form-group');
449            $otpField.addClass('error');
450            $otpGroup.append('<div class="field-error">Please verify your mobile number with OTP.</div>');
451            isValid = false;
452        }
453        
454        // Check consents
455        const $consent1 = $('#consent_1');
456        const $consent2 = $('#consent_2');
457        const $consent3 = $('#consent_3');
458        const $consentGroup = $consent1.closest('.form-group');
459        
460        if (!$consent1.is(':checked') || !$consent2.is(':checked') || !$consent3.is(':checked')) {
461            $consent1.addClass('error');
462            $consent2.addClass('error');
463            $consent3.addClass('error');
464            $consentGroup.append('<div class="field-error">Please agree to all consent terms.</div>');
465            isValid = false;
466        } else {
467            $consent1.removeClass('error');
468            $consent2.removeClass('error');
469            $consent3.removeClass('error');
470        }
471        
472        return isValid;
473    }
474    
475    function checkFormValidity() {
476        const requiredFields = ['#full_name', '#gender', '#year_of_birth', '#state', '#email', '#fpl_team_name'];
477        let allFieldsFilled = true;
478        
479        requiredFields.forEach(function(field) {
480            if (!$(field).val()) {
481                allFieldsFilled = false;
482            }
483        });
484        
485        const email = $('#email').val();
486        const emailValid = email && isValidEmail(email);
487        const consentsChecked = $('#consent_1').is(':checked') && $('#consent_2').is(':checked') && $('#consent_3').is(':checked');
488        
489        if (allFieldsFilled && emailValid && consentsChecked && otpVerified) {
490            $('#submit-registration').prop('disabled', false);
491        } else {
492            $('#submit-registration').prop('disabled', true);
493        }
494    }
495    
496    function isValidEmail(email) {
497        const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
498        return emailRegex.test(email);
499    }
500    
501    function showMessage(message, type) {
502        const $messages = $('#hmfl-messages');
503        const messageClass = type === 'success' ? 'success' : 'error';
504        
505        // Clear any existing messages first
506        $messages.empty();
507        
508        // Create the message element
509        const $messageElement = $('<div class="message ' + messageClass + '">' + message + '</div>');
510        $messages.append($messageElement);
511        
512        // For error messages, don't auto-hide them - let user dismiss manually
513        if (type === 'error') {
514            // Add a close button for error messages
515            $messageElement.append('<button type="button" class="message-close" style="float: right; background: none; border: none; font-size: 18px; cursor: pointer; color: inherit;">&times;</button>');
516            
517            // Handle close button click
518            $messageElement.find('.message-close').on('click', function() {
519                $messageElement.fadeOut();
520            });
521            
522            // Auto-hide after 10 seconds instead of 5 for errors
523            setTimeout(function() {
524                if ($messageElement.is(':visible')) {
525                    $messageElement.fadeOut();
526                }
527            }, 10000);
528        } else {
529            // Auto-hide success messages after 5 seconds
530            setTimeout(function() {
531                if ($messageElement.is(':visible')) {
532                    $messageElement.fadeOut();
533                }
534            }, 5000);
535        }
536        
537        // Scroll to message if it's not visible
538        $('html, body').animate({
539            scrollTop: $messages.offset().top - 100
540        }, 500);
541    }
542    
543    function resetForm() {
544        otpVerified = false;
545        currentMobile = '';
546        $('.otp-section').hide();
547        $('#mobile').prop('readonly', false).val('');
548        $('#send-otp-btn').show().prop('disabled', true).text('Send OTP').removeClass('sending verifying');
549        $('#otp_code').prop('readonly', false).val('');
550        $('#verify-otp-btn').prop('disabled', false).text('Verify OTP').removeClass('verified verifying');
551        $('#submit-registration').prop('disabled', true).text('Submit Registration').removeClass('submitting');
552        $('.form-group').removeClass('error');
553        $('.field-error, .field-success').remove();
554        
555        // Clear any existing timers
556        if (window.otpTimer) {
557            clearInterval(window.otpTimer);
558            window.otpTimer = null;
559        }
560    }
561    
562    function startOtpTimer() {
563        let timeLeft = 300; // 5 minutes in seconds
564        const $btn = $('#send-otp-btn');
565        
566        // Clear any existing timer
567        if (window.otpTimer) {
568            clearInterval(window.otpTimer);
569        }
570        
571        window.otpTimer = setInterval(function() {
572            const minutes = Math.floor(timeLeft / 60);
573            const seconds = timeLeft % 60;
574            
575            if (timeLeft <= 0) {
576                clearInterval(window.otpTimer);
577                window.otpTimer = null;
578                showMessage('OTP has expired. Please request a new one.', 'error');
579                resetOtpSection();
580            } else {
581                $btn.text('Resend OTP (' + minutes + ':' + (seconds < 10 ? '0' : '') + seconds + ')');
582            }
583            
584            timeLeft--;
585        }, 1000);
586    }
587    
588    function resetOtpSection() {
589        $('.otp-section').hide();
590        $('#mobile').prop('readonly', false);
591        $('#send-otp-btn').show().prop('disabled', false).text('Send OTP').removeClass('sending');
592        $('#otp_code').val('');
593        $('#verify-otp-btn').prop('disabled', false).text('Verify OTP').removeClass('verified verifying');
594        $('.field-error, .field-success').remove();
595        otpVerified = false;
596        currentMobile = '';
597        
598        // Clear any existing timer
599        if (window.otpTimer) {
600            clearInterval(window.otpTimer);
601            window.otpTimer = null;
602        }
603    }
604}); 

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.