PageSourceSearch

https://cdncontent.bitszol.com/js/custom/sitebundle.min.js?v=639258560040000000

js bitszol.com collected 2026-10-02 00:47:23 UTC 191,706 bytes, 4,252 lines download raw bytes

1var authentication = (function () {
2    var authenticationMethods = {}, authenticationPrivateMethods = {};
3
4    authenticationMethods.events = {};
5
6    authenticationMethods.properties = {
7        captchaKey: '6LfH-lQiAAAAADWzik-dFOIjWgWiOdl4KwB4DloL',
8        isCaptchaEnabled: true,
9        fedAuthFLKey: '380038002695511',
10        fedGoogleAuthClientId: '63048652837-uajuv9lc6se95hct2ef7r8tsnos81u1c.apps.googleusercontent.com',
11        newemail: '',
12        newMobile: '',
13        signupEmail: '',
14        signupName: '',
15        signupPhone: '',
16        password: ''
17    };
18    authenticationPrivateMethods.properties = {
19        isOtpTriggered: false,
20        tmrCountdownId: null,
21        verifyPsw: 'Authentication/VerifyPsw',
22        updateStatusHandler: '/UpdateVerifiedStatus',
23        countryCodeList: {
24            "UK": "GB",
25            "UAE": "AE"
26        }
27    };
28    authenticationMethods.url = {
29        getOtp: '/Authentication/GetOtp',
30        verifyOtp: '/Authentication/VerifyOtp',
31        signUp: '/Authentication/SignUp',
32        redirectUrl: '',
33        resendOtp: '',
34        getEmailOtp: '/login/validateemail',
35        fedRedirectUrl: 'https://www.bitszol.com'
36    };
37    authenticationMethods.messages = {
38        phoneExistsAlert: 'This phone number is already registered. Please use a different number.',
39        emailExistsAlert: 'This email is already registered. Please use a different email.',
40    };
41
42    authenticationPrivateMethods.controls = {
43        addressModal: '#address-modal',
44        mobile: '#txt-mobile',
45        otpsingle: '#txtLoginOTP',
46        otpFirst: '#txt-otp-first',
47        otpSecond: '#txt-otp-second',
48        otpThird: '#txt-otp-third',
49        otpFourth: '#txt-otp-fourth',
50        frmmobilelogin: '#frmmobilelogin',
51        loginClose: '#loginclose',
52        mobileControls: '.mobile-control',
53        otpControls: '.otp-control',
54        loginModal: '#login-modal',
55        mobileSignUp: '#txt-signup-mobile',
56        nameSignUp: '#txt-signup-name',
57        emailSignUp: '#txt-signup-email',
58        passwordSignup: '#txt-mobile-password',
59        flMobileSignUp: '#txt-mobile-acc-create',
60        showSignUp: '.link-show-signup',
61        frmSignup: '#frmsignup',
62        frmmobileotp: '#frmmobileotp',
63        loginModalTitle: '#h-loginHead',
64        signupControls: '.create_account',
65        labelMobileNumber: '#lblMobileNum',
66        verifyOtp: "#btn-verify-otp",
67        otpBoxes: ".otp-txt-boxes",
68        changeMobile: '#lbl-change-mobile',
69        invalidOtp: '#invalid-otp',
70        signupError: '#error-signup',
71        emailLoginSec: '.emaillogin_sec',
72        emailLoginBtn: '#emailLogin-btn',
73        mobileLogin: '#mobileLogin',
74        instagramLogin: '#lbtninstalogin',
75        facebookLogin: '#lbtnFBlogin',
76        emaillogin: '#emaillogin',
77        emailloginInput: '.emaillogin-ip',
78        email: '#txt-email',
79        labelEmail: '#lbl-email',
80        emailPassword: '.enterpassword_email_container',
81        enterpassword_mobile_container: '.enterpassword_mobile_container',
82        changeEmailPwd: '#lbl-email-pwd',
83        labelPassword: '#lbl-password',
84        loginWithOtpLabel: ".loginWithOtpLabel",
85        editBtn: '.edit_btn',
86        changeEmail: '#lbl-change-email',
87        changePhonePwd: '#lbl-change-mobile-pwd',
88        frmmobileloginpsw: '#enterpassword_mobile',
89        enterpassword_control: ".enterpassword_control",
90        verifyValidation: '.verify_validation',
91        changeTarget: '.change_target',
92        intlTeleInput: '.intl_tele_input'
93
94    };
95
96    authenticationPrivateMethods.isValidMobile = function (newMobile) {
97        $(authenticationPrivateMethods.controls.loginModal).find(".Error").remove();
98
99        var mobile = newMobile ? newMobile : $(authenticationPrivateMethods.controls.mobile).val().replace(/\D/g, "");
100        let code = master.properties.countryCode;
101        var countryCodeList = authenticationPrivateMethods.properties.countryCodeList;
102        var countryCode = countryCodeList[code] || code;
103        try {
104            const phoneNumber = libphonenumber.parsePhoneNumberFromString(mobile, countryCode);
105            if (phoneNumber && phoneNumber.isValid()) {
106                return true;
107            }
108        } catch (error) {
109            return false;
110            //console.error("Phone number parsing error:", error);
111        }
112
113        // Show error if validation fails
114       // $(authenticationPrivateMethods.controls.mobile).parent().append("<div class='Error'>Please enter a valid mobile number.</div>");
115        $('.invalid-feedback.invalid-phoone').show();
116        //$('#frmmobilelogin').addClass('was-validated') 
117
118        return false;
119    };
120    authenticationPrivateMethods.isValidEmail = function (emailProp) {
121        var isValid = true;
122        $(authenticationPrivateMethods.controls.loginModal).find(".Error").remove();
123        var email = emailProp ? emailProp : $(authenticationPrivateMethods.controls.email).val(); // Fetch the value of the email input field
124        var pattern = /^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$/;
125
126        if (pattern.test(email)) { // Use test method on the regex pattern
127            return true;
128        } else {
129            $(authenticationPrivateMethods.controls.email).parent().append("<div class='Error'>Please enter a valid Email.</div>");
130            return false;
131        }
132        return isValid;
133    };
134
135    authenticationPrivateMethods.isValidOTP = function (otpProp) {
136        var controls = authenticationPrivateMethods.controls;
137        var isValid = true;
138        $(controls.loginModal).find(".Error").remove();
139        var otp = otpProp ? otpProp : $(controls.otpsingle).val();//$(controls.otpFirst).val() + $(controls.otpSecond).val() + $(controls.otpThird).val() + $(controls.otpFourth).val();
140        var pattern = /^\d{4}$/;
141
142        if (pattern.test(otp)) {
143            return true;
144        }
145        else {
146            //$(controls.otpFirst).parent().append("<div class='Error'>Please enter valid OTP.</div>");
147            // $(controls.otpsingle).parent().append("<div class='invalid-feedback invalid-otp' style='display:block;' >Please enter valid OTP.</div>");
148            $('.invalid-feedback.invalid-otp').show();
149            $('.invalid-feedback.invalid-otp').html("<div class='invalid-feedback invalid-otp' style='display:block;'>Please enter valid OTP.</div>");
150            return false;
151        }
152        return isValid;
153    };
154
155
156
157    authenticationPrivateMethods.getOtp = function (self, token) {
158        var url = authenticationMethods.url.getOtp; // + "?token=" + token;
159        if ($(self).find('button.btn.mobilevalidationbtn').hasClass('processing'))
160            return false;
161
162        if (!authenticationPrivateMethods.isValidMobile()) {
163            // $(self).removeClass('processing');
164            $(self).find('button.btn.mobilevalidationbtn').removeClass('processing');
165            $(self).find('button.btn.mobilevalidationbtn').attr('disabled', false);
166
167            return false;
168        }
169        $(self).find('button.btn.mobilevalidationbtn').addClass('processing');
170        $(self).find('button.btn.mobilevalidationbtn').attr('disabled', true);
171
172        authenticationPrivateMethods.resetValidations();
173
174
175        //$('#frmmobilelogin').removeClass('was-validated') 
176        var mobile = $(authenticationPrivateMethods.controls.mobile).val().replace(/\D/g, "");
177        var selectedCountryCode = $('.iti__selected-dial-code').html();
178        fullPhone = selectedCountryCode + mobile;
179        var usepsw = ($(self).attr('usepsw') == '1' ? 1 : 0);
180        onSuccess = function (data) {
181            if (data && data.status === 'ok') {
182                //$(self).removeClass('processing');
183                $(self).find('button.btn.mobilevalidationbtn').removeClass('processing');
184                $(self).find('button.btn.mobilevalidationbtn').attr('disabled', false);
185
186                if (data.msg == "verified successfully for password") {//pwd
187                    toggleElements(authenticationPrivateMethods.controls.mobileControls, true);
188                    toggleElements(authenticationPrivateMethods.controls.enterpassword_control, false);
189                    var html = "Please enter the password for " + $('#txt-mobile').val() + '<a class="edit_btn" ><small id="lbl-change-mobile>change</small></a>';
190                    $(authenticationPrivateMethods.controls.labelPassword).html(html);
191                    $(authenticationPrivateMethods.controls.loginModalTitle).html("Password");
192                    toggleElements('.otpText', true);
193                    $('#pswmobile').val(fullPhone);
194                    $('#psw-email').val('');
195                    $('#psw-mobile').val(fullPhone);
196                    $('#psw-type').val('1');
197
198                } else { //otp
199                    toggleElements('#lbl-change-mobile', false);
200                    toggleElements(authenticationPrivateMethods.controls.mobileControls, true);
201                    toggleElements(authenticationPrivateMethods.controls.otpControls, false);
202                    authenticationPrivateMethods.properties.isOtpTriggered = true;
203                    var htmlFailure = "Please enter the verification code received in " + $(authenticationPrivateMethods.controls.mobile).val();
204                    $(authenticationPrivateMethods.controls.labelMobileNumber).html(htmlFailure);
205                    $(authenticationPrivateMethods.controls.loginModalTitle).html("Verification Code");
206                    //$(authenticationPrivateMethods.controls.otpFirst).focus();
207                    $("#dynamic-otp0").focus();
208                    authenticationPrivateMethods.setResendTimer();
209                }
210
211            } else {
212                $(authenticationPrivateMethods.controls.loginModal).modal('hide');
213                master.showResult('There is a technical error. Please contact administrator for more details', 'Failure', false);
214            }
215        };
216
217        onError = function (data) {
218            //console.log(data);
219            master.showResult('There is a technical error. Please contact administrator for more details', 'Failure', false);
220            $(self).removeClass('processing');
221        };
222        master.ajax.JSONRequest(url, 'POST', { Mobile: fullPhone, usePsw: usepsw, token: token }, onSuccess, onError);
223
224    };
225
226    //Send OTP via Email
227    authenticationPrivateMethods.getEmailOtp = function (self, token, bypassPwd) {
228        try {
229            var url = authenticationMethods.url.getEmailOtp;// + "?token=" + token;
230            $(self).addClass('processing');
231            if (!authenticationPrivateMethods.isValidEmail(false)) {
232                $(self).removeClass('processing');
233                $('.emailloginform').addClass('was-validated');
234                $('.invalid-feedback.error-email').show();
235
236                return false;
237            }
238
239            authenticationPrivateMethods.resetValidations();
240
241            var email = $(authenticationPrivateMethods.controls.email).val();
242            onSuccess = function (data) {
243                //console.log(data);
244                if (data && data.status === 'ok') {
245                    $(self).removeClass('processing');
246                    data.msg = bypassPwd ? "cx" : data.msg;
247                    if (data.msg == "verified successfully for password") {//pwd
248
249
250                        toggleElements(authenticationPrivateMethods.controls.emailLoginSec, true);
251                        toggleElements(authenticationPrivateMethods.controls.enterpassword_control, false);
252                        var html = "Please enter the password for " + $(authenticationPrivateMethods.controls.email).val() + '<a  href="javascript:void(0)" class="edit_btn" id="lbl-change-email"><small class="ms-1">change</small></a>';
253                        $(authenticationPrivateMethods.controls.labelPassword).html(html);
254                        $(authenticationPrivateMethods.controls.loginModalTitle).html("Password");
255                        toggleElements('.otpText', true);
256                        var email = $(authenticationPrivateMethods.controls.email).val();
257                        $('#psw-email').val(email);
258                        $('#psw-mobile').val('');
259                        $('#psw-type').val('2');
260
261                        //$(authenticationPrivateMethods.controls.otpsingle).focus();
262                        //authenticationPrivateMethods.setResendTimer('-email');
263                    } else {//otp
264                        toggleElements(authenticationPrivateMethods.controls.emailloginInput, true);
265                        toggleElements(authenticationPrivateMethods.controls.emailPassword, true);
266                        toggleElements(authenticationPrivateMethods.controls.enterpassword_control, true);
267                        toggleElements('#lbl-change-mobile', true);
268                        toggleElements('.emaillogin_sec', true);
269                        toggleElements('.otp-control', false);
270                        authenticationPrivateMethods.properties.isOtpTriggered = true;
271                        var htmlFailedVerification = 'enter the verification code received in <span>' + $(authenticationPrivateMethods.controls.email).val() + '<a id="lbl-change-mobile" class="change-mobile" href="">Change</a></span>';
272                        $('#lblMobileNum').html(htmlFailedVerification);
273                        $(authenticationPrivateMethods.controls.loginModalTitle).html("Verification Code");
274                        //$(authenticationPrivateMethods.controls.otpFirst).focus();
275                        $("#dynamic-otp0").focus();
276                        authenticationPrivateMethods.setResendTimer('-email');
277
278                    }
279
280
281                } else {
282                    $(authenticationPrivateMethods.controls.loginModal).modal('hide');
283                    master.showResult('There is a technical error. Please contact administrator for more details', 'Failure', false);
284                }
285            };
286
287            onError = function (data) {
288                //console.log(data);
289                master.showResult('There is a technical error. Please contact administrator for more details', 'Failure', false);
290            };
291            //console.log(url, 'POST', { Email: email })
292            master.ajax.JSONRequest(url, 'POST', { Email: email, usePsw: (bypassPwd ? 0 : 1), token: token }, onSuccess, onError);
293        }
294        catch (e) {
295            //console.log(e);
296        }
297
298    };
299    //Send an OTP for email verification after signup (when the logged in user have a non verified email after signup)
300
301    authenticationPrivateMethods.getEmailOtpForVerificationAfterSignup = function (self, token, email, emailFromApi) {
302        try {
303            var url = authenticationMethods.url.getEmailOtp; // + "?token=" + token;
304            authenticationMethods.properties.newEmail = email;
305            $('.newEmail').text('Enter OTP recieved in ' + email);
306
307            $(self).addClass('processing');
308            if (!authenticationPrivateMethods.isValidEmail(email)) {
309                $(self).removeClass('processing');
310                return false;
311            }
312
313
314            onSuccess = function (data) {
315                //console.log(data);
316                $(authenticationPrivateMethods.controls.verifyValidation).removeClass('processing');
317
318                if (data && data.status === 'ok') {
319                    if (emailFromApi) {
320                        $('.openpopover').addClass('active');
321                        $('.emailverification ').removeClass('hide');
322                        $('#emailVerifyOtp').focus();
323                    } else {
324                        $(self).removeClass('processing');
325
326                        $('.openpopover').removeClass('active');
327                        $('.emailverification ').removeClass('hide');
328                    }
329
330
331                } else {
332                    $(authenticationPrivateMethods.controls.loginModal).modal('hide');
333                    master.showResult('There is a technical error. Please contact administrator for more details', 'Failure', false);
334                }
335            };
336
337            onError = function (data) {
338                $(controls.verifyValidation).removeClass('processing');
339                //console.log(data);
340                master.showResult('There is a technical error. Please contact administrator for more details', 'Failure', false);
341            };
342            //console.log(url, 'POST', { Email: email })
343            master.ajax.JSONRequest(url, 'POST', { Email: email, usePsw: 0, token: token }, onSuccess, onError);
344        }
345        catch (e) {
346            //console.log(e);
347        }
348
349    };
350    //Send an OTP for mobile number verification after signup (when the logged in user have a non verified mobile number after signup)
351
352    authenticationPrivateMethods.getMobileOtpForVerificationAfterSignup = function (self, token, mobile, mobileFromApi) {
353        try {
354            var url = authenticationMethods.url.getOtp;// + "?token=" + token;
355            authenticationMethods.properties.newMobile = mobile;
356            $('.newEmail').text('Enter OTP recieved in ' + mobile);
357            $(self).addClass('processing');
358            if (!authenticationPrivateMethods.isValidMobile(mobile)) {
359                $(self).removeClass('processing');
360                return false;
361            }
362            onSuccess = function (data) {
363                $(authenticationPrivateMethods.controls.verifyValidation).removeClass('processing');
364                //console.log(data);
365                if (data && data.status === 'ok') {
366                    if (mobileFromApi) {
367                        $('.openpopover').addClass('active');
368                        $('.newmobileverification').removeClass('hide');
369                        $('#otpHiddenInput').focus();
370                    }
371                } else {
372                    $(authenticationPrivateMethods.controls.loginModal).modal('hide');
373                    master.showResult('There is a technical error. Please contact administrator for more details', 'Failure', false);
374                }
375            };
376
377            onError = function (data) {
378                $(authenticationMethods.controls.verifyValidation).removeClass('processing');
379                //console.log(data);
380                master.showResult('There is a technical error. Please contact administrator for more details', 'Failure', false);
381            };
382
383            master.ajax.JSONRequest(url, 'POST', { Mobile: mobile, usePsw: 0, token: token }, onSuccess, onError);
384        }
385        catch (e) {
386            //console.log(e);
387        }
388
389    };
390
391    //Verify the OTP after signup (when the logged in user have a non verified email after signup)
392    authenticationPrivateMethods.emailOtpVerificationAfterSignup = function (self, token, newEmail) {
393        var controls = authenticationPrivateMethods.controls;
394        var otp = $('#otpHiddenInput').val();
395        $(self).addClass('processing');
396        if (!authenticationPrivateMethods.isValidOTP(otp)) {
397            $(self).removeClass('processing');
398            return false;
399        }
400
401        var details = {};
402        details.mobile = "";
403        details.email = authenticationMethods.properties.newEmail;
404        details.otp = otp; //$(controls.otpFirst).val() + $(controls.otpSecond).val() + $(controls.otpThird).val() + $(controls.otpFourth).val();
405        $(controls.mobileSignUp).val(details.mobile);
406        onSuccess = function (result) {
407            //console.log(result)
408            if (result && result.status == 'ok') {
409                $('.verify_dropdown_popover').addClass('hide');
410
411                $.ajax({
412                    url: authenticationPrivateMethods.properties.updateStatusHandler,
413                    type: 'POST',
414                    data: { verified: 'email', },
415                    success: function (response) {
416                        // Handle success response if needed
417                        location.reload(true); // Reload the page after updating the user
418                    },
419                });
420            }
421            else {
422                master.showResult(result && result.error && result.error.msg ? result.error.msg : "Couldn't Verify", 'Failure', false);
423                $('#emailVerifyOtp').val('');
424                $('#otpContainer .otp-input').val('');
425                $('.verify_dropdown_popover').removeClass('active');
426                $(self).removeClass('processing');
427            }
428
429
430        };
431        onError = function (data, polo, marco) {
432            //console.log(data);
433            master.showResult('There is a technical error. Please contact administrator for more details', 'Failure', false);
434        };
435        master.ajax.JSONRequest(authenticationMethods.url.verifyOtp, 'POST', details, onSuccess, onError);
436    };
437
438    authenticationPrivateMethods.mobileOtpVerificationAfterSignup = function (self, token, newMobile) {
439        var controls = authenticationPrivateMethods.controls;
440        $(self).addClass('processing');
441        if (!authenticationPrivateMethods.isValidOTP(false)) {
442            $(self).removeClass('processing');
443            return false;
444        }
445
446        var details = {};
447        details.mobile = $('#mobile_to_verify').val().replace('+91 ', '');
448        details.email = "";
449        details.otp = $('#txtLoginOTP').val(); //$(controls.otpFirst).val() + $(controls.otpSecond).val() + $(controls.otpThird).val() + $(controls.otpFourth).val();
450        // $(controls.mobileSignUp).val(details.mobile);
451
452        onSuccess = function (result) {
453
454            if (result && result.data && result.data.is_registered) {
455
456                $.ajax({
457                    url: authenticationPrivateMethods.properties.updateStatusHandler,
458                    type: 'POST',
459                    data: { verified: 'mobile' },
460                    success: function (response) {
461                        location.reload(true); // Reload the page after updating the user
462                    },
463
464                });
465
466
467            }
468            else {
469                $(self).removeClass('processing');
470
471            }
472        };
473        onError = function (data, polo, marco) {
474            //console.log(data);
475            master.showResult('There is a technical error. Please contact administrator for more details', 'Failure', false);
476        };
477        master.ajax.JSONRequest(authenticationMethods.url.verifyOtp, 'POST', details, onSuccess, onError);
478    };
479    authenticationPrivateMethods.oneClickVerify = function (param, prop, emailFromApi) {
480        var self = $(this);
481        if (param == 'email') {
482            if (authenticationMethods.properties.isCaptchaEnabled) {
483                grecaptcha.ready(function () {
484                    grecaptcha.execute(authenticationMethods.properties.captchaKey, { action: 'submit' }).then(function (token) {
485                        authenticationPrivateMethods.getEmailOtpForVerificationAfterSignup(self, token, prop, emailFromApi);
486                    });
487                });
488            } else {
489                //console.log('Skipping recaptcha execution');
490                authenticationPrivateMethods.getEmailOtpForVerificationAfterSignup(self, 'dummyToken', prop, emailFromApi);
491            }
492        } else {
493            if (authenticationMethods.properties.isCaptchaEnabled) {
494                grecaptcha.ready(function () {
495                    grecaptcha.execute(authenticationMethods.properties.captchaKey, { action: 'submit' }).then(function (token) {
496                        authenticationPrivateMethods.getMobileOtpForVerificationAfterSignup(self, token, prop, emailFromApi);
497                    });
498                });
499            } else {
500                //console.log('Skipping recaptcha execution');
501                authenticationPrivateMethods.getMobileOtpForVerificationAfterSignup(self, 'dummyToken', prop, emailFromApi);
502
503            }
504        }
505
506    };
507    authenticationPrivateMethods.setResendTimer = function (from) {
508        if (from == null)
509            from = '';
510        $("#countdown" + from).show();
511        if (authenticationPrivateMethods.properties.tmrCountdownId)
512            clearInterval(authenticationPrivateMethods.properties.tmrCountdownId);
513        var btn = $('#resend' + from);
514        $(btn).html("");
515        var timeout = 60;
516
517        authenticationPrivateMethods.properties.tmrCountdownId = setInterval(showCountDown, 1000);
518        function showCountDown() {
519            if (timeout == 0) {
520                $("#countdown" + from).hide();
521                clearInterval(authenticationPrivateMethods.properties.tmrCountdownId);
522                $(btn).html("Didn't receive the code? <span class='resent' id='resend-trigger'>Resend</span>");
523
524                $("#resend-trigger").off("click").on("click", function () {
525                    //authenticationPrivateMethods.getOtp($(authenticationPrivateMethods.controls.frmmobileotp));
526                    var self = $(authenticationPrivateMethods.controls.frmmobileotp); //$(this);
527                    $("#countdown" + from).html('');
528                    if (authenticationMethods.properties.isCaptchaEnabled) {
529                        grecaptcha.ready(function () {
530                            grecaptcha.execute(authenticationMethods.properties.captchaKey, { action: 'submit' }).then(function (token) {
531                                authenticationPrivateMethods.getOtp(self, token);
532                            });
533                        });
534                    }
535                    else {
536
537                        //console.log('Skipping recaptcha execution');
538                        authenticationPrivateMethods.getOtp(self, 'dummyToken');
539                    }
540
541                });
542            } else {
543                timeout--;
544                $("#countdown" + from).html('Resend in ' + timeout + ' seconds');
545                $('#resend').prop('disabled', true);
546            }
547
548        }
549
550    };
551
552    authenticationPrivateMethods.verifyOtp = function (self) {
553        var controls = authenticationPrivateMethods.controls;
554        var signUpFromElem = $(controls.frmSignup);
555        // $(self).addClass('processing');
556        $(self).find('button.btn.validate').addClass('processing');
557        $(self).find('button.btn.validate').attr('disabled', true);
558        if (!authenticationPrivateMethods.isValidOTP(false)) {
559            //$(self).removeClass('processing')
560            $(self).find('button.btn.validate').removeClass('processing');
561            $(self).find('button.btn.validate').attr('disabled', false);
562            return false;
563        }
564
565        var details = {};
566        var mobile = $(controls.mobile).val() ? $(controls.mobile).val().replace(/\s+/g, '') : "";
567        var selectedCountryCode = $('.iti__selected-dial-code').html();
568
569        fullPhone = mobile != "" ? selectedCountryCode + mobile : "";
570        details.mobile = fullPhone;
571        details.email = $(controls.email).val();
572        details.otp = $(controls.otpsingle).val(); //$(controls.otpFirst).val() + $(controls.otpSecond).val() + $(controls.otpThird).val() + $(controls.otpFourth).val();
573        authenticationMethods.url.redirectUrl = window.location.pathname;
574
575        $(controls.mobileSignUp).val(details.mobile);
576
577        if (details.email) {
578            $('#phone-acc-create').removeClass('hide');
579            $('#txt-mobile-acc-create').prop('required', true);
580            $('#newacount_emailid_field').addClass('hide');
581            $(authenticationPrivateMethods.controls.emailSignUp).removeAttr('required');
582        }
583        else {
584            $('#newacount_emailid_field').removeClass('hide');
585            $(authenticationPrivateMethods.controls.emailSignUp).prop('required', true);
586            $('#phone-acc-create').addClass('hide');
587            $('#txt-mobile-acc-create').removeAttr('required');
588        }
589
590        onSuccess = function (result) {
591
592
593            $(signUpFromElem).find('button').parent('div').removeClass('processing');
594
595            if (result && result.data && result.data.is_registered) {
596                $(controls.invalidOtp).addClass('hide');
597                if (authenticationMethods.url.redirectUrl != '')
598                    window.location.href = authenticationMethods.url.redirectUrl;
599                else if (window.location.pathname == '/')
600                    window.location.reload(true);
601                else
602                    window.location.replace("/");
603            }
604            else if (result && result.data && result.data.is_registered == false) {
605                $(controls.invalidOtp).addClass('hide');
606                // $(self).removeClass('processing');
607                $(self).find('.button.btn.validate').removeClass('processing');
608                $(self).find('button.btn.validate').attr('disabled', false);
609                $(controls.loginModalTitle).html("Create Account");
610                $(function () {
611                    $(authenticationPrivateMethods.controls.nameSignUp).focus();
612                });
613                toggleElements(controls.mobileControls, true);
614                toggleElements(controls.otpControls, true);
615                $(controls.signupControls).removeClass("hide");
616                $('.sociallogin').addClass("hide");
617
618                //$(authenticationPrivateMethods.controls.passwordSignup).removeAttr('required');
619
620            }
621            else {
622                //$(self).removeClass('processing');
623                //$('#login-modal').modal('hide');
624                // master.showResult(result.error.msg ? result.error.msg : 'There is a technical error. Please contact administrator for more details', 'Failure', false);
625
626                $('.invalid-feedback.invalid-otp').show();
627                $('.otp-input').css('border-color', 'red');
628
629                if (result && result.error && result.error.msg) {
630                    $('.invalid-feedback.invalid-otp').html(result.error.msg);
631                }
632                $(self).find('button.btn.validate').parent('div').removeClass('processing');
633
634                $(self).find('button.btn.validate').removeClass('processing');
635                $(self).find('button.btn.validate').attr('disabled', false);
636                $(controls.otp).val('');
637                $(controls.invalidOtp).removeClass('hide');
638            }
639        };
640        onError = function (data, polo, marco) {
641            //console.log(data);
642            master.showResult('There is a technical error. Please contact administrator for more details', 'Failure', false);
643        };
644        master.ajax.JSONRequest(authenticationMethods.url.verifyOtp, 'POST', details, onSuccess, onError);
645    };
646    authenticationPrivateMethods.initiateSignup = function (self) {
647        var details = {
648            mobile: authenticationMethods.properties.signupPhone,
649            email: authenticationMethods.properties.signupEmail,
650            name: authenticationMethods.properties.signupName,
651            password: authenticationMethods.properties.password
652        };
653        onSuccess = function (data) {
654            if (data.status == 'error') {
655                $(self).find('button').parent('div').removeClass('processing');
656                var signpUsingPhone = $('#phone-acc-create').hasClass('hide');
657
658                var errorMessage = 'There is a technical error.Please contact administrator for more details';
659                if (data.message[0] == 'Already Registered') {
660                    errorMessage = signpUsingPhone ? authentication.messages.emailExistsAlert : authenticationMethods.messages.phoneExistsAlert;
661                    $('#error-signup').html(errorMessage);
662                }
663                $('#resultsModal .modal-content').css('border', '1px solid #ffd6d6');
664
665                master.showResult("Could'nt signup! " + errorMessage, 'Failure', false);
666                setTimeout(function () {
667                    $('#resultsModal').modal('hide');
668                    $('#resultsModal .modal-content').css('border', '1px solid #ffffff');
669
670                }, 5000);
671            } else {
672                if (window.location.pathname != '/')
673                    window.location.href = '/';
674                else
675                    window.location.reload(true);
676            }
677
678        };
679
680        onError = function (data) {
681            $(self).find('button').parent('div').removeClass('processing');
682            //console.log(data);
683        };
684        master.ajax.JSONRequest(
685            //authenticationMethods.url.signUp,
686            'Authentication/SignUp',
687            'POST', details, onSuccess, onError);
688    };
689    authenticationPrivateMethods.signUp = function (self) {
690        authenticationMethods.properties.signupEmail = $(authenticationPrivateMethods.controls.emailSignUp).val() ? $(authenticationPrivateMethods.controls.emailSignUp).val() : $(authenticationPrivateMethods.controls.email).val();
691        authenticationMethods.properties.signupName = $(authenticationPrivateMethods.controls.nameSignUp).val();
692        var mobilenum = $('#txt-mobile').val() != "" ? $('#txt-mobile').closest('.iti').find('.iti__selected-dial-code').html() + $('#txt-mobile').val() : $(authenticationPrivateMethods.controls.flMobileSignUp).closest('.iti').find('.iti__selected-dial-code').html() + $(authenticationPrivateMethods.controls.flMobileSignUp).val();
693
694        authenticationMethods.properties.signupPhone = mobilenum.replace(" ", "").trim();
695        authenticationMethods.properties.password = $(authenticationPrivateMethods.controls.passwordSignup).val();
696
697        //console.log(address.properties.signupEmail, address.properties.signupName, address.properties.signupPhone);
698        if (authenticationMethods.properties.signupEmail.trimEnd() != '' && authenticationMethods.properties.signupName.trimEnd() != '') {
699            //address.triggerAddAddress(true);
700            authenticationPrivateMethods.initiateSignup(self);
701            //$(authenticationPrivateMethods.controls.loginModal).modal('hide');
702        } else {
703            $(authenticationPrivateMethods.controls.signupError).removeClass("hide");
704        }
705
706    };
707
708    authenticationPrivateMethods.focusOnOtpBox = function (self) {
709        var position = self.data("next");
710        if (position == "submit") {
711            $(authenticationPrivateMethods.controls.verifyOtp).focus();
712        } else {
713            $("#txt-otp-" + position).focus();
714        }
715    };
716
717    authenticationPrivateMethods.verifyPsw = function (self, token) {
718        var url = authenticationPrivateMethods.properties.verifyPsw;// + "?token=" + token;
719        //var data = $(self).serializeArray().reduce(function (json, { name, value }) {
720        //        json[name] = value;
721        //        return json;
722        //    }, {});
723        //var data = $(self).serialize();
724        $(self).find(".Error").remove();
725        authenticationMethods.url.redirectUrl = window.location.pathname;
726
727        var data = $(self).serializeArray().map(function (x) { this[x.name] = x.value; return this; }.bind({}))[0];
728        data.token = token;
729
730        $(self).addClass('processing');
731        onSuccess = function (data) {
732            $(self).removeClass('processing');
733
734            if (data && data.status === 'ok') {
735                if (authenticationMethods.url.redirectUrl != '')
736                    window.location.href = authenticationMethods.url.redirectUrl;
737                else
738                    window.location.reload(true);
739            }
740            else if (data && data.status == 'error' && data.error && data.error.msg && data.error.msg != '') {
741                $(self).find('div.Error').text(data.error.msg);
742                $(self).find('.errclasstobeadded').append("<div class='invalid-feedback invali
742d-otp' style='display:block;'>" + data.error.msg + "</div>");
743            }
744            else {
745                $(authenticationPrivateMethods.controls.loginModal).modal('hide');
746                master.showResult('There is a technical error. Please contact administrator for more details', 'Failure', false);
747
748            }
749        };
750
751        onError = function (data) {
752            master.showResult('There is a technical error. Please contact administrator for more details', 'Failure', false);
753            $(self).removeClass('processing');
754        };
755        master.ajax.JSONRequest('/' + url, 'POST', data, onSuccess, onError);
756
757    };
758
759
760    authenticationPrivateMethods.bringBackMobileModal = function () {
761        $(authenticationPrivateMethods.controls.otpControls).addClass("hide");
762        $(authenticationPrivateMethods.controls.mobileControls).removeClass("hide");
763        $(authenticationPrivateMethods.controls.enterpassword_mobile_container).addClass("hide");
764        authenticationPrivateMethods.properties.isOtpTriggered = false;
765    };
766    authenticationPrivateMethods.bringBackEmailModal = function () {
767
768        toggleElements('.otp-control', true);
769        toggleElements(authenticationPrivateMethods.controls.enterpassword_control, true);
770        toggleElements(authenticationPrivateMethods.controls.emailPassword, true);
771        $(authenticationPrivateMethods.controls.changeEmailPwd).html("");
772        $(authenticationPrivateMethods.controls.loginModalTitle).html("Email");
773        toggleElements(authenticationPrivateMethods.controls.emailloginInput, false);
774    };
775    authenticationPrivateMethods.getCodeForInput = function () {
776        //The country code used in the configuration files may not be compatible with the intlTelInput,
777        //So wee need a function to map the country codes from the configuration files/apis to the country code format that intlTelInput supports.
778
779        let code = master.properties.countryCode;
780
781        //List of country codes that has to be mapped.
782        //countryCodeList = {country code from master : country code supported by intlTelInput}
783
784        const countryCodeList = {
785            "GB": "UK",
786            "UAE": "AE",
787            "UK": "gb"
788        };
789        // return the country code from countryCodeList, else return the country code from master 
790        return countryCodeList[code] || code;
791    };
792authenticationPrivateMethods.initializeMobileInput = function () {
793
794    let countryCodeForInput = authenticationPrivateMethods.getCodeForInput();
795
796    const inputs = document.querySelectorAll(".intl_tele_input");
797    inputs.forEach(input => {
798        window.intlTelInput(input, {
799            initialCountry: countryCodeForInput,
800            preferredCountries: [countryCodeForInput],
801            strictMode: true,
802            allowDropdown: countryCodeForInput == "IN" ? false : true,
803            separateDialCode: true,
804            formatOnDisplay: false, // Disables automatic formatting
805
806        });
807    });
808
809
810
811    //$(authenticationPrivateMethods.controls.intlTeleInput).intlTelInput({
812    //    autoHideDialCode: true,
813    //    autoPlaceholder: "ON",
814    //    dropdownContainer: document.body,
815    //    formatOnDisplay: true,
816    //    hiddenInput: "full_number",
817    //    initialCountry: countryCodeForInput,
818    //    nationalMode: true,
819    //    placeholderNumberType: "MOBILE",
820    //    preferredCountries: [countryCodeForInput],
821    //    separateDialCode: true,
822    //    showSelectedDialCode: true,
823    //    showFlags: true,
824    //    allowDropdown: countryCodeForInput == "IN" ? false : true,
825
826    //});
827};
828    authenticationPrivateMethods.getAuthCodeIfLoggedIn = function () {
829        // Get the URL parameters
830        const queryString = window.location.search;
831        const urlParams = new URLSearchParams(queryString);
832
833        // Get the value of the 'code' parameter
834        const authCode = urlParams.get('code');
835        if (authCode) {
836            // Use the 'authCode' variable to send to server and validate
837            //console.log('Auth Code:', authCode);
838            onSuccess = function (result) {
839
840                if (result && result.data && result.data.is_registered) {
841                    if (authenticationMethods.url.redirectUrl != '')
842                        window.location.href = authenticationMethods.url.redirectUrl;
843                    else if (window.location.pathname == '/')
844                        window.location.reload(true);
845                    else
846                        window.location.replace("/");
847                }
848
849                else if (result && result.data && result.data.is_registered == false) {
850                    $(self).removeClass('processing');
851                    $(controls.loginModalTitle).html("Create Account");
852                    toggleElements(controls.mobileControls, true);
853                    toggleElements(controls.otpControls, false);
854                    $(controls.signupControls).removeClass("hide");
855
856                }
857                else {
858                    $(self).removeClass('processing');
859                    $(controls.otp).val('');
860                    $(controls.invalidOtp).removeClass('hide');
861                }
862            };
863            onError = function (data, polo, marco) {
864                //console.log(data);
865                master.showResult('There is a technical error. Please contact administrator for more details', 'Failure', false);
866            };
867
868            //pass in the code to validate it from the server
869            //master.ajax.JSONRequest(authenticationMethods.url.verifyCode, 'POST', details, onSuccess, onError);
870
871
872        }
873
874    };
875    authenticationMethods.initializePage = function () {
876        authenticationMethods.events.initialize();
877        authenticationPrivateMethods.initializeMobileInput();
878        authenticationPrivateMethods.getAuthCodeIfLoggedIn();
879        registerFedLoginMessageListener();
880
881    };
882
883    authenticationMethods.events.initialize = function () {
884        var controls = authenticationPrivateMethods.controls;
885
886        $(controls.frmmobilelogin).off('submit').on('submit', function (event) {
887            event.preventDefault();
888            var self = $(this);
889            $("#countdown").html('');
890            if (authenticationMethods.properties.isCaptchaEnabled) {
891                grecaptcha.ready(function () {
892                    grecaptcha.execute(authenticationMethods.properties.captchaKey, { action: 'submit' }).then(function (token) {
893                        authenticationPrivateMethods.getOtp(self, token);
894                    });
895                });
896            }
897            else {
898
899                //console.log('Skipping recaptcha execution');
900                authenticationPrivateMethods.getOtp(self, 'dummyToken');
901            }
902
903        });
904
905        $(controls.frmmobileloginpsw).off('submit').on('submit', function (event) {
906            event.preventDefault();
907            var self = $(this);
908            grecaptcha.ready(function () {
909                grecaptcha.execute(authenticationMethods.properties.captchaKey, { action: 'submit' }).then(function (token) {
910                    authenticationPrivateMethods.verifyPsw(self, token);
911                });
912            });
913        });
914
915        $(controls.emaillogin).off('submit').on('submit', function (event) {
916            event.preventDefault();
917            var self = $(this);
918            $("#countdown").html('');
919            grecaptcha.ready(function () {
920                grecaptcha.execute(authenticationMethods.properties.captchaKey, { action: 'submit' }).then(function (token) {
921                    authenticationPrivateMethods.getEmailOtp(self, token, false);
922                });
923            });
924        });
925        $(controls.frmmobileotp).off('submit').on('submit', function (event) {
926            event.preventDefault();
927            authenticationPrivateMethods.verifyOtp($(this));
928        });
929
930        $(controls.frmSignup).off('submit').on('submit', function (event) {
931            var self = $(controls.frmSignup);
932            if ($(self).find('button').parent('div').hasClass('processing'))
933                return false;
934            $(self).find('button').parent('div').addClass('processing');
935            $('#error-signup').html('');
936            event.preventDefault();
937
938            authenticationPrivateMethods.signUp(self);
939        });
940
941        if (master.properties.countryCode == "IN") {
942            $(controls.mobile).inputmask({
943                placeholder: '',
944                clearMaskOnLostFocus: false,
945                colorMask: true,
946                mask: [{ "mask": "##########" }],
947                greedy: false,
948                definitions: { '#': { validator: "[0-9]", cardinality: 1 } }
949            });
950        }
951       
952
953        $(controls.otp).inputmask({
954            placeholder: '',
955            clearMaskOnLostFocus: false,
956            colorMask: true,
957            mask: [{ "mask": "####" }],
958            greedy: false,
959            definitions: { '#': { validator: "[0-9]", cardinality: 1 } }
960        });
961
962        //$(controls.emailSignUp).inputmask({
963        //    mask: "*{1,20}[.*{1,20}][.*{1,20}][.*{1,20}]@*{1,20}[.*{2,6}][.*{1,2}]",
964        //    greedy: false,
965        //    onBeforePaste: function (pastedValue, opts) {
966        //        pastedValue = pastedValue.toLowerCase();
967        //        return pastedValue.replace("mailto:", "");
968        //    },
969        //    definitions: {
970        //        '*': {
971        //            validator: "[0-9A-Za-z!#$%&'*+/=?^_`{|}~\-]",
972        //            casing: "lower"
973        //        }
974        //    }
975        //});
976
977        $(controls.otpBoxes).off("keyup").on("keyup", function () {
978            authenticationPrivateMethods.focusOnOtpBox($(this));
979        });
980
981        $('#lbl-change-mobile').off("click").on("click", function () {
982            authenticationPrivateMethods.bringBackMobileModal();
983        });
984
985        //Email click function
986        $(controls.emailLoginBtn).off("click").on("click", function () {
987            //Elements to be hidden
988            toggleElementsFromArray([
989                controls.mobileControls,
990                controls.emailLoginBtn,
991                controls.signupControls,
992                controls.emailPassword,
993                controls.otpControls
994            ], true);
995
996            //Elements to be shown
997
998            toggleElementsFromArray([
999                controls.mobileLogin,
1000                controls.emailLoginSec
1001            ], false);
1002            document.getElementById("txt-email").focus();
1003            clearInputValue(controls.email);
1004            $(authenticationPrivateMethods.controls.emailloginInput).removeClass('hide');
1005
1006        });
1007
1008        //Mobile click function
1009        $(controls.mobileLogin).off("click").on("click", function () {
1010            //Elements to be hidden
1011            toggleElementsFromArray([
1012                controls.mobileLogin,
1013                controls.emailLoginSec,
1014                controls.signupControls,
1015                controls.emailPassword,
1016                controls.otpControls,
1017                controls.enterpassword_control
1018            ], true);
1019            //Elements to be shown
1020            toggleElementsFromArray([
1021                controls.mobileControls,
1022                controls.emailLoginBtn
1023            ], false);
1024            document.getElementById("txt-mobile").focus();
1025            clearInputValue(controls.mobile);
1026
1027        });
1028
1029        authenticationPrivateMethods.resetValidations = function () {
1030            //Resetting validation
1031            $('.invalid-feedback.invalid-phoone').hide();
1032            $('.invalid-feedback.invalid-otp').hide();
1033            $('.otp-input').css('border-color', '#ccc');
1034        };
1035
1036        //Verify email or phone 
1037        $('#change_email_form').submit(function (event) {
1038            // Prevent the default form submission behavior
1039            event.preventDefault();
1040
1041            // Get the email address entered by the user
1042            var newEmail = $('#newemail').val();
1043            var self = $(this);
1044            if (authenticationMethods.properties.isCaptchaEnabled) {
1045                grecaptcha.ready(function () {
1046                    grecaptcha.execute(authenticationMethods.properties.captchaKey, { action: 'submit' }).then(function (token) {
1047                        authenticationPrivateMethods.getEmailOtpForVerificationAfterSignup(self, token, newEmail);
1048                    });
1049                });
1050            } else {
1051
1052                //console.log('Skipping recaptcha execution');
1053                authenticationPrivateMethods.getEmailOtpForVerificationAfterSignup(self, 'dummyToken', authenticationMethods.properties.newEmail);
1054
1055            }
1056
1057
1058        });
1059
1060        $('#verify_email_otp').submit(function (event) {
1061            // Prevent the default form submission behavior
1062            event.preventDefault();
1063            let otp = $('#otpHiddenInput').val();
1064            if (otp.length < 4) {
1065                $('.verificationStripError.email').removeClass('hide');
1066                $('.verificationStripError.email').html('Please enter a valid OTP');
1067                return false;
1068            }
1069
1070            // Get the email address entered by the user
1071            var newEmail = $('#email_to_verify').val();
1072            var self = $(this);
1073            if (authenticationMethods.properties.isCaptchaEnabled) {
1074                grecaptcha.ready(function () {
1075                    grecaptcha.execute(authenticationMethods.properties.captchaKey, { action: 'submit' }).then(function (token) {
1076                        authenticationPrivateMethods.emailOtpVerificationAfterSignup(self, token, newEmail);
1077                    });
1078                });
1079            } else {
1080
1081                //console.log('Skipping recaptcha execution');
1082                authenticationPrivateMethods.emailOtpVerificationAfterSignup(self, 'dummyToken', newEmail);
1083
1084            }
1085
1086
1087        });
1088
1089
1090        $('#verify_mobile_otp').submit(function (event) {
1091            // Prevent the default form submission behavior
1092            event.preventDefault();
1093
1094            // Get the email address entered by the user
1095            var newMobile = $('#mobile_to_verify').val();
1096            var self = $(this);
1097            let otp = $('#txtLoginOTP').val();
1098
1099            if (otp.length < 4) {
1100                $('.verificationStripError.mobile').removeClass('hide');
1101                $('.verificationStripError.mobile').html('Please enter a valid OTP');
1102                return false;
1103            }
1104            if (authenticationMethods.properties.isCaptchaEnabled) {
1105                grecaptcha.ready(function () {
1106                    grecaptcha.execute(authenticationMethods.properties.captchaKey, { action: 'submit' }).then(function (token) {
1107                        authenticationPrivateMethods.mobileOtpVerificationAfterSignup(self, token, newMobile);
1108                    });
1109                });
1110            } else {
1111
1112                //console.log('Skipping recaptcha execution');
1113                authenticationPrivateMethods.mobileOtpVerificationAfterSignup(self, 'dummyToken', newMobile);
1114
1115            }
1116
1117
1118        });
1119        //Instagram Login
1120        $(controls.instagramLogin).on("click", function () {
1121            openFedLoginPopup('https://api.instagram.com/oauth/authorize?client_id=' + authenticationMethods.properties.fedAuthFLKey + '&redirect_uri=' + authenticationMethods.url.fedRedirectUrl + '/fl/in&scope=user_profile,user_media&response_type=code&state=popup');
1122            //navigateTo(authenticationMethods.url.fedRedirectUrl.replace('[source]', 'instagram'))
1123        });
1124        //Facebook Login
1125        $('.facebookLogin').on("click", function () {
1126            openFedLoginPopup('https://graph.facebook.com/oauth/authorize?client_id=' + authenticationMethods.properties.fedAuthFLKey + '&redirect_uri=' + authenticationMethods.url.fedRedirectUrl + '/fl/fb&scope=email,public_profile&state=popup');
1127            //navigateTo(authenticationMethods.url.fedRedirectUrl.replace('[source]', 'facebook'))
1128        });
1129        //Google Login
1130        $('.google').on("click", function () {
1131            // state was previously the stray literal "https://mafarm.in" (leftover from a copied
1132            // template, unrelated to this site) - now doubles as the popup-flow flag instead.
1133            openFedLoginPopup('https://accounts.google.com/o/oauth2/auth?response_type=code&redirect_uri=' + authenticationMethods.url.fedRedirectUrl + '/fl/gm&scope=https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile&client_id=' + authenticationMethods.properties.fedGoogleAuthClientId + '&state=popup');
1134            //navigateTo(authenticationMethods.url.fedRedirectUrl.replace('[source]', 'google'))
1135        });
1136        $(controls.loginWithOtpLabel).on("click", function ($event) {
1137
1138            var self = $(this);
1139
1140            $("#countdown").html('');
1141            grecaptcha.ready(function () {
1142                grecaptcha.execute(authenticationMethods.properties.captchaKey, { action: 'submit' }).then(function (token) {
1143                    authenticationPrivateMethods.getEmailOtp(self, token, true);
1144                    toggleElements(controls.emailPassword, true);
1145                    toggleElements(controls.emailOtpControls, false);
1146                });
1147            });
1148        });
1149
1150        $(document).on("click", controls.changeEmail, function () {
1151            authenticationPrivateMethods.bringBackEmailModal();
1152        });
1153        $(document).on("click", controls.changeMobile, function () {
1154            authenticationPrivateMethods.bringBackMobileModal();
1155        });
1156        $(document).on("click", controls.changePhonePwd, function () {
1157
1158            authenticationPrivateMethods.bringBackMobileModal();
1159        });
1160
1161        $(document).on("click", controls.changeTarget, function () {
1162
1163            $('.verify_dropdown_popover').toggleClass('hide');
1164            //$(controls.postCodeLookup).addClass('hide')
1165            var target = $(this).data('target');
1166            switch (target) {
1167                case "email":
1168                    $('.newemailid').toggleClass('hide');
1169                    break;
1170                case 'mobile':
1171                    $('.newmobilenumber').toggleClass('hide');
1172                    break;
1173
1174            }
1175        });
1176
1177        $(document).on("click", controls.verifyValidation, function () {
1178            var target = $(this).data('target');
1179            //console.log(target);
1180            $(controls.verifyValidation).addClass('processing');
1181            switch (target) {
1182                case "email":
1183                    var email = $('#email_to_verify').val();
1184                    authenticationPrivateMethods.oneClickVerify('email', email, true);
1185                    break;
1186                case 'mobile':
1187                    var phone = $('#mobile_to_verify').val();
1188                    authenticationPrivateMethods.oneClickVerify('phone', phone, true);
1189                    //$('.newmobilenumber').toggleClass('hide')
1190                    break;
1191
1192            }
1193        });
1194
1195
1196
1197
1198
1199        //Provide the array of classes and IDs from the controls for toggling the 'hide' class in bulk
1200        function toggleElementsFromArray(array, isHide) {
1201            array.forEach(function (string) {
1202                toggleElements(string, isHide);
1203            });
1204        }
1205
1206        function clearInputValue(inputElement) {
1207            $(inputElement).val('');
1208        }
1209
1210    };
1211
1212    //Toggles the class hide on provided element
1213    function toggleElements(element, isHide) { // true => hide, false => show
1214        $(element).toggleClass("hide", isHide);
1215    }
1216    //Navigates to the provided url
1217    function navigateTo(url) {
1218        window.location.href = url;
1219    }
1220
1221    // Opens the federated-login OAuth URL in a popup instead of navigating the current tab away,
1222    // so whatever page the customer was on (cart, product, checkout...) stays live behind it.
1223    // window.open() here runs synchronously, directly inside the click handler that calls this -
1224    // i.e. as a direct response to a user gesture, which is what every modern browser's popup
1225    // blocker actually keys off (unsolicited/async popups get blocked; ones opened this way don't,
1226    // regardless of the "block popups" setting most users have on by default). The remaining
1227    // real-world cases that still block it - a user-level "always block" override, an aggressive
1228    // ad-blocker extension, or an in-app browser like Facebook's/Instagram's own webview, which is
1229    // a genuinely common way customers land on this site from social traffic - are caught by the
1230    // null/closed check below and fall back to the pre-existing full-page redirect, so a blocked
1231    // popup degrades to "works exactly like it did before this change" rather than a dead button.
1232    function openFedLoginPopup(url) {
1233        var w = 500, h = 640;
1234        var left = (window.screenX || window.screenLeft || 0) + Math.max(0, (window.outerWidth - w) / 2);
1235        var top = (window.screenY || window.screenTop || 0) + Math.max(0, (window.outerHeight - h) / 2);
1236        var features = 'width=' + w + ',height=' + h + ',left=' + left + ',top=' + top +
1237            ',resizable=yes,scrollbars=yes,status=no,toolbar=no,menubar=no,location=yes';
1238
1239        var popup = null;
1240        try {
1241            popup = window.open(url, 'bitszolFedLogin', features);
1242        } catch (e) {
1243            popup = null;
1244        }
1245
1246        if (!popup || typeof popup.closed === 'undefined' || popup.closed) {
1247            navigateTo(url);
1248            return;
1249        }
1250
1251        popup.focus();
1252    }
1253
1254    // Handles the outcome of the popup-based federated login, whether it arrives via postMessage
1255    // from the popup (FedLoginPopupResult.cshtml) or - kept for parity - via Home/Index.cshtml's
1256    // own ?fl=1 fallback path for when the popup was blocked and openFedLoginPopup fell back to a
1257    // full-page redirect. status is one of 'success' | 'signup' | 'login' | 'failed'.
1258    authenticationMethods.handleFedLoginResult = function (result) {
1259        var controls = authenticationPrivateMethods.controls;
1260        if (!result) return;
1261
1262        if (result.status === 'success') {
1263            // The popup already hit the server callback and set the login cookie; reloading this
1264            // exact page (not navigating to "/") picks up the server-rendered logged-in header/cart
1265            // without losing the page the customer was actually on.
1266            window.location.reload();
1267            return;
1268        }
1269
1270        if (result.status === 'signup') {
1271            $(controls.loginModal).modal('show');
1272            $(controls.emailSignUp).val(result.email || '');
1273            $('#newacount_emailid_field').addClass('hide');
1274            $(controls.loginModalTitle).html('Create Account');
1275            $(controls.mobileControls).toggleClass('hide', true);
1276            $(controls.otpControls).toggleClass('hide', false);
1277            $(controls.signupControls).removeClass('hide');
1278            $(controls.otpControls).addClass('hide');
1279            $('.sociallogin').addClass('hide');
1280            $('#email-acc-create').addClass('hide');
1281            $('#phone-acc-create').removeClass('hide');
1282            $('#pwd-acc-create').removeClass('hide');
1283            return;
1284        }
1285
1286        if (result.status === 'login') {
1287            $(controls.loginModal).modal('show');
1288            $(controls.loginModalTitle).html('Login');
1289            $(controls.mobileControls).toggleClass('hide', true);
1290            $(controls.otpControls).addClass('hide');
1291            $('.enterpassword_control').removeClass('hide');
1292            $('#psw-email').val(result.email || '');
1293            $('#lbl-password').html('Please enter your password');
1294            return;
1295        }
1296
1297        // 'failed', or anything unrecognized
1298        master.showResult('There is a technical error. Please contact administrator for more details', 'Failure', false);
1299    };
1300
1301    // Bound once at page init (see initializePage below) rather than per-click, since the message
1302    // can arrive any time after the popup opens. Origin-checked so only our own callback page
1303    // (FedLoginPopupResult.cshtml, same origin) can trigger this - postMessage has no other
1304    // built-in sender restriction.
1305    function registerFedLoginMessageListener() {
1306        window.addEventListener('message', function (event) {
1307            if (event.origin !== window.location.origin) return;
1308            var data = event.data;
1309            if (!data || data.source !== 'bitszol-fed-login') return;
1310            authenticationMethods.handleFedLoginResult(data);
1311        });
1312    }
1313
1314    return authenticationMethods;
1315})();
1316$(function () {
1317    authentication.initializePage();
1318});
1319var address = (function () {
1320    var addressMethods = {}, addressPrivateMethods = {};
1321
1322    addressPrivateMethods.events = {};
1323
1324    addressMethods.properties = {
1325        hasAddress: true,
1326        logoutOnClose: false,
1327        signupPhone: '',
1328        signupEmail: '',
1329        signupName: '',
1330        needDelivery: true,
1331        addressKey: 'ak_la3pqmnt3LrJ16Jm51QyieMp2o7Z5',
1332        deflatitude: 28.5935552,
1333        deflongitude: 77.2961699,
1334        password: '',
1335        outsideUk: master.properties.countryCode ? (master.properties.countryCode == 'UK' ? true : false) : false,
1336        locality: ''
1337    };
1338    addressPrivateMethods.properties = {
1339        map: null,
1340        autocomplete: null,
1341        geocoder: null,
1342        locationDetails: {
1343            street_number: "",
1344            route: "",
1345            locality: "",
1346            administrative_area_level_1: "",
1347            country: "",
1348            postal_code: "",
1349            latitude: 28.5935552,
1350            longitude: 77.2961699
1351        },
1352        fullLocationAddresss: '',
1353        isInvokedFromHeader: false,
1354        hasSelected: false,
1355        selectedAddressId: 0,
1356        countryNumber: '1',
1357        selectedStateId: '',
1358        selectedStateName: '',
1359        selectedDistrictName: '',
1360        stateList: [],
1361        addressType: "Home",
1362    };
1363    addressMethods.url = {
1364        addAddress: '/Address/AddAddress',
1365        verifyOtp: '',
1366        signUp: '',
1367        changeAddress: '/Address/ChangeAddress',
1368        removeAddress: '/Address/DeleteAddress',
1369        branches: '/branches',
1370        switchbranch: '/switchbranch',
1371        getAddrStates: '/getAddrStates',
1372        getDistricts: '/getDistricts'
1373    };
1374
1375    addressPrivateMethods.controls = {
1376        addressModal: '#address-modal',
1377        location: 'txt-location',
1378        map: 'map',
1379        deliveryMap: 'delivery-map',
1380        //submit: '#btn-add-address',
1381        showModal: '.btn-show-address-popup',
1382        chooseLocation: "#choose-location",
1383        chooseLocationModal: "#choose-location-modal",
1384        addressForm: "#frmaddaddress",
1385        removeAddress: '.remove_adress',
1386        chooseDeliveryMethod: '#choose-deliverymethod',
1387        deliveryAddress: '.delivery_adress',
1388        branchModel: '#BranchesModal',
1389        chooseDeliveryType: '#choose-deliverytype-modal',
1390        addAddressButton: '#btn-add-address',
1391        searchLocation: '.searchlocation',
1392        houseNumber: '#txt-house-number',
1393        houseName: '#txt-street-name',
1394        streetName: '#txt-street-name',
1395        addressLineOne: '#txt-addressline-one',
1396        addressLineTwo: '#txt-addressline-two',
1397        state: '#txt-state',
1398        addressType: '#drp-address-type',
1399        postalcode: '#txt-post-code',
1400        landmark: '#txt-landmark',
1401        district: '#txt-district',
1402        addressTypeOtherSection: '.other-address-Type',
1403        otherType: '#txt-other-type',
1404        addressTile: '.address-tile-',
1405        addressChangeConfirmationModal: '#address-change-confirmation',
1406        changeAddressConfirm: '#btn-confirm-address-change',
1407        changeAddressCancel: '#btn-cancel-address-change',
1408        districtLabel: '#lbl-district',
1409        your_location_btn: '.your_location',
1410        outsideUk: '#outsideUk',
1411        withinUk: '#withinUk',
1412        mapLocationField: '#map-location-field',
1413        postCodeLookup: '.postcode_lookup_wrap',
1414        addrNotListedLabel: '.addr-not-listed'
1415    };
1416
1417    addressMethods.initializeMap = function () {
1418        $(addressPrivateMethods.controls.searchLocation).find('#' + addressPrivateMethods.controls.map).show();
1419        $('#' + addressPrivateMethods.controls.map).css('height', '400px');
1420        $('#' + addressPrivateMethods.controls.map).css('width', '100%');
1421        $('#' + addressPrivateMethods.controls.map).css('overflow', 'unset');
1422
1423        var myLatlng = new google.maps.LatLng(addressMethods.properties.deflatitude, addressMethods.properties.deflongitude);
1424        if (navigator.geolocation) {
1425            navigator.geolocation.getCurrentPosition(function (position) {
1426                myLatlng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
1427            });            
1428        }
1429        var scrollwheelanddraggable =
1430            master.properties.countryCode !== 'UK' ? true : ($('#getaddress_dropdown').val() && $('#getaddress_dropdown').val() !== 'open' ? false : true);
1431        var mapOptions = {
1432            center: myLatlng,
1433            zoom: 17,
1434            disableDefaultUI: !scrollwheelanddraggable,
1435            scrollwheel: scrollwheelanddraggable,
1436            draggable: scrollwheelanddraggable,
1437            panControl: false,
1438            zoomControlOptions: {
1439                style: google.maps.ZoomControlStyle.SMALL
1440            },
1441            mapTypeControl: false,
1442            scaleControl: false,
1443            streetViewControl: false,
1444        };
1445
1446        var map = new google.maps.Map(document.getElementById(addressPrivateMethods.controls.map),
1447            mapOptions);
1448
1449        var marker = new google.maps.Marker({
1450            position: myLatlng,
1451            map: map
1452        });
1453        addressPrivateMethods.properties.geocoder = new google.maps.Geocoder();
1454        google.maps.event.addListener(map, 'center_changed', function () {
1455
1456            // 0.1 seconds after the center of the map has changed,
1457            // set back the marker position.
1458            window.setTimeout(function () {
1459                var center = map.getCenter();
1460                marker.setPosition(center);
1461                //geocodePosition(marker.getPosition());
1462            }, 100);
1463        });
1464        google.maps.event.addListener(map, 'dragend', function () { // 'idle', function () {
1465
1466            // 0.1 seconds after the center of the map has changed,
1467            // set back the marker position.
1468            window.setTimeout(function () {
1469                //var center = map.getCenter();
1470                //marker.setPosition(center);
1471                geocodePosition(marker.getPosition());
1472                $('.your_location').removeClass('active');
1473            }, 100);
1474        });
1475        // Create the DIV to hold the control.
1476        const centerControlDiv = document.createElement("div");
1477        // Create the control.
1478        const centerControl = createCenterControl(map);
1479
1480        function createCenterControl(map) {
1481            const controlButton = document.createElement("button");
1482
1483            // Emulate the style of Google Maps Current Location button
1484            controlButton.style.backgroundColor = "white";
1485            controlButton.style.width = "auto";
1486            controlButton.style.height = "auto";
1487            controlButton.style.minHeight = "auto";
1488            controlButton.style.border = "1px solid #ccc";
1489            controlButton.style.borderRadius = "8px";
1490            controlButton.style.boxShadow = "0 1px 4px rgba(0, 0, 0, 0.3)";
1491            controlButton.style.cursor = "pointer";
1492            controlButton.style.fontFamily = "Roboto,Arial,sans-serif";
1493            controlButton.style.fontSize = "14px";
1494            controlButton.style.padding = "10px";
1495            controlButton.style.margin = "10px";
1496            controlButton.style.textAlign = "center";
1497            controlButton.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="21" height="21" viewBox="0 0 21 21" fill="none">
1498												<circle cx="10.25" cy="10.7149" r="6.99419" stroke="black" stroke-width="1.5" />
1499												<path d="M10.25 1.25V5.98256" stroke="black" stroke-width="1.5" stroke-linecap="round" />
1500												<path d="M10.25 15.0176V19.7501" stroke="black" stroke-width="1.5" stroke-linecap="round" />
1501												<path d="M19.5 10.5L14.7674 10.5" stroke="black" stroke-width="1.5" stroke-linecap="round" />
1502												<path d="M5.73242 10.5L0.999864 10.5" stroke="black" stroke-width="1.5" stroke-linecap="round" />
1503												<circle cx="10.2503" cy="10.7152" r="2.5814" fill="black" />
1504											</svg>`;
1505            //controlButton.style.backgroundImage = "~\images\mylocation.png";
1506            controlButton.classList.add("your_location");
1507
1508
1509            controlButton.title = "Your Location";
1510            controlButton.type = "button";
1511
1512            // Set hover effect
1513            controlButton.addEventListener("mouseenter", () => {
1514                controlButton.style.backgroundColor = "#f9f9f9";
1515            });
1516
1517            controlButton.addEventListener("mouseleave", () => {
1518                controlButton.style.backgroundColor = "white";
1519            });
1520
1521            controlButton.addEventListener("click", () => {
1522                map.setCenter(myLatlng);
1523                window.setTimeout(function () {
1524                    geocodePosition(marker.getPosition());
1525                    $('.your_location').addClass('active');
1526                }, 100);
1527
1528            });
1529            addressMethods.setCurrentLoaction = function () {
1530                map.setCenter(myLatlng);
1531                window.setTimeout(function () {
1532                    geocodePosition(marker.getPosition());
1533                    $('.your_location').addClass('active');
1534                }, 100);
1535            };
1536            return controlButton;
1537        }
1538
1539        // Append the control to the DIV.
1540        if (scrollwheelanddraggable) {
1541            centerControlDiv.appendChild(centerControl);
1542            map.controls[google.maps.ControlPosition.TOP_RIGHT].push(centerControlDiv);
1543        }
1544
1545    };
1546
1547    function geocodePosition(pos) {
1548        addressPrivateMethods.properties.geocoder.geocode({
1549            latLng: pos
1550        }, function (responses) {
1551            if (responses && responses.length > 0) {
1552                var addr = responses[0].formatted_address;
1553                $('#' + addressPrivateMethods.controls.location).val(addr);
1554                addressPrivateMethods.properties.hasSelected = true;
1555                addressPrivateMethods.properties.fullLocationAddresss = responses[0].formatted_address;
1556                addressPrivateMethods.fillInAddressProperties(responses[0]);
1557
1558            }
1559        });
1560    }
1561
1562    addressPrivateMethods.initializeAddressAutocompleteUsingGoogleMap = function () {
1563        var addressInput = document.getElementById(addressPrivateMethods.controls.location);
1564        destroyAutocomplete();
1565        addressPrivateMethods.properties.autocomplete = createAutocomplete(addressInput);
1566    };
1567    function destroyAutocomplete() {
1568        if (addressPrivateMethods.properties.autocomplete) {
1569            google.maps.event.clearInstanceListeners(addressPrivateMethods.properties.autocomplete);
1570            $(".pac-container").remove(); // Removing the suggestions dropdown from dom
1571            // Remove the autocomplete instance
1572            addressPrivateMethods.properties.autocomplete = null;
1573        }
1574    }
1575    function createAutocomplete(input) {
1576        var options = {
1577            types: [],
1578            fields: ["address_components", "geometry"]
1579        };
1580
1581        if (master.properties.countryCode == 'IN' || (master.properties.countryCode == 'UK' && !addressMethods.properties.outsideUk)) {
1582            options.componentRestrictions = {
1583                country: master.properties.countryCode
1584            };
1585        }
1586
1587        // options.fields already requests the fields we need; the old setFields(["address_component", ...])
1588        // call overrode it with the legacy singular name, which can leave place.address_components undefined.
1589        var autocomplete = new google.maps.places.Autocomplete(input, options);
1590        autocomplete.addListener("place_changed", addressPrivateMethods.fillInAddress);
1591
1592        return autocomplete;
1593    }
1594
1595    addressPrivateMethods.initializeAddressAutocomplete = function () {
1596        IdealPostcodes.AddressFinder.setup({
1597            apiKey: addressMethods.properties.addressKey,
1598            outputFields: {
1599                line_1: addressPrivateMethods.controls.addressLineOne,
1600                line_2: addressPrivateMethods.controls.addressLineTwo,
1601                postcode: addressPrivateMethods.controls.postalcode,
1602                post_town: addressPrivateMethods.controls.district
1603            },
1604        });
1605    };
1606
1607    addressPrivateMethods.changeAddress = function (self) {
1608        if (!addressPrivateMethods.properties.selectedAddressId || addressPrivateMethods.properties.selectedAddressId < 1)
1609            return;
1610
1611        $(addressPrivateMethods.controls.changeAddressConfirm).prop("disabled", true);
1612        $(addressPrivateMethods.controls.changeAddressCancel).prop("disabled", true);
1613        $(self).addClass("processing");
1614
1615        onSuccess = function (data) {
1616            if (window.location.pathname != '/')
1617                window.location.href = '/';
1618            else
1619                window.location.reload(true);
1620        };
1621
1622        onError = function (data) {
1623            console.log(data);
1624            $(self).removeClass('processing');
1625        };
1626        master.ajax.JSONRequest(addressMethods.url.changeAddress, 'POST', { AddressId: addressPrivateMethods.properties.selectedAddressId }, onSuccess, onError);
1627    };
1628
1629    addressMethods.getBranches = function (obj) {
1630
1631        onSuccess = function (data) {
1632            if (data && data.length > 0) {
1633                var div_data = "";
1634                var template = '<div class="card hover-overlay ripple shadow-1-strong rounded" style="width: 99%; margin: 3px auto; cursor: pointer; box-shadow: 0 4px 8px 0 rgb(0 0 0 / 20%); transition: .3s; height: 100%; " onclick="address.switchBranch(this);" brid="[BRANCHID]"><div class="row myorder" style="padding: 20px;"><div class="col-md-12 col-xs-12"><b><i class="fa fa-shopping-cart" style="margin-right: 4px;"></i> [NAME]</b></div></div></div>';
1635                $.each(data, function (k, v) {
1636                    div_data += template.replace('[NAME]', v.br_Name + '<br/> ' + v.br_Address).replace('[BRANCHID]', v.br_ID);
1637                });
1638                $(obj).html(div_data);
1639            }
1640
1641        };
1642
1643        onError = function (data) {
1644            console.log(data);
1645        };
1646        master.ajax.JSONRequest(addressMethods.url.branches, 'POST', {}, onSuccess, onError);
1647    };
1648    addressMethods.switchBranch = function (obj) {
1649        var brid = $(obj).attr('brid');
1650        onSuccess = function (data) {
1651            window.location.reload(true);
1652        };
1653
1654        onError = function (data) {
1655            console.log(data);
1656        };
1657        master.ajax.JSONRequest(addressMethods.url.switchbranch, 'POST', { br_id: brid }, onSuccess, onError);
1658    };
1659
1660    addressMethods.deleteAddress = function (self) {
1661        var isPrimary = $(self).find('.delivery_location.delivery_adress').data('primary');
1662        var addressId = $(self).find('.delivery_location.delivery_adress').data('addrid');
1663        //console.log(isPrimary, addressId);
1664        if (isPrimary == '1') {
1665            alert('Sorry, you cannot remove primary address!');
1666            return;
1667        }
1668        if (!confirm("Are you sure you want to remove this address?"))
1669            return;
1670
1671        onSuccess = function (data) {
1672
1673            window.location.reload();
1674        };
1675
1676        onError = function (data) {
1677            //console.log(data);
1678        };
1679        master.ajax.JSONRequest(addressMethods.url.removeAddress, 'POST', { AddressId: addressId }, onSuccess, onError);
1680    };
1681
1682    addressPrivateMethods.fillInAddress = function () {
1683        var place = addressPrivateMethods.properties.autocomplete.getPlace();
1684        if (!place || !place.geometry)
1685            return; // user pressed Enter without picking a suggestion
1686
1687        if (place.address_components && place.address_components.length > 0) {
1688            addressPrivateMethods.fillInAddressProperties(place);
1689        } else {
1690            // Fall back to reverse geocoding so state/district/postcode still get populated
1691            new google.maps.Geocoder().geocode({ location: place.geometry.location }, function (results, status) {
1692                if (status === "OK" && results[0])
1693                    addressPrivateMethods.fillInAddressProperties({ address_components: results[0].address_components, geometry: place.geometry });
1694                else
1695                    console.error('Unable to resolve address components for selected place', status);
1696            });
1697        }
1698        $(addressPrivateMethods.controls.searchLocation).addClass('searchlocationselected');
1699        $(addressPrivateMethods.controls.searchLocation + ' input.form-control').prop('disabled', true);
1700
1701        addressMethods.properties.deflatitude = place.geometry.location.lat();
1702        addressMethods.properties.deflongitude = place.geometry.location.lng();
1703        addressMethods.initializeMap();
1704        if (loggedIn == "False") {
1705            master.updateguestuser();
1706        }
1707    };
1708
1709    addressPrivateMethods.fillInAddressProperties = async function (place) {
1710
1711        $(addressPrivateMethods.controls.addressForm).find("p.Error").remove();
1712        addressPrivateMethods.properties.fullLocationAddresss = '';
1713        addressPrivateMethods.properties.locationDetails = {
1714            subpremise: "", premise: "",
1715            neighborhood: "", postal_town: "", sublocality: "",
1716            street_number: "",
1717            route: "",
1718            locality: "",
1719            administrative_area_level_3: "",
1720            administrative_area_level_2: "",
1721            administrative_area_level_1: "",
1722            country: "",
1723            postal_code: "",
1724            latitude: 0,
1725            longitude: 0
1726
1727        };
1728
1729        var addressArray = [];
1730
1731        place.address_components.forEach(comp => {
1732            comp.types.forEach(type => {
1733                if (addressPrivateMethods.properties.locationDetails.hasOwnProperty(type)) {
1734                    addressPrivateMethods.properties.locationDetails[type] = comp.long_name;
1735                    addressArray.push(comp.long_name);
1736                }
1737            });
1738        });
1739
1740
1741        const house = addressPrivateMethods.properties.locationDetails.subpremise || addressPrivateMethods.properties.locationDetails.premise || addressPrivateMethods.properties.locationDetails.street_number;
1742        const street = addressPrivateMethods.properties.locationDetails.route || addressPrivateMethods.properties.locationDetails.neighborhood || "";
1743        const lineOne = (addressPrivateMethods.properties.locationDetails.route !== null ? addressPrivateMethods.properties.locationDetails.neighborhood : null) || addressPrivateMethods.properties.locationDetails.locality || addressPrivateMethods.properties.locationDetails.postal_town || "";
1744        const lineTwo = addressPrivateMethods.properties.locationDetails.sublocality || addressPrivateMethods.properties.locationDetails.administrative_area_level_2 || "";
1745
1746        $('.populate-autoselection-primary').html(lineOne);
1747
1748        if (addressArray.length > 0)
1749            addressPrivateMethods.properties.hasSelected = true;
1750
1751        addressPrivateMethods.properties.fullLocationAddresss = addressArray.join();
1752        addressPrivateMethods.properties.locationDetails.latitude = place.geometry.location.lat();
1753        addressPrivateMethods.properties.locationDetails.longitude = place.geometry.location.lng();
1754
1755        if (addressPrivateMethods.properties.locationDetails.administrative_area_level_1 != '') {
1756            $(addressPrivateMethods.controls.state).val(addressPrivateMethods.properties.locationDetails.administrative_area_level_1);
1757            if (master.properties.countryCode == "IN") {
1758                addressMethods.getAddrStates();
1759            }
1760
1761        }
1762
1763        if (addressPrivateMethods.properties.locationDetails.administrative_area_level_2 != '')
1764            $(addressPrivateMethods.controls.district).val(addressPrivateMethods.properties.locationDetails.administrative_area_level_2);
1765        else if (addressPrivateMethods.properties.locationDetails.locality != '')
1766            $(addressPrivateMethods.controls.district).val(addressPrivateMethods.properties.locationDetails.locality);
1767        if (addressPrivateMethods.properties.locationDetails.postal_code != '')
1768            $(addressPrivateMethods.controls.postalcode).val(addressPrivateMethods.properties.locationDetails.postal_code);
1769
1770    };
1771    addressMethods.fillInFindAddress = function (addr, lat, lng, district, post, city, state) {
1772        $(addressPrivateMethods.controls.addressForm).find("p.Error").remove();
1773        addressPrivateMethods.properties.fullLocationAddresss = '';
1774        addressPrivateMethods.properties.locationDetails = {
1775            street_number: "",
1776            route: "",
1777            locality: city,
1778            administrative_area_level_3: "",
1779            administrative_area_level_2: district,
1780            administrative_area_level_1: state,
1781            country: "",
1782            postal_code: post,
1783            latitude: lat,
1784            longitude: lng
1785        };
1786
1787        addressPrivateMethods.properties.hasSelected = true;
1788        addressPrivateMethods.properties.fullLocationAddresss = addr;
1789        addressMethods.properties.deflatitude = lat; addressMethods.properties.deflongitude = lng; addressMethods.properties.locality = addr;
1790        addressMethods.initializeMap();
1791    };
1792    addressMethods.backSearchView = function () {
1793        $(addressPrivateMethods.controls.searchLocation).removeClass('searchlocationselected');
1794        $(addressPrivateMethods.controls.searchLocation + ' input.form-control').prop('disabled', false);
1795        $(addressPrivateMethods.controls.searchLocation).find('#' + addressPrivateMethods.controls.map).hide();
1796        $('#' + addressPrivateMethods.controls.location).removeProp('disabled');
1797        $('#' + addressPrivateMethods.controls.location).val('');
1798        $('#' + addressPrivateMethods.controls.location).focus();
1799    };
1800    addressMethods.showSelAddress = function (logoutOnClose) {
1801        addressMethods.backSearchView();
1802        $(addressPrivateMethods.controls.addressModal).modal('hide');
1803
1804        $(addressPrivateMethods.controls.chooseLocationModal).modal({ backdrop: 'static', keyboard: false });
1805        $(addressPrivateMethods.controls.chooseLocationModal).find('.model-left').css('width', '100%');
1806        if (logoutOnClose) {
1807            $(addressPrivateMethods.controls.chooseLocationModal).find('.close').unbind('click').on('click', function () {
1808                if (confirm("You need to select address to avail the service of store. You'll be logged out if you close now. Are you sure to skip and continue?"))
1809                    window.location.href = '/logout';
1810                else
1811                    return false;
1812            });
1813        }
1814    };
1815
1816    addressPrivateMethods.onAddAddressInvoke = function (logoutOnClose) {
1817        var controls = addressPrivateMethods.controls;
1818        if ($(controls.chooseLocationModal).hasClass('show')) {
1819            $(controls.chooseLocationModal).modal('hide');
1820            addressPrivateMethods.properties.isInvokedFromHeader = true;
1821        }
1822        if (logoutOnClose) {
1823            $(controls.addressModal).find('.closepopup').unbind('click').on('click', function () {
1824                if (confirm("You need atleast one address to avail the service of store. You'll be logged out if you close now. Are you sure to cancel?"))
1825                    window.location.href = '/logout';
1826                else
1827                    return false;
1828            });
1829        }
1830        $(controls.addressModal).modal('show');
1831    };
1832
1833    addressPrivateMethods.isValidForm = function () {
1834        var isValid = true;
1835        $(addressPrivateMethods.controls.addressForm).find("p.Error").remove();
1836
1837        if (!addressPrivateMethods.properties.hasSelected) {
1838            $(addressPrivateMethods.controls.addressForm).find('#' + addressPrivateMethods.controls.location).parent().append("<p class='Error'>Invalid location. Please select location from list.</p>");
1839            return false;
1840        }
1841        $(addressPrivateMethods.controls.addressForm).find('input[type="text"]').each(function () {
1842            var isValid = true;
1843            $(this).siblings("p.Error").remove();
1844            if ($(this).hasClass('required') && $(this).val() == '') {
1845                $(this).parent().append("<p class='Error'>This field is required</p>");
1846                isValid = false;
1847            }
1848        });
1849
1850        if ($(addressPrivateMethods.controls.addressType).val() == '') {
1851            $(addressPrivateMethods.controls.addressType).parent().append("<p class='Error'>This field is required</p>");
1852        } else {
1853            $(addressPrivateMethods.controls.addressType).siblings("p.Error").remove();
1854        }
1855
1856        if ($(addressPrivateMethods.controls.addressForm).find("p.Error").length > 0)
1857            isValid = false;
1858
1859        return isValid;
1860    };
1861
1862    addressMethods.loadNearestStores = function (lat, lng) {
1863        $('.dvnearestbranch').html('');
1864        $('.dvnearestbranch').parent().next('.preferredstoreslider').remove();
1865        onSuccess = function (data) {
1866            if (data.stores.data.length <= 0) {
1867                $('.dvnearestbranch').html("<p>No nearby stores are currently available. Kindly utilize the 'change location' option above to locate stores in a different area.</p>");
1868                return;
1869            }
1870
1871            var featuredOuterTemplate = '<div class="swiper preferredstoreslider store_list_wrap_sec d-flex flex-wrap row g-3"><div id="cnt_neareststores" class="swiper-wrapper p-0 m-0">[ITEMREPEAT]</div><div class="swiper-button-next"></div><div class="swiper-button-prev"></div></div>';
1872            var featuredRepeatTemplate = '<div class="swiper-slide"><div class="store_list_wrap justify-content-center d-flex flex-wrap"><div class="card p-3"><a href="/br/[STOREID]/[STORENAME]"><span class="highlight_store"><i class="fa-solid fa-star"></i></span><div class="store_logo d-flex justify-content-center align-items-center mb-2">[STORELOGO] <h4>[STORENAME]</h4></div><div style="position: relative;" class=""><div class="store_location w-100 text-center"> &nbsp;</div><div class="store_category w-100 text-center">[STOREADDRESS]</div><div class="store_visite"><span class="visite_store">Visit Store Now</span></div></div></a></div></div></div>';
1873
1874            var template = '<div class="store_list_wrap col-12 col-sm-6 col-md-4 col-lg-3 justify-content-center d-flex flex-wrap"><div class="card p-3"><a href="/br/[STOREID]/[STORENAME]"><div class="store_awayfrom text-center"><span>[DISTANCE] km</span> Away</div><div class="store_logo d-flex justify-content-center align-items-center mb-2">[STORELOGO] <h4>[STORENAME]</h4></div><div style="position: relative;" class=""><div class="store_location w-100 text-center"> &nbsp;</div><div class="store_category w-100 text-center">[STOREADDRESS]</div><div class="store_visite"><span class="visite_store">Visit Store</span></div></div></a></div></div>';
1875            var div_data = '';
1876            var div_featured_data = '';
1877            var indx = 0;
1878            var hasFeaturedTemplate = 0;
1879            for (var i = 0; i < data.stores.data.length && (i < (data.stores.data.length >= 8 ? 4 : 8)); i++) {
1880                var dst = Math.round(data.stores.data[i].distance * 100) / 100;
1881                var logoTemplate = (data.stores.data[i].logo && data.stores.data[i].logo != '' ? '<img src="' + data.stores.data[i].logo + '"/>' : '');
1882                div_data += template.replace('[STORENAME]', data.stores.data[i].br_Name).replace('[STORENAME]', data.stores.data[i].br_Name).replace('[STORELOGO]', logoTemplate).replace('[STOREID]', data.stores.data[i].br_ID).replace('[DISTANCE]', dst).replace('[STOREADDRESS]', data.stores.data[i].br_Address + ',' + data.stores.data[i].br_City);
1883                indx += 1;
1884            }
1885            for (var i = indx; i < data.stores.data.length; i++) {
1886                var dst2 = Math.round(data.stores.data[i].distance * 100) / 100;
1887                var logoTemplate2 = (data.stores.data[i].logo && data.stores.data[i].logo != '' ? '<img src="' + data.stores.data[i].logo + '"/>' : '');
1888                div_featured_data += featuredRepeatTemplate.replace('[STORENAME]', data.stores.data[i].br_Name).replace('[STORENAME]', data.stores.data[i].br_Name).replace('[STORELOGO]', logoTemplate2)
1889                    .replace('[STOREID]', data.stores.data[i].br_ID).replace('[DISTANCE]', dst2)
1890                    .replace('[STOREADDRESS]', data.stores.data[i].br_Address + ',' + data.stores.data[i].br_City).replace('[STORELOGO]', '');
1891                indx += 1;
1892                hasFeaturedTemplate += 1;
1893            }
1894
1895            $('.dvnearestbranch').html(div_data);
1896            if (hasFeaturedTemplate > 0) {
1897                $('.dvnearestbranch').parent().after(featuredOuterTemplate.replace('[ITEMREPEAT]', div_featured_data));
1898            }
1899
1900        };
1901
1902        onError = function (data) {
1903            $('.dvnearestbranch').html("<p>Your location is not accessible. Please use the change location button above to find the stores nearby.</p>");
1904        };
1905        master.ajax.JSONRequest('/findneareststores/' + lat + '/' + lng, 'POST', {}, onSuccess, onError);
1906    };
1907
1908    addressPrivateMethods.addAddress = function (self) {
1909
1910
1911        var controls = addressPrivateMethods.controls;
1912        var locationDetails = addressPrivateMethods.properties.locationDetails;
1913        var addrType = addressPrivateMethods.properties.addressType;
1914        var mobile = addressMethods.properties.signupPhone ? addressMethods.properties.signupPhone : $('#txt-addr-phoneNumber').val();
1915        $(controls.addAddressButton).prop('disabled', true);
1916        $(controls.addAddressButton).addClass('processing');
1917
1918
1919        if (!addressPrivateMethods.isValidForm()) {
1920            $(controls.addAddressButton).prop('disabled', false);
1921            $(self).find('.processing').removeClass('processing');
1922            return false;
1923        }
1924        if (addrType == 'other' && $(controls.otherType).val() != '')
1925            addrType = $(controls.otherType).val();
1926        let deliveryState = ($(addressPrivateMethods.controls.state).val() == '' ? locationDetails.administrative_area_level_1 : $(addressPrivateMethods.controls.state).val());
1927        let deliveryCity = locationDetails.locality;
1928        if (master.properties.countryCode == "UAE") {
1929            deliveryCity = addressPrivateMethods.properties.selectedDistrictName;
1930        } else if (master.properties.countryCode != "GB") {
1931            deliveryState = addressPrivateMethods.properties.selectedStateName == '' ? locationDetails.administrative_area_level_1 : addressPrivateMethods.properties.selectedStateName;
1932        }
1933        var deliDistrict = $(controls.district + ' option:selected').text(); //$(controls.district).val(); 
1934        var deliveryName = $('#txt-addr-username').val();
1935        var details = {
1936            deli_delivery_pin: $(controls.postalcode).val(),
1937            deli_house_no: $(controls.houseNumber).val(),
1938            deli_house_name: $(controls.houseName).val(),
1939            deli_land_mark: $(controls.landmark).val(),
1940            deli_city: deliveryCity,
1941            deli_state: deliveryState,
1942            deli_district: deliDistrict, //deliveryCity,
1943            deli_type: addrType,
1944            deli_latitude: locationDetails.latitude,
1945            deli_longitude: locationDetails.longitude,
1946            deli_google_pin: locationDetails.postal_code === '' ? $(controls.postalcode).val() : locationDetails.postal_code,
1947            deli_post: locationDetails.postal_code === '' ? $(controls.postalcode).val() : locationDetails.postal_code,
1948            deli_address: $(controls.addressLineOne).val(),
1949            deli_address2: $(controls.addressLineTwo).val(),
1950            deli_google_address: addressPrivateMethods.properties.fullLocationAddresss,
1951            deli_is_primary: 0,
1952            deli_contact_no: mobile,
1953            deli_name: deliveryName,
1954            deli_email: addressMethods.properties.signupEmail,//Not necessary for now, in India. may be necessary for UK
1955            signupEmail: addressMethods.properties.signupEmail,
1956            signupName: addressMethods.properties.signupName,
1957            password: address.properties.password
1958        };
1959        onSuccess = function (data) {
1960            if (window.location.pathname != '/')
1961                window.location.href = '/';
1962            else
1963                window.location.reload(true);
1964        };
1965
1966        onError = function (data) {
1967            $(self).find('.processing').removeClass('processing');
1968            console.log(data);
1969        };
1970        // console.log(details)
1971        master.ajax.JSONRequest(addressMethods.url.addAddress, 'POST', details, onSuccess, onError);
1972    };
1973
1974    addressPrivateMethods.events.onChooseLocation = function () {
1975        var controls = addressPrivateMethods.controls;
1976        $(controls.chooseDeliveryType).modal('hide');
1977        $(controls.chooseDeliveryType).find('.model-left').css('width', '0%');
1978        $(controls.chooseLocationModal).modal('show');
1979        $(controls.chooseLocationModal).find('.model-left').css('width', '100%');
1980    };
1981
1982    addressPrivateMethods.events.onChooseDeliveryType = function () {
1983        var controls = addressPrivateMethods.controls;
1984        $(controls.chooseDeliveryType).modal('show');
1985        $(controls.chooseDeliveryType).find('.model-left').css('width', '100%');
1986    };
1987
1988    addressPrivateMethods.events.toggleOtherAddressSection = function (selectedType) {
1989        //console.log(selectedType);
1990        var controls = addressPrivateMethods.controls;
1991        addressPrivateMethods.properties.addressType = selectedType;
1992        if (selectedType === 'other') {
1993            $(controls.addressTypeOtherSection).removeClass('hide');
1994            $(controls.otherType).addClass('required');
1995        } else {
1996            $(controls.addressTypeOtherSection).addClass('hide');
1997            $(controls.otherType).removeClass('required');
1998        }
1999    };
2000
2001    addressMethods.triggerAddAddress = function (logoutOnClose) {
2002        addressPrivateMethods.onAddAddressInvoke(logoutOnClose);
2003    };
2004    addressMethods.returnGuestLocation = function () {
2005        return addressPrivateMethods.properties.locationDetails;
2006    };
2007    addressMethods.returnGuestLocationAutoDetect = function () {
2008        return {
2009            latitude: addressMethods.properties.deflatitude,
2010            longitude: addressMethods.properties.deflongitude,
2011            locality: addressMethods.properties.locality
2012        };
2013    };
2014
2015    addressMethods.getAddrStates = function () {
2016        var countryNumber = addressPrivateMethods.properties.countryNumber;
2017        if (master.properties.countryCode == "UAE")
2018            countryNumber = '3';
2019        else if (master.properties.countryCode == "UK") {
2020            countryNumber = '2';
2021        }
2022        var onSuccess = function (data, apiSkipped) {
2023            if (data.status == 'ok' || apiSkipped) {
2024                addressPrivateMethods.properties.stateList = data.data;
2025                var select = document.getElementById('txt-state');
2026                select.innerHTML = '<option value="">Select a State</option>'; // Reset the select options
2027
2028                var locationDetails = addressPrivateMethods.properties.locationDetails;
2029                var selectedStateId = null;
2030                // Google and the API differ on case and "and" vs "&" (e.g. "Jammu and Kashmir" / "Jammu & Kashmir")
2031                var normalizeState = function (name) {
2032                    return (name || '').toLowerCase().replace(/&/g, 'and').replace(/\s+/g, ' ').trim();
2033                };
2034                var googleState = normalizeState(locationDetails.administrative_area_level_1);
2035
2036                // Populate the select options
2037                data.data.forEach(function (state) {
2038                    var option = document.createElement('option');
2039                    option.value = state.st_ID;
2040                    option.text = state.st_name;
2041                    if (!selectedStateId && ($(select).attr('selst') == state.st_name || (googleState && googleState === normalizeState(state.st_name)))) {
2042                        option.selected = true;
2043                        selectedStateId = state.st_ID;
2044                    }
2045                    select.appendChild(option);
2046                });
2047
2048                // If a state was selected, save its ID and name
2049                if (selectedStateId) {
2050                    addressPrivateMethods.properties.selectedStateId = selectedStateId;
2051                    addressPrivateMethods.properties.selectedStateName = locationDetails.administrative_area_level_1;
2052                    addressMethods.onStateChange();
2053                }
2054            }
2055        };
2056
2057        var onError = function (data) {
2058            console.log(data);
2059        };
2060
2061        if (addressPrivateMethods.properties.stateList.length == 0)
2062            master.ajax.JSONRequest(addressMethods.url.getAddrStates, 'POST', countryNumber, onSuccess, onError);
2063        else {
2064            var a = { data: addressPrivateMethods.properties.stateList };
2065            onSuccess(a, true);
2066        }
2067    };
2068    $(document).on('change', '#txt-state', function () {
2069        addressMethods.onStateChange();
2070    });
2071
2072    addressMethods.onStateChange = function () {
2073        var selectElement = document.getElementById('txt-state');
2074        var selectedStateId = selectElement.value;
2075        var selectedStateName = selectElement.options[selectElement.selectedIndex].text;
2076
2077        if (!selectedStateId) return; // Exit if no state is selected
2078        addressPrivateMethods.properties.selectedStateId = selectedStateId;
2079        addressPrivateMethods.properties.selectedStateName = selectedStateName;
2080
2081        var onSuccess = function (data) {
2082            if (data.status === 'ok') {
2083                var select = document.getElementById('txt-district');
2084                select.innerHTML = '<option value="">Select a City/District</option>'; // Reset the select options
2085
2086                var locationDetails = addressPrivateMethods.properties.locationDetails;
2087                var selectedDistrictId = null;
2088
2089                data.data.forEach(function (district) {
2090                    var option = document.createElement('option');
2091                    option.value = district.dst_Id;
2092                    option.text = district.dst_Name;
2093                    if ($(select).attr('seldist') == district.dst_Name || (locationDetails.administrative_area_level_3 && locationDetails.administrative_area_level_3 === district.dst_Name)) {
2094                        option.selected = true;
2095                        selectedDistrictId = district.dst_Id;
2096                    }
2097                    select.appendChild(option);
2098                });
2099
2100                // If a district was selected, save its ID and name
2101                if (selectedDistrictId) {
2102                    addressPrivateMethods.properties.selectedDistrictId = selectedDistrictId;
2103                    addressPrivateMethods.properties.selectedDistrictName = locationDetails.administrative_area_level_3;
2104                }
2105            }
2106        };
2107
2108        var onError = function (data) {
2109            console.log(data);
2110        };
2111
2112        master.ajax.JSONRequest(addressMethods.url.getDistricts, 'POST', selectedStateId, onSuccess, onError);
2113    };
2114
2115    addressPrivateMethods.events.InitializeAddressComponents = function () {
2116        $(addressPrivateMethods.controls.deliveryAddress).unbind('click').on('click', function () {
2117            if ($(this).parent().hasClass("active") || $(this).hasClass("active")) {
2118                $('#adressDropdown').modal('hide');
2119            } else {
2120                addressPrivateMethods.properties.selectedAddressId =
2121                    $(this).parent().data('addrid') || $(this).data('addrid');
2122                addressPrivateMethods.changeAddress($(this).parent());
2123            }
2124        });
2125
2126        $(addressPrivateMethods.controls.removeAddress).unbind('click').on('click', function () {
2127            addressMethods.deleteAddress($(this).parent());
2128        });
2129    };
2130
2131    addressMethods.onDistrictChange = function () {
2132        var selectElement = document.getElementById('txt-district');
2133        var selectedDistrictName = selectElement.options[selectElement.selectedIndex].text;
2134        addressPrivateMethods.properties.selectedDistrictName = selectedDistrictName;
2135
2136
2137    };
2138    addressPrivateMethods.events.initialize = function () {
2139        var controls = addressPrivateMethods.controls;
2140        let addressLoaded = false;
2141        $('#adressDropdown').on('shown.bs.modal', function () {
2142            if (addressLoaded)
2143                return;
2144
2145            $(this).find('div.addressListContainer').load('/Address/LoadAddresses', function () {
2146                addressLoaded = true;
2147                addressPrivateMethods.events.InitializeAddressComponents();
2148            });
2149        });
2150        
2151        $('#btn-search-address').unbind('click').on('click', function () {
2152            var locationDetails = addressPrivateMethods.properties.locationDetails;
2153            address.loadNearestStores(locationDetails.latitude, locationDetails.longitude);
2154            $('#search-address-modal').modal('hide');
2155        });
2156
2157        $('#search-address-modal').on('shown.bs.modal', function (e) {
2158            addressPrivateMethods.controls.map = 'searchmap';
2159            addressPrivateMethods.controls.location = 'search-txt-location';
2160            addressMethods.initializeMap();
2161            addressPrivateMethods.initializeAddressAutocompleteUsingGoogleMap();
2162
2163            addressPrivateMethods.controls.map = 'map';
2164            addressPrivateMethods.controls.location = 'txt-location';
2165
2166        });
2167
2168        $(controls.addressForm).unbind('submit').on('submit', function (event) {
2169            event.preventDefault();
2170            console.log('addAddress');
2171            addressPrivateMethods.addAddress($(this));
2172        });
2173
2174        $('#' + controls.location).unbind('change').on('change', function () {
2175            addressPrivateMethods.properties.hasSelected = false;
2176        });
2177
2178        $(controls.showModal).unbind('click').on('click', function () {
2179            addressPrivateMethods.onAddAddressInvoke(addressMethods.properties.logoutOnClose);
2180        });
2181
2182        $(controls.chooseLocation).unbind('click').on('click', function () {
2183            addressPrivateMethods.events.onChooseLocation();
2184        });
2185
2186        $(controls.chooseDeliveryMethod).unbind('click').on('click', function () {
2187            addressPrivateMethods.events.onChooseDeliveryType();
2188        });
2189
2190        $(controls.removeAddr).unbind('click').on('click', function (e) {
2191            e.stopImmediatePropagation(); e.stopPropagation();
2192            addressMethods.deleteAddress(this);
2193        });
2194
2195        $(controls.branchModel).on('shown.bs.modal', function (e) {
2196            addressMethods.getBranches($(this).find('.lstbranches'));
2197        });
2198        addressPrivateMethods.events.InitializeAddressComponents();
2199
2200        $('.address-type').change(function () {
2201            let selectedValue = $(this).val();
2202            addressPrivateMethods.events.toggleOtherAddressSection(selectedValue);
2203
2204        });
2205        $(controls.changeAddressConfirm).unbind('click').on('click', function () {
2206            addressPrivateMethods.changeAddress($(this));
2207        });
2208        $(controls.your_location_btn).unbind('click').on('click', function () {
2209            addressMethods.setCurrentLoaction();
2210
2211        });
2212        $('.detect-location').unbind('click').on('click', function () {
2213            $('.detect-location').addClass('processing');
2214            $('.search_address_input_text').html('<p>Locating you — this may take a few seconds…<p>');
2215            if (navigator.geolocation) {
2216                navigator.geolocation.getCurrentPosition(
2217                    function (position) {
2218                        const lat = position.coords.latitude;
2219                        const lng = position.coords.longitude;
2220
2221                        addressMethods.properties.deflatitude = lat;
2222                        addressMethods.properties.deflongitude = lng;
2223
2224                        // Reverse Geocoding
2225                        const geocoder = new google.maps.Geocoder();
2226                        const latlng = { lat: lat, lng: lng };
2227
2228                        geocoder.geocode({ location: latlng }, function (results, status) {
2229                            if (status === "OK" && results[0]) {
2230                                let locality = "";
2231                                locality = results[0].formatted_address;
2232                                addressMethods.properties.locality = locality;
2233                                $('.detect-location').removeClass('processing');
2234                                master.updateGuestUserByAutoDetect();
2235                            } else {
2236                                addressMethods.properties.locality = "Nearest Location";
2237                                master.updateGuestUserByAutoDetect();
2238
2239                            }
2240                        });
2241                    },
2242                    function (error) {
2243                        console.error("Error getting location:", error);
2244
2245                    }
2246                );
2247            } else {
2248                alert("Geolocation is not supported by this browser.");
2249            }
2250        });
2251        $(controls.addrNotListedLabel).unbind('click').on('click', function () {
2252            $(controls.mapLocationField).removeClass('hide');
2253            $(controls.postCodeLookup).addClass('hide');
2254        });
2255        
2256        $('.btn-more-address').unbind('click').on('click', function () {
2257            // Only require a picked location here - state lives on the next step and is validated on submit (required select)
2258            if ($('#txt-location').val() !== "" && addressPrivateMethods.properties.fullLocationAddresss !== "") {
2259                $('.address-details').toggleClass('hide');
2260                $('.address-location-map').toggleClass('hide');
2261            } else {
2262                alert('Please select a valid location from map');
2263            }
2264
2265        });
2266
2267        $('.changeDeliveryNumber').unbind('click').on('click', function () {
2268            $('#txt-addr-phoneNumber').attr('disabled', false);
2269            $('.changeDeliveryNumber').addClass('hide');
2270
2271        });
2272        // Function to log messages for checked and unchecked radio buttons
2273        function changeLocationPref(event) {
2274            const radioId = event.target.id;
2275            const checkedStatus = event.target.checked;
2276
2277            // Log messages based on checked status
2278            if (checkedStatus) {
2279                switch (radioId) {
2280                    case "outsideUk":
2281                        $(controls.mapLocationField).removeClass('hide');
2282                        $(controls.postCodeLookup).addClass('hide');
2283                        addressMethods.properties.outsideUk = true;
2284                        addressPrivateMethods.initializeAddressAutocompleteUsingGoogleMap();
2285                        $('.curt_locationwrap').removeClass('hide');
2286                        $('#getaddress_dropdown').val('open');
2287                        addressMethods.initializeMap();
2288
2289                        break;
2290                    case "withinUk":
2291                        $(controls.mapLocationField).addClass('hide');
2292                        $(controls.postCodeLookup).removeClass('hide');
2293                        addressMethods.properties.outsideUk = false;
2294                        addressPrivateMethods.initializeAddressAutocompleteUsingGoogleMap();
2295                        $('.curt_locationwrap').addClass('hide');
2296
2297                        break;
2298                    default:
2299                        //console.log('checked withinUk - default');
2300                        break;
2301                }
2302            }
2303        }
2304
2305        // Attach event listeners to the radio buttons
2306        document.querySelectorAll('input[type="radio"]').forEach(radio => {
2307            radio.addEventListener('change', changeLocationPref);
2308        });
2309    };
2310
2311    addressMethods.initializePage = function () {
2312        addressPrivateMethods.events.initialize();
2313        addressPrivateMethods.initializeAddressAutocompleteUsingGoogleMap();
2314
2315        getLocation = function (position) {
2316            addressPrivateMethods.properties.locationDetails.latitude = position.coords.latitude;
2317            addressPrivateMethods.properties.locationDetails.longitude = position.coords.longitude;
2318            addressMethods.initializeMap();
2319        };
2320
2321        handleError = function (error) {
2322            addressMethods.initializeMap();
2323        };
2324
2325        addressMethods.initializeMap();
2326        //addressMethods.getAddrStates();    //}
2327
2328    };
2329    return addressMethods;
2330})();
2331$(function () {
2332    address.initializePage();
2333});
2334var cart = (function () {
2335    var cartMethods = {}, cartPrivateMethods = {};
2336
2337    cartPrivateMethods.events = {};
2338
2339    cartMethods.properties = {
2340        isCartPage: false,
2341        multiCourier: false,
2342        cartItems: { 'items': [] },
2343        paymentGatewayType: 1, // 1: popup, 2: inline
2344        currencySymbol: '₹',
2345        notesLength: 200
2346    };
2347    cartPrivateMethods.properties = {
2348        isOtpTriggered: false,
2349        template: ''
2350
2351    };
2352    cartMethods.url = {
2353        addToCart: '/Cart/AddToCart',
2354        updateCart: '',
2355        deleteCart: '/Cart/DeleteCartItem',
2356        clearCart: '/Cart/ClearCart',
2357        cartCount: '/cartcount',
2358        updateQuantity: '/Cart/UpdateCart',
2359        cartSummary: '/Cart/CartSummary',
2360        addCoupon: '/Checkout/SubmitCoupon',
2361        removeCoupon:'/Checkout/RemoveCoupon',
2362        useWallet: '/Checkout/UseWallet',
2363        availableCoupons: '/checkout/availablecoupons/',
2364        changeDelivery: '/cart/replaceitem',
2365        setSlot: '/checkout/setslot',
2366        removeOrderGroup: '/checkout/removeorderGroup',
2367        addOrdernote: '/checkout/addOrderNote'
2368    };
2369
2370    cartPrivateMethods.controls = {
2371        deleteProduct: ".btn-cart-remove",
2372        cartcount: ".cartcount",
2373        addProduct: '.btn-add-product-cart',
2374        cartContainer: '#cart-container',
2375        qtyminus: '.minus',
2376        qtyplus: '.plus',
2377        clear: '#btnemptycart',
2378        applycoupon: '.btnapplycoupon',
2379        viewCoupons: '#btnViewCoupons',
2380        couponPopoverClose: '.coupon-popover_close',
2381        groupButton: '.btn-group',
2382        headerCartSection: '.minicart_menu',
2383        deleteOutOfStock: '.btn-cart-out-of-stock-remove',
2384        courierLabelBlock: '#courier-title-block',
2385        outOfSockTile: '.out-of-stock-tile',
2386        cartHeaderTemplate: 'cart-details-model',
2387        walletHolder: '.wallet-holder',
2388        walletAmountUsed: '#wallet-amount-used',
2389        removeOrder: '.remove_order'
2390    };
2391
2392    cartMethods.addToCart = function (details, callback) {
2393        cartPrivateMethods.addToCart(details, callback);
2394    };
2395
2396    cartPrivateMethods.cartCount = function (minify) {
2397        onSuccess = function (cart) {
2398            $(cartPrivateMethods.controls.headerCartSection).find('.cartcount').html(cart.totalItems);
2399
2400            // Adding and updating count for floating cart view
2401                if (cart.totalItems > 0) {
2402                    var itemLabel = cart.totalItems > 1 ? "Items" : "Item";
2403                    //$('.header-action-list').addClass('hide');
2404                    $('.cart-notification-sticky').removeClass('hide');
2405                    $('#cart-notification-sticky-btn').html(`<span class="itemscount">${cart.totalItems} ${itemLabel}</span>
2406            <span>in cart</span>`);
2407                    if (cart && cart.cartItems && cart.cartItems.length > 0 && cart.cartItems[0].productImage && cart.cartItems[0].productImage !== "")
2408                        $('#cart-notification-sticky-img').attr('src', cart.cartItems[0].productImage);
2409                    // cart.totalItems + itmes in cart
2410                }
2411                else {
2412                    $('.header-action-list').removeClass('hide');
2413                    $('.cart-notification-sticky').addClass('hide');
2414                }
2415
2416            if (minify === 0) {
2417                cartPrivateMethods.properties.template = cartPrivateMethods.properties.template === '' ? document.getElementById(cartPrivateMethods.controls.cartHeaderTemplate).innerHTML : cartPrivateMethods.properties.template;
2418                var template = Handlebars.compile(cartPrivateMethods.properties.template);
2419                var compiledTemplate = template(cart);
2420                $(cartPrivateMethods.controls.headerCartSection).find('.Carttoggelwrap').html(compiledTemplate);
2421
2422            }
2423            cartPrivateMethods.events.initialize();
2424        };
2425
2426        onError = function (data) {
2427
2428        };
2429        master.ajax.JSONRequest(cartMethods.url.cartCount + (minify === 0 ? '/0' : ''), 'GET', {}, onSuccess, onError);
2430
2431    };
2432
2433    cartPrivateMethods.registerHandlebarHelpers = function (data) {
2434
2435        Handlebars.registerHelper("showRemainingItems", function (remainingItems, options) {
2436            if (remainingItems == 0) {
2437                return options.inverse(this);
2438            }
2439            else {
2440                return options.fn(this);
2441            }
2442        });
2443
2444        Handlebars.registerHelper("isThereAnyItemsInCart", function (cartCount, options) {
2445            if (cartCount == 0) {
2446                return options.inverse(this);
2447            }
2448            else {
2449                return options.fn(this);
2450            }
2451        });
2452    };
2453
2454    cartMethods.updateCartCount = function (count) {
2455        var ccount = '';
2456        if (count >= 0) {
2457            ccount = '' + count;
2458        }
2459        $(cartPrivateMethods.controls.cartcount).html(ccount);
2460
2461    };
2462
2463    cartMethods.updateCartSummary = function () {
2464        onSuccess = function (data) {
2465            if (data) {
2466                // data.priceLabels[0].label
2467                if (data.cart.length < 1 && data.priceLabels.length < 1) {
2468                    window.location.reload(true);
2469                    return;
2470                }
2471                else if (data.priceLabels) {
2472                    $.each(data.priceLabels, function (i, val) {
2473                        $('ul.order-summery_list li').each(function () {
2474                            if ($(this).find('div').eq(0).html() == val.label)
2475                                $(this).find('div').eq(1).html(val.value);
2476
2477                        });
2478                        if ($('div.orderSummoryTotal') && val.label == 'Total')
2479                            $('div.orderSummoryTotal').find('div').eq(1).html(val.value);
2480                    });
2481                }
2482                // 
2483                if (data.cart) {
2484                    $.each(data.cart, function (i, val) {
2485                        var objitemprice = $('#cartitemsellingprice_' + val.id);
2486                        if (objitemprice) {
2487                            var totalitemprice = val.cart_sales_price * val.cart_order_qty;
2488                            var pricehtml = cart.properties.currencySymbol + ' ' + val.cart_sales_price + ' x ' + val.cart_order_qty + ' = ' + cart.properties.currencySymbol + ' ' + totalitemprice.toFixed(2) + '';
2489                            $(objitemprice).find('span.product-price_discount').html(pricehtml);
2490                        }
2491                    });
2492                }
2493            }
2494        };
2495
2496        onError = function (data) {
2497            //console.log(data);
2498        };
2499        master.ajax.JSONRequest(cartMethods.url.cartSummary, 'GET', {}, onSuccess, onError);
2500    };
2501
2502    cartPrivateMethods.changeDelivery = function (self) {
2503        var details = {
2504            cart_product_id: self.data('productid'),
2505            cart_group_id: self.data('groupid'),
2506            cart_order_qty: parseInt($("#product-qty-" + self.data('productid') + "-" + self.data('groupid')).val()),
2507            cart_branch_id: self.data('brid'),
2508            branch_type_id: self.data('brtypeid'),
2509            cart_id: self.data('id')
2510        };
2511
2512        onSuccess = function (result) {
2513            window.location.reload(true);
2514        };
2515
2516        onError = function (data) {
2517            //console.log(data);
2518        };
2519        master.ajax.JSONRequest(cartMethods.url.changeDelivery, 'POST', details, onSuccess, onError);
2520
2521    };
2522
2523    cartPrivateMethods.prepareModelAndAddToCart = function ($btn) {
2524        // 1. UI feedback
2525        $btn.addClass('processing');
2526        const $item = $btn.closest('.catitems');
2527        $item.find('.right-column').children().hide();
2528        $item.find('.left-column').children().show();
2529        $item.find('.tocart').hide();
2530        $item.find('.incart').show();
2531
2532        // 2. Resolve quantity
2533        const productId = $btn.data('productid');
2534        const groupId = $btn.data('groupid');
2535        let $qtyInput = $btn.closest('.form-qty-block').find('.form-qty');
2536        if (!$qtyInput.length) {
2537            $qtyInput = $(`#product-qty-${productId}-${groupId}`);
2538        }
2539        let qty = parseInt($qtyInput.val(), 10) || 1;
2540        $qtyInput.val(qty);
2541
2542        // 3. Build details and delegate to addToCart
2543        const details = {
2544            cart_product_id: productId,
2545            cart_group_id: groupId,
2546            cart_order_qty: qty,
2547            cart_branch_id: $btn.data('brid'),
2548            branch_type_id: $btn.data('brtypeid')
2549        };
2550
2551        cartPrivateMethods.addToCart(details);
2552    };
2553
2554
2555    cartPrivateMethods.addToCart = function (details, callback) {
2556        // Success handler
2557        const onSuccess = result => {
2558            // Always clear any “processing” state
2559            $('.processing').removeClass('processing');
2560
2561            // If result is invalid or indicates failure, log and stop
2562            if (!result || result === -1) {
2563                //console.warn('Add to cart failed or returned invalid result:', result);
2564                return;
2565            }
2566
2567            // GA4 ecommerce: fire only once the add is confirmed server-side
2568            if (typeof gtag === 'function') {
2569                gtag('event', 'add_to_cart', {
2570                    currency: 'INR',
2571                    items: [{
2572                        item_id: String(details.cart_product_id),
2573                        item_group_id: String(details.cart_group_id),
2574                        quantity: details.cart_order_qty || 1
2575                    }]
2576                });
2577            }
2578
2579            // 1. Update internal cart model
2580            cartMethods.properties.cartItems.items.push({
2581                id: result.itemid,
2582                groupId: result.grp,
2583                quantity: 1
2584            });
2585
2586            // 2. Ensure quantity >= 1
2587            const item = cartMethods.properties.cartItems.items
2588                .find(i => i.id === result.itemid && i.groupId === result.grp);
2589            if (item && item.quantity <= 0) {
2590                item.quantity = 1;
2591            }
2592
2593            // 3. Refresh UI
2594            cartMethods.updateCartButton();
2595            cartPrivateMethods.cartCount();
2596            if (cartMethods.properties.isCartPage) {
2597                cartMethods.updateCartSummary();
2598            }
2599
2600            // 4. Invoke optional callback (e.g., remove from wishlist)
2601            if (typeof callback === 'function') {
2602                callback(details.cart_product_id, details.cart_group_id, false);
2603            }
2604
2605            // 5. Show mini-cart feedback
2606            cartPrivateMethods.events.showCart();
2607            setTimeout(cartPrivateMethods.events.hideCart, 3000);
2608        };
2609
2610        // Error handler
2611        const onError = err => {
2612            //console.error('Error adding to cart:', err);
2613            // Cleanup and UI rollback
2614            $('.processing').removeClass('processing');
2615            cartMethods.updateCartButton();
2616        };
2617
2618        // Fire the AJAX request
2619        master.ajax.JSONRequest(
2620            cartMethods.url.addToCart,
2621            'POST',
2622            details,
2623            onSuccess,
2624            onError
2625        );
2626    };
2627
2628
2629    cartPrivateMethods.updateQuantity = function ($btn) {
2630        // 1. Mark processing state
2631        $btn.addClass('processing');
2632
2633        // 2. Resolve IDs and quantity input
2634        const productId = $btn.data('productid');
2635        const groupId = $btn.data('groupid');
2636        let $input = $btn.closest('.form-qty-block').find('.form-qty');
2637        if (!$input.length) {
2638            $input = $(`#product-qty-${productId}-${groupId}`);
2639        }
2640
2641        // 3. Parse and clamp quantity
2642        let qty = parseInt($input.val(), 10);
2643        if (isNaN(qty) || qty < 0) {
2644            qty = 0;
2645        }
2646        const max = parseInt($input.attr('max'), 10) || Infinity;
2647
2648        // 4. Disable/enable controls based on max
2649        if (qty >= max) {
2650            if ($btn.hasClass('plus')) $btn.prop('disabled', true);
2651            $('#pr_limit_reached_err').show(); //$btn.siblings('.Error').show();
2652        }
2653        else {
2654            $btn.prop('disabled', false)
2655                .siblings('.plus').prop('disabled', false);
2656            //.siblings('.Error').hide();
2657            $('#pr_limit_reached_err').hide();
2658        }
2659
2660        // 5. Reflect clamped value back to input(s)
2661        const displayQty = Math.max(qty, 1);
2662        $input.val(displayQty);
2663        $(`.product-tile-qty-${productId}-${groupId}`).val(displayQty);
2664
2665        // 6. Prepare payload
2666        const details = {
2667            cart_product_id: productId,
2668            cart_order_qty: qty
2669        };
2670
2671        // 7. Success & error handlers
2672        const onSuccess = result => {
2673            $btn.removeClass('processing');
2674
2675            if (!result) {
2676                //console.warn('Quantity update failed');
2677                return;
2678            }
2679
2680            // If qty zero, remove item
2681            if (qty <= 0) {
2682                $btn.closest('div.product-card.cartItem').remove();
2683
2684                //fixing an issue that caused some UI issues while removing and adding products randomly in product card
2685            cartMethods.properties.cartItems.items = cartMethods.properties.cartItems.items.filter(function (item) {
2686                return item.id !== result.itemid;
2687            });
2688            }
2689
2690            // Update counts and UI
2691            cartPrivateMethods.cartCount();
2692            cartMethods.updateCartCount(result.cartCount);
2693            if (cartMethods.properties.isCartPage) {
2694                cartMethods.updateCartSummary();
2695            }
2696        };
2697
2698        const onError = err => {
2699            $btn.removeClass('processing');
2700            //console.error('Error updating quantity:', err);
2701        };
2702
2703        // 8. Fire AJAX
2704        master.ajax.JSONRequest(
2705            cartMethods.url.updateQuantity,
2706            'POST',
2707            details,
2708            onSuccess,
2709            onError
2710        );
2711    };
2712
2713
2714    cartPrivateMethods.updateCart = function () {
2715
2716        var mobile = $(cartPrivateMethods.controls.mobile).val();
2717        onSuccess = function (data) {
2718            cartPrivateMethods.cartCount();
2719            if (cartMethods.properties.isCartPage)
2720                cartMethods.updateCartSummary();
2721
2722        };
2723
2724        onError = function (data) {
2725            //console.log(data);
2726        };
2727        master.ajax.JSONRequest(cartMethods.url.updateCart, 'POST', { Mobile: mobile }, onSuccess, onError);
2728
2729    };
2730    cartPrivateMethods.deleteOrder = function (orderId) {
2731        var details = { OrderId: orderId };
2732        onSuccess = function (data) {
2733            $('.order-' + orderId).remove();
2734            if ($('.cartcheckoutlisting li').length <= 0) {
2735                window.location.href = '/';
2736                $('#btncontinuePay').addClass('disabled');
2737                return;
2738            }
2739        };
2740
2741        onError = function (data) {
2742            //console.log(data);
2743        };
2744
2745        master.ajax.JSONRequest(cartMethods.url.removeOrderGroup, 'POST', details, onSuccess, onError);
2746    };
2747    cartPrivateMethods.deleteCart = function (productId, isOutOfStock = false) {
2748        const details = { cart_product_id: productId };
2749
2750        // Success handler
2751        const onSuccess = response => {
2752            if (!response || response.status !== 'ok') {
2753                //console.warn('deleteCart did not succeed:', response);
2754                return;
2755            }
2756
2757            // 1. Remove the table row
2758            var removedId = response.data.product_id || productId;
2759            $(`#tr-product-${removedId}`).remove();
2760
2761            // 2. Update counts and summary
2762            cartPrivateMethods.cartCount();
2763            if (cartMethods.properties.isCartPage) {
2764                cartMethods.updateCartSummary();
2765            }
2766
2767            // 3. Handle out-of-stock UI
2768            if (isOutOfStock) {
2769                $(`.out-of-stock-block-${productId}`).remove();
2770
2771                // If no more out-of-stock tiles, reload to re-render
2772                if (!$(`${cartPrivateMethods.controls.outOfStockTile}`).length) {
2773                    return window.location.reload(true);
2774                }
2775            }
2776
2777            // 4. Conditionally hide empty sections
2778            const sections = [
2779                { selector: '.courier-items li', wrap: '.courier_Delivery_wrap' },
2780                { selector: '.quik-items li', wrap: '.Quick_Delivery_wrap' },
2781                { selector: '.multi-listing-items li', wrap: '.multi-listing-items-wrap' }
2782            ];
2783
2784            sections.forEach(({ selector, wrap }) => {
2785                if (!$(selector).length) {
2786                    $(wrap).addClass('hide');
2787                }
2788            });
2789            //hide the Remove unavailable buttons and show the review to checkout button if the last
2790            //unavailable item is removed manually
2791            if ($('.cart-listing > .product_outofstock').length === 0) {
2792                $('.checkout_btn').removeClass('hide'); //this should always be first
2793                $('.auto_remove_items').addClass('hide'); //this should always be second as both buttons has checkout_btn class in it
2794            }
2795          
2796        };
2797
2798        // Error handler
2799        const onError = err => {
2800            //console.error('Error deleting cart item:', err);
2801        };
2802
2803        // Fire the AJAX request
2804        master.ajax.JSONRequest(
2805            cartMethods.url.deleteCart,
2806            'POST',
2807            details,
2808            onSuccess,
2809            onError
2810        );
2811    };
2812
2813
2814    cartPrivateMethods.clearCart = function () {
2815        // 1. Confirm action
2816        if (!window.confirm('Are you sure you want to clear all items in your cart?')) {
2817            return;
2818        }
2819
2820        // 2. Success & error handlers, scoped as constants
2821        const onSuccess = response => {
2822            // Update counts & UI
2823            cartPrivateMethods.cartCount();
2824            if (cartMethods.properties.isCartPage) {
2825                cartMethods.updateCartSummary();
2826            }
2827            // Reload to show empty cart
2828            window.location.reload(true);
2829        };
2830
2831        const onError = error => {
2832            //console.error('Failed to clear cart:', error);
2833            // Optional: show user-facing error message here
2834        };
2835
2836        // 3. Fire AJAX request
2837        master.ajax.JSONRequest(
2838            cartMethods.url.clearCart,
2839            'POST',
2840            {},
2841            onSuccess,
2842            onError
2843        );
2844    };
2845
2846    //cartPrivateMethods.applyCoupon = function ($btn) {
2847    //    // 1. Visual feedback
2848    //    $btn.addClass('processing');
2849
2850    //    // 2. Determine action & source input
2851    //    const isInputClick = $btn.is('input');
2852    //    const currentText = $btn.text().trim();
2853    //    //const isRemoving = !isInputClick && currentText === 'Remove';
2854    //    const rawCouponInput = isInputClick
2855    //        ? $('#CouponCode')
2856    //        : $('#txtCoupon');
2857    //    const couponCode = rawCouponInput.val().trim();
2858
2859    //    // 3. Validation
2860    //    if (!isInputClick && !couponCode) {
2861    //        alert('Invalid coupon code. Please enter a valid coupon.');
2862    //        $btn.removeClass('processing');
2863    //        return;
2864    //    }
2865    //    // Mirror code between inputs
2866    //    if (!isInputClick) {
2867    //        $('#CouponCode').val(couponCode);
2868    //    } else {
2869    //        $('#txtCoupon').val(couponCode);
2870    //    }
2871
2872    //    // 4. Prepare payload
2873    //    const useWallet = $('#frmSubmitCheckout')
2874    //        .find('.walletrow input:checked')
2875    //        .length > 0;
2876    //    const details = {
2877    //        OrderId: $('#OrderId').val(),
2878    //        CouponCode: couponCode,
2879    //        UseWallet: useWallet
2880    //    };
2881
2882    //    // 5. Handlers
2883    //    const onSuccess = response => {
2884    //        const labels = response?.data?.labels;
2885    //        if (Array.isArray(labels) && labels.length) {
2886    //            // Clear old summary
2887    //            $('.order-summery_wrap ul').empty();
2888
2889    //            let netPayment = 0;
2890    //            let totalDiscount = 0;
2891
2892    //            labels.forEach(({ label, value }) => {
2893    //                const formatted = isNaN(value) ? value : Number(value).toFixed(2);
2894
2895    //                if (label === 'Net Amount Payable') {
2896    //                    netPayment = formatted;
2897    //                    $('.grand-total').html(
2898    //                        ` <div class="order-summery_label">Grand Total</div><div class="order-summery_value">${formatted}</div>`
2899    //                    );
2900    //                } else {
2901    //                    $('.order-summery_wrap ul').prepend(
2902    //                        ` <li class="cost-prod"> <div class="order-summery_label">${label}</div>` +
2903    //                        ` <div class="order-summery_value">${formatted}</div></li>`
2904    //                    );
2905    //                }
2906    //                if (label === 'Discount') totalDiscount = formatted;
2907    //            });
2908
2909    //            $('#frmSubmitCheckout input#NetAmount').val(netPayment);
2910    //            $('.paymentoptionsrow').attr('total', netPayment);
2911
2912    //            if (!isInputClick) {
2913    //                const $couponRow = $('#frmSubmitCheckout .have-acoupon-wrap');
2914    //                $couponRow.find('label').text(
2915    //                    isRemoving ? 'Have Coupon? ' : 'Coupon applied'
2916    //                );
2917    //                $couponRow.find('#txtCoupon')
2918    //                    .prop('disabled', !isRemoving);
2919    //                $btn.text(isRemoving ? 'Apply' : 'Remove');
2920
2921    //                rawCouponInput.val(isRemoving ? '' : couponCode);
2922    //                master.showResult(
2923    //                    `Coupon ${isRemoving ? 'removed' : 'applied'} successfully!` +
2924    //                    (totalDiscount > 0
2925    //                        ? `<br/>Total Discount: ${master.properties.currency} ${totalDiscount}`
2926    //                        : ''),
2927    //                    `Coupon ${isRemoving ? 'Removed' : 'Applied'}`,
2928    //                    true
2929    //                );
2930    //            }
2931    //        } else {
2932    //            const errMsg = response?.result?.error?.msg || 'An error occurred.';
2933    //            master.showResult(errMsg, 'Failure', false);
2934    //        }
2935
2936    //        // 6. Cleanup
2937    //        $btn.removeClass('processing');
2938    //    };
2939
2940    //    const onError = err => {
2941    //        console.error('applyCoupon error', err);
2942    //        $btn.removeClass('processing');
2943    //    };
2944
2945    //    // 7. Send request
2946    //    master.ajax.JSONRequest(
2947    //        cartMethods.url.addCoupon,
2948    //        'POST',
2949    //        details,
2950    //        onSuccess,
2951    //        onError
2952    //    );
2953    //};
2954
2955
2956    // Reflects which coupon (if any) is currently applied back onto the coupon-selector cards:
2957    // marks the applied one, restores the rest to their original applicable/disabled state.
2958    cartPrivateMethods.updateCouponSelector = function (appliedCode) {
2959        $('.coupon-item').each(function () {
2960            const $item = $(this);
2961            const $btn = $item.find('.btn-select-coupon');
2962            const isApplied = appliedCode && $item.data('code') === appliedCode;
2963            const isApplicable = String($item.data('applicable')) !== 'false';
2964
2965            $item.toggleClass('applied', !!isApplied);
2966            $btn.text(isApplied ? 'Remove' : 'Apply')
2967                .prop('disabled', isApplied ? false : !isApplicable);
2968        });
2969    };
2970
2971    // Shows/updates/hides the "Add ₹X more for free delivery" banner under "Your Orders".
2972    cartPrivateMethods.updateFreeDeliveryMsg = function (amountForFreeDelivery) {
2973        const $msg = $('#freeDeliveryMsg');
2974        if (amountForFreeDelivery > 0) {
2975            const formatted = Number(amountForFreeDelivery).toFixed(2);
2976            const text = `Add ${master.properties.currency} ${formatted} more to get <strong>FREE delivery!</strong>`;
2977            if ($msg.length) {
2978                $msg.html(text).show();
2979            } else {
2980                $('.checkout-listing_wrap .sub_title').after(`<div class="free-delivery-msg" id="freeDeliveryMsg">${text}</div>`);
2981            }
2982        } else {
2983            $msg.hide();
2984        }
2985    };
2986
2987    cartPrivateMethods.escapeHtml = function (str) {
2988        return $('<div>').text(str == null ? '' : str).html();
2989    };
2990
2991    // Renders the fetched coupon catalog into the #couponPopover list. Each item reuses the
2992    // .btnapplycoupon/.coupon-item wiring that applyCoupon()/updateCouponSelector() already use,
2993    // so applying/removing from the popover works the same way as the manual code box.
2994    cartPrivateMethods.renderAvailableCoupons = function (coupons) {
2995        const $list = $('#couponPopover .coupon-list');
2996        const appliedCode = $('#txtCoupon').val();
2997
2998        if (!Array.isArray(coupons) || !coupons.length) {
2999            $list.html('<li class="coupon-list_empty">No coupons available right now.</li>');
3000            return;
3001        }
3002
3003        const html = coupons.map(c => {
3004            const isApplied = appliedCode && appliedCode === c.coupon_code;
3005            const isApplicable = c.is_applicable !== false;
3006            const disabledAttr = (isApplied || isApplicable) ? '' : 'disabled';
3007
3008            return `<li class="coupon-item ${isApplicable ? '' : 'disabled'} ${isApplied ? 'applied' : ''}" data-code="${cartPrivateMethods.escapeHtml(c.coupon_code)}" data-applicable="${isApplicable}">` +
3009                `<div class="coupon-item_info">` +
3010                `<div class="coupon-item_title">${cartPrivateMethods.escapeHtml(c.title)}</div>` +
3011                (c.description ? `<div class="coupon-item_desc">${cartPrivateMethods.escapeHtml(c.description)}</div>` : '') +
3012                (!isApplicable && c.reason ? `<div class="coupon-item_reason">${cartPrivateMethods.escapeHtml(c.reason)}</div>` : '') +
3013                `</div>` +
3014                `<button type="button" class="btn btn-outline-primary btn-sm btn-select-coupon btnapplycoupon" ${disabledAttr}>${isApplied ? 'Remove' : 'Apply'}</button>` +
3015                `</li>`;
3016        }).join('');
3017
3018        $list.html(html);
3019        cartMethods.rebindEvents(); // newly injected .btnapplycoupon buttons need their click handler (re)bound
3020    };
3021
3022    cartPrivateMethods.loadAvailableCoupons = function () {
3023        const $popover = $('#couponPopover');
3024        const $list = $popover.find('.coupon-list');
3025        $list.html('<li class="coupon-list_loading">Loading coupons...</li>');
3026
3027        const onSuccess = response => {
3028            cartPrivateMethods.renderAvailableCoupons(response && response.data ? response.data : []);
3029        };
3030        const onError = () => {
3031            $list.html('<li class="coupon-list_empty">No coupons available right now.</li>');
3032        };
3033
3034        master.ajax.JSONRequest(
3035            cartMethods.url.availableCoupons + $('#OrderId').val(),
3036            'GET',
3037            {},
3038            onSuccess,
3039            onError
3040        );
3041    };
3042
3043    cartPrivateMethods.applyCoupon = function ($btn) {
3044        $btn.addClass('processing');
3045
3046        const isInputClick = $btn.is('input');
3047        const $couponItem = $btn.closest('.coupon-item');
3048        const cardCode = $couponItem.length ? $couponItem.data('code') : null;
3049
3050        const rawCouponInput = isInputClick ? $('#CouponCode') : $('#txtCoupon');
3051        const couponCode = cardCode || rawCouponInput.val().trim();
3052
3053        if (!couponCode && !isInputClick) {
3054            alert('Invalid coupon code. Please enter a valid coupon.');
3055            $btn.removeClass('processing');
3056            return;
3057        }
3058
3059        $('#CouponCode, #txtCoupon').val(couponCode); // Mirror inputs
3060
3061        const useWallet = $('#frmSubmitCheckout').find('.walletrow input:checked').length > 0;
3062        const details = {
3063            OrderId: $('#OrderId').val(),
3064            CouponCode: couponCode,
3065            UseWallet: useWallet
3066        };
3067
3068        const onSuccess = response => {
3069            const labels = (response && response.data ? response.data.labels : null);
3070            if (Array.isArray(labels) && labels.length) {
3071                $('.order-summery_wrap ul').empty();
3072                let netPayment = 0, totalDiscount = 0;
3073
3074                labels.forEach(({ label, value }) => {
3075                    if (value) {
3076                        const formatted = isNaN(value) ? value : Number(value).toFixed(2);
3077                        if (label === 'Net Amount Payable') {
3078                            netPayment = formatted;
3079                            $('.grand-total').html(
3080                                `<div class="order-summery_label">Grand Total</div><div class="order-summery_value">${formatted}</div>`
3081                            );
3082                            $('.contunuPay_btn').html(`Pay Now ${formatted}`);
3083                        }
3084                        else {
3085                            $('.order-summery_wrap ul').prepend(
3086                                `<li class="cost-prod"><div class="order-summery_label">${label}</div>` +
3087                                `<div class="order-summery_value">${formatted}</div></li>`
3088                            );
3089                        }
3090                        if (label === 'Discount') totalDiscount = formatted;
3091                    }
3092                 
3093                });
3094
3095                $('#frmSubmitCheckout input#NetAmount').val(netPayment);
3096                $('.paymentoptionsrow').attr('total', netPayment);
3097                var attr = netPayment.replace(/[^0-9.]/g, '');
3098                    
3099                if (attr == "0") {
3100                    $('#btncontinuePay').removeClass("hide");
3101                    $('.contunuPay_btn').addClass("hide");
3102                }
3103                else {
3104                    $('#btncontinuePay').addClass("hide");
3105                    $('.contunuPay_btn').removeClass("hide"); 
3106                }
3107                
3108
3109                cartPrivateMethods.updateFreeDeliveryMsg(response.data.amount_for_free_delivery);
3110
3111                if (!isInputClick) {
3112                    if ($couponItem.length) {
3113                        cartPrivateMethods.updateCouponSelector(couponCode);
3114                    }
3115                    else {
3116                        $('#frmSubmitCheckout .coupon-label-text').text('Coupon applied');
3117                        $('#txtCoupon').prop('disabled', true);
3118                        $btn.text('Remove');
3119                    }
3120
3121                    master.showResult(
3122                        `Coupon applied successfully!` +
3123                        (totalDiscount > 0 ? `<br/>Total Discount: ${master.properties.currency} ${totalDiscount}` : ''),
3124                        'Coupon Applied',
3125                        true
3126                    );
3127                }
3128            }
3129            else {
3130                const errMsg = (response && response.result && response.result.error ? response.result.error.msg : 'An error occurred.');
3131                master.showResult(errMsg, 'Failure', false);
3132                if ($('#chkcheckoutusewallet').is(':checked')) {
3133                    $('#chkcheckoutusewallet').prop('checked', false);
3134                }
3135            }
3136
3137            $btn.removeClass('processing');
3138        };
3139
3140        const onError = err => {
3141            //console.error('applyCoupon error', err);
3142            $btn.removeClass('processing');
3143            if ($('#chkcheckoutusewallet').is(':checked')) {
3144                $('#chkcheckoutusewallet').prop('checked', false);
3145            }
3146        };
3147
3148        master.ajax.JSONRequest(
3149            cartMethods.url.addCoupon,
3150            'POST',
3151            details,
3152            onSuccess,
3153            onError
3154        );
3155    };
3156
3157    cartPrivateMethods.removeCoupon = function ($btn) {
3158        $btn.addClass('processing');
3159        const rawCouponInput =  $('#txtCoupon');
3160        const couponCode = rawCouponInput.val().trim();
3161        const details = {
3162            OrderId: $('#OrderId').val(),
3163            CouponCode: couponCode,
3164            UseWallet: $('#frmSubmitCheckout').find('.walletrow input:checked').length > 0
3165        };
3166
3167        const onSuccess = response => {
3168            const labels = (response && response.data ? response.data.labels : null);
3169
3170            $('.order-summery_wrap ul').empty();
3171            $('#frmSubmitCheckout input#NetAmount').val('');
3172            $('.paymentoptionsrow').removeAttr('total');
3173            $('.grand-total').empty();
3174            if (labels && Array.isArray(labels)) {
3175                labels.forEach(({ label, value }) => {
3176                    const formatted = isNaN(value) ? value : Number(value).toFixed(2);
3177                    if (label === 'Net Amount Payable') {
3178                        netPayment = formatted;
3179                        $('.grand-total').html(
3180                            `<div class="order-summery_label">Grand Total</div><div class="order-summery_value">${formatted}</div>`
3181                        );
3182                    }
3183                    else {
3184                        $('.order-summery_wrap ul').prepend(
3185                            `<li class="cost-prod"><div class="order-summery_label">${label}</div>` +
3186                            `<div class="order-summery_value">${formatted}</div></li>`
3187                        );
3188                    }
3189                    if (label === 'Discount') totalDiscount = formatted;
3190                });
3191            }
3192            $('#txtCoupon, #CouponCode').val('').prop('disabled', false);
3193            $('#frmSubmitCheckout .coupon-label-text').text('Have Coupon?');
3194            $btn.text('Apply');
3195            cartPrivateMethods.updateCouponSelector(null);
3196            cartPrivateMethods.updateFreeDeliveryMsg(response && response.data ? response.data.amount_for_free_delivery : 0);
3197
3198            master.showResult('Coupon removed successfully!', 'Coupon Removed', true);
3199            $btn.removeClass('processing');
3200        };
3201
3202        const onError = err => {
3203            //console.error('removeCoupon error', err);
3204            $btn.removeClass('processing');
3205
3206        };
3207
3208        master.ajax.JSONRequest(
3209            cartMethods.url.removeCoupon,
3210            'POST',
3211            details,
3212            onSuccess,
3213            onError
3214        );
3215    };
3216
3217    cartPrivateMethods.validateCartSubmit = function (obj, e) {
3218        if ($('.cart-listing').find('.outofstock').length > 0) {
3219            master.showResult("Your cart contains out of stock items. Please remove these items from cart to proceed.", "Failure!", false);
3220            e.preventDefault();
3221            $(this).find('button[type=submit]').prop('disabled', false);
3222            return false;
3223        }
3224        if ($('#prescriptionupload') && prescription && !prescription.validate()) {
3225            e.preventDefault();
3226            alert('Your cart contains medicine items that require a prescription. Please upload a prescription or remove those items to proceed.');
3227            return false;
3228        }
3229        return true;
3230    };
3231    cartPrivateMethods.loadPayment = function (obj, e) {
3232        var attr = ''; // $('.paymentoptionsrow').attr('total').replace(/[^0-9.]/g, '');
3233        $('#btncontinuePay').addClass('processing');
3234        if ($('.paymentoptionsrow').attr('total'))
3235            attr = $('.paymentoptionsrow').attr('total').replace(/[^0-9.]/g, '');
3236
3237        if (typeof attr !== 'undefined' && attr !== false && attr === "0") {
3238            //e.preventDefault();
3239            $('#frmSubmitCheckout').submit();
3240            return false;
3241        }
3242
3243        $('#dvpaymentmodes').show(); $('#dvcheckoutinfo').hide();
3244        $('.titlewrap title_group').html('<h2>Payment</h2>');
3245
3246        $('#payment-progress').addClass('odr_processing');
3247
3248        $('.have-acoupon-wrap').hide();
3249        $('.couponrow').hide();
3250        $('.haveAcouponWrap').hide();
3251        $('#btncontinuePay').hide();
3252        if ($("#payment-request").length > 0) {
3253            var checkoutvals = cartPrivateMethods.getCheckoutVal($('#frmSubmitCheckout'));
3254            master.getPaymentPage(checkoutvals, 0, true);
3255        }
3256
3257        return false;
3258    };
3259
3260    cartPrivateMethods.loadOnlinePayment = function (obj, e) {
3261        if ($('#frmSubmitCheckout').attr('cancheckout') != 'True') {
3262            e.preventDefault();
3263            $(".submitonlinepaymentWrap").removeClass("processing");
3264            alert('Sorry, we are not started accepting orders. Please check back soon.');
3265            return false;
3266        }
3267        if (e)
3268            e.preventDefault();
3269        var checkoutvals = cartPrivateMethods.getCheckoutVal($('#frmSubmitCheckout'));
3270        $('#frmSubmitCheckout').addClass('processing');
3271        master.getPaymentPage(checkoutvals);
3272        return false;
3273
3274    };
3275    cartPrivateMethods.continuePOD = function (obj, e) {
3276        if ($('#frmSubmitCheckout').attr('cancheckout') != 'True') {
3277            e.preventDefault();
3278            $(".submitonlinepaymentWrap").removeClass("processing");
3279            alert('Sorry, we are not started accepting orders. Please check back soon.');
3280            return false;
3281        }
3282        $('#rdPaymentMethod_0').prop('checked', true);
3283        return true;
3284
3285    };
3286    cartPrivateMethods.getCheckoutVal = function (obj) {
3287        var Checkout = {
3288            PaymentMethod: 2,//$(frm).find('#PaymentMethod').val(),
3289            TimeSlote: $('#TimeSlote').val(),
3290            OrderId: $('#OrderId').val(),
3291            CustomerId: $('#CustomerId').val(),
3292            OrderNum: $('#OrderNum').val(),
3293            NetAmount: $('#NetAmount').val(),
3294            UseWallet: $('#chkcheckoutusewallet').is(":checked"),
3295            CouponCode: $('#CouponCode').val(),
3296            OrderGroupId: $('#OrderGroupId').val()
3297        };
3298        return Checkout;
3299    };
3300
3301    cartPrivateMethods.validateCheckoutSubmit = function (obj, e) {
3302        if ($(obj).attr('cancheckout') != 'True') {
3303            e.preventDefault();
3304            alert('Sorry, we are not started accepting orders. Please check back soon.');
3305            return false;
3306        }
3307
3308        //if ($(obj).find('.paymentoptionsrow').is(":visible")) {
3309        if ($("#rdPaymentMethod_0").is(":checked")) {
3310            return true; //confirm("You have selected to Pay On Delivery. Are you sure to proceed?");
3311        } // 
3312        else if ($("#rdPaymentMethod_1").is(":checked")) {
3313            //$('#frmSubmitCheckout').attr("action", "/checkout")
3314            e.preventDefault();
3315            var checkoutvals = cartPrivateMethods.getCheckoutVal(this);
3316            master.getPaymentPage(checkoutvals);
3317            return false;
3318        }
3319        else if ($('.paymentoptionsrow').attr('total') && $('.paymentoptionsrow').attr('total').replace(/[^0-9.]/g, '') === "0") {
3320            return true;
3321        }
3322        else {
3323            e.preventDefault();
3324            //alert("Please select a Payment Method to proceed");
3325            return false;
3326        }
3327        //}
3328        //else {
3329        //    $('#frmSubmitCheckout').attr("action", "/Checkout/SubmitOrder");
3330        //    return true;
3331        //}
3332
3333    };
3334
3335    cartMethods.updateCartButton = function () {
3336        if (!master.properties.hasLoadedCartAndWishlist && !master.properties.isLoadingCartAndWishlist) {
3337            setTimeout(cartMethods.updateCartButton, 15000);
3338            return;
3339        }
3340        $.each(cartMethods.properties.cartItems.items, function (index, item) {
3341            $(".addunitWrap-" + item.id + "-" + item.groupId).addClass('form-qty-full');
3342            $(".product-tile-qty-" + item.id + "-" + item.groupId).val(item.quantity);
3343            $(".product-tile-plus-" + item.id + "-" + item.groupId).removeClass('btn-add').html('+');
3344            $(".product-tile-minus-" + item.id + "-" + item.groupId).removeClass('hide');
3345            $(".product-tile-qty-" + item.id + "-" + item.groupId).removeClass('hide');
3346        });
3347    };
3348
3349    cartPrivateMethods.events.onAdd = function (self) {
3350        if (self.hasClass('open-login-modal')) { //check if the user is logged in or not.
3351
3352            $("#login-modal").modal("show");
3353            setTimeout(function () {
3354                $("#txt-mobile").focus();
3355            }, 500);
3356            return; //If not logged in break the execution and show login modal.
3357
3358        }
3359        //If logged in, Continue execution.
3360
3361        // Get current quantity values
3362        var qtyblock = self.closest('.form-qty-block');
3363        var qty = qtyblock.find('.form-qty');
3364        var val = parseInt(qty.val()) || 0;
3365        var max = parseInt(qty.attr('max')) || 0;
3366        var min = parseInt(qty.attr('min')) || 0;
3367        var step = parseInt(qty.attr('step')) || 0;
3368
3369        var minusbtn = qtyblock.find('.btn-minus');
3370        var plusbtn = qtyblock.find('.btn-plus');
3371        var formqty = qtyblock.find('.form-qty');
3372
3373        var cart_product_id = self.data('productid');
3374        var cart_group_id = self.data('groupid');
3375
3376        // Change the value if plus or minus
3377        if (self.is('.btn-plus')) {
3378            if (max && (max <= val)) {
3379                qty.val(max);
3380            }
3381            else {
3382                qty.val(val + step);
3383            }
3384            if (minusbtn.is(':hidden')) {
3385                $('input.product-tile-qty-' + cart_product_id + '-' + cart_group_id).val(min + step);
3386                $('.product-tile-plus-' + cart_product_id + '-' + cart_group_id).removeClass('btn-add').html('+');
3387                $('.product-tile-minus-' + cart_product_id + '-' + cart_group_id).removeClass('hide');
3388                $('input.product-tile-qty-' + cart_product_id + '-' + cart_group_id).removeClass('hide');
3389                $("div.form-qty-block").find("[data-productid='" + cart_product_id + "']").addClass('form-qty-full');
3390
3391                //qty.val(min + step);
3392                cartPrivateMethods.prepareModelAndAddToCart(self);
3393                //plusbtn.removeClass('btn-add').html('+');
3394                //minusbtn.removeClass('hide');
3395                //formqty.removeClass('hide');
3396                //qtyblock.addClass('form-qty-full');
3397            }
3398            else {
3399                cartPrivateMethods.updateQuantity(self, true);
3400                cartMethods.properties.cartItems.items.forEach(item => {
3401                    if (item.id === cart_product_id && item.groupId === cart_group_id) {
3402                        item.quantity += 1; // Increment quantity
3403                    }
3404                });
3405            }
3406        }
3407        else {
3408            if (val == (min + 1)) {
3409                $("div.form-qty-block").find("[data-productid='" + cart_product_id + "']").removeClass('form-qty-full');
3410                $('.product-tile-plus-' + cart_product_id + '-' + cart_group_id).addClass('btn-add').html('<span>Add</span>+');
3411                $('.product-tile-minus-' + cart_product_id + '-' + cart_group_id).addClass('hide');
3412                $('input.product-tile-qty-' + cart_product_id + '-' + cart_group_id).addClass('hide');
3413
3414                //qtyblock.removeClass('form-qty-full');
3415                //plusbtn.addClass('btn-add').html('<span>Add</span>+');
3416                //minusbtn.addClass('hide');
3417                //formqty.addClass('hide');
3418                qty.val(0);
3419            }
3420            else {
3421                qty.val(val - step);
3422                cartMethods.properties.cartItems.items.forEach(item => {
3423                    if (item.id === cart_product_id && item.groupId === cart_group_id) {
3424                        item.quantity -= 1; // decrement quantity
3425                    }
3426                });
3427            }
3428            cartPrivateMethods.updateQuantity(self, false);
3429        }
3430    };
3431
3432
3433    cartPrivateMethods.events.navigateToGroup = function (self) {
3434        var groupId = self.data('groupid');
3435        var groupName = self.data('groupname');
3436        window.location.href = '/groupitem/' + groupId + '/' + groupName;
3437    };
3438
3439    cartMethods.deleteItem = function (productId, wishListCallBack) {
3440        cartPrivateMethods.deleteCart(productId, false, wishListCallBack);
3441    };
3442
3443    cartPrivateMethods.events.showCart = function (self) {
3444        //Function shows the mini cart dropdown
3445        if (typeof gtag === 'function') {
3446            gtag('event', 'view_cart');
3447        }
3448        cartMethods.updateCartHtml();
3449        cartPrivateMethods.cartCount(0);
3450        //self.addClass('active');
3451        $('.Carttoggelwrap').slideDown();
3452        $('.Carttoggelwrap').addClass('active');
3453        $('#site-wrapper').addClass('Cart-visible');
3454        $('.TopMenuCategoriesTogel, .TopMenuCategories, .delivery_adress_togle, .delivery_adress_triger, .trigerprofile, .Profiletogle, .ShareTriger').removeClass('active');
3455        $(".delivery_adress_togle, .Profiletogle, .BookaSlotToggle, .Sharetogle .TopMenuCategories").hide();
3456        $('#site-wrapper').removeClass('menu-visible delivery_adress_visible profile-visible BookaSlot-visible');
3457
3458    };
3459
3460    cartPrivateMethods.events.hideCart = function (self) {
3461        $('.minicart').removeClass('open-minicart');
3462        $('.Carttoggelwrap').removeClass('active');
3463    };
3464    $('.close-cart').on("click", function (event) {
3465        cartPrivateMethods.events.hideCart();
3466    });
3467    cartMethods.updateCartHtml = function () {
3468        $(cartPrivateMethods.controls.headerCartSection).find('.Carttoggelwrap').html(`
3469        <div class="minicart-card">
3470			<div class="minicart-card_head">
3471				<h5>My cart</h5>
3472				<div class="close-minicart_icon">
3473					<a href="javascript:void(0)" class="close-minicart" role="button" aria-label="Close Cart">
3474						<i class="fa-regular fa-xmark" aria-hidden="true"></i>
3475					</a>
3476				</div>
3477			</div>
3478			<div class="minicart-card_body" style="overflow:hidden;">
3479				<div class="preloder">
3480                <span class="preloder_content">Loading...</span>
3481                <span class="loader_anim"></span>
3482                </div>
3483			</div>
3484		</div>
3485        `);
3486    }
3487
3488
3489    cartMethods.setTimeSlot = function (self, isDeselected) {
3490        var ordid = self.attr('ordid');
3491        var tslot = self.attr('tslot');
3492        var slotid = isDeselected ? -1 : self.attr('slotid');
3493        var slotdate = self.attr('slotdate');
3494        if (!isDeselected) {
3495            $('.BookaSlotTriger').html(tslot + "<i></i>");
3496            $('#delivery-label').removeClass("active");
3497            $('.BookaSlotTriger').css("background", "#fff2d9");
3498
3499        }
3500        else {
3501            $('.BookaSlotTriger').html("Book a Slot <i></i>");
3502            $('#delivery-label').addClass("active");
3503            $('.BookaSlotTriger').css("background", "#ffffff");
3504
3505        }
3506
3507        var obj = self;
3508        var useWallet = $('#chkcheckoutusewallet').prop('checked') ? 1 : 0;
3509        var details = { OrderId: ordid, SlotId: slotid, SlotDate: slotdate, UseWallet: useWallet };
3510        onSuccess = function (data) {
3511            if (data && data.result.status == 'ok') {
3512                $('#TimeSlote').val(tslot); $(obj).parent('ul').find('li').removeClass('active'); $(obj).addClass('active');
3513                $(obj).closest('.BookaSlotToggle').hide();
3514                $('#site-wrapper').removeClass('BookaSlot-visible');
3515                //for (var i = 1; i < data.result.data.orders.length; i++) {
3516                $.each(data.result.data.orders, function (key, value) {
3517                    if (value.order_id == ordid) {
3518                        $(obj).closest('div.ItemdeliveryInfoWrap').find('ul.orderingitems_itemInfo li').each(function () {
3519                            if ($(this).find('span').length > 1 && $(this).children('span').eq(0).html() == 'Delivery Charge :')
3520                                $(this).children('span').eq(1).html(value.style.find(o => o.label == 'Delivery charge').value);
3521                            else if ($(this).find('span').length > 1 && $(this).children('span').eq(0).html() == 'Order Amount :')
3522                                $(this).children('span').eq(1).html(value.style.find(o => o.label == 'Total').value);
3523                        });
3524                    }
3525                });
3526
3527
3528                cartMethods.updateActiveSlots(slotid);
3529                $('.orderSummoryTableItems ul li').remove();
3530                var totaldiscount = 0;
3531                var netpayment = 0;
3532                $.each(data.result.data.summary.style, function (key, value) {
3533                    if (value.label == 'Net Amount Payable') {
3534                        //$('#tblordersummary').prepend('<tr  class="order-total baboth cartval" style="border-top: 1px solid #ded7d7"><th>' + value.label + '</th><td>' + value.value + '</td></tr>');
3535                        $('.orderSummoryTotal span').remove();
3536                        netpayment = value.value;
3537                        $('.orderSummoryTotal').append('<span>Amount Payable</span><span>' + (isNaN(netpayment) ? netpayment : Number(netpayment).toFixed(2)) + '</span>');
3538                    }
3539                    else {
3540                        $('.orderSummoryTableItems ul').append('<li><span>' + value.label + '</span><span>' + (isNaN(value.value) ? value.value : Number(value.value).toFixed(2)) + '</span></li>');
3541                    }
3542
3543                    //else if (value.order == 1)
3544                    //    $('#tblordersummary').prepend('<tr class="cartval"><th><b>' + value.label + '</b></th><td><b>' + value.value + '</b></td></tr>');
3545                    //else
3546                    //    $('#tblordersummary').prepend('<tr class="cartval"><th>' + value.label + '</th><td>' + value.value + '</td></tr>');
3547                    if (value.label == 'Discount')
3548                        totaldiscount = value.value;
3549                });
3550                $('#frmSubmitCheckout').find('input[id="NetAmount"]').val(netpayment);
3551
3552            }
3553
3554
3555        };
3556
3557        onError = function (data) {
3558            //console.log(data);
3559        };
3560        master.ajax.JSONRequest(cartMethods.url.setSlot, 'POST', details, onSuccess, onError);
3561
3562    };
3563    cartMethods.updateActiveSlots = function (targetSlotId) {
3564        $('ul.time-slot li.time-slot-item.active').each(function () {
3565            var slotId = $(this).attr('slotid');
3566            //console.log(slotId, targetSlotId);
3567            // Check if the slotid does not match the targetSlotId
3568            if (slotId != targetSlotId) {
3569                // Remove the 'active' class
3570                $(this).removeClass('active');
3571            }
3572        });
3573    };
3574    cartMethods.OpenMiniCart = function () {
3575        $(".mycart_dropdown").addClass("active");
3576        $(".minicart").addClass("openminicart");
3577    };
3578    cartMethods.CloseMiniCart = function () {
3579        $(".minicart").removeClass("openminicart");
3580        $(".mycart_dropdown").removeClass("active");
3581    };
3582    cartMethods.initializePage = function () {
3583        cartPrivateMethods.events.initialize();
3584        cartPrivateMethods.registerHandlebarHelpers();
3585        cartPrivateMethods.cartCount();
3586    };
3587    // Rebind click handlers only, without re-fetching cart count or re-registering Handlebars
3588    // helpers. Use this after injecting new markup into the page (e.g. search-in-other-store
3589    // results) so add-to-cart etc. work on the new elements, without the redundant /cartcount
3590    // request and helper re-registration that cartMethods.initializePage() would also trigger.
3591    cartMethods.rebindEvents = function () {
3592        cartPrivateMethods.events.initialize();
3593    };
3594
3595    cartPrivateMethods.events.initialize = function () {
3596        var controls = cartPrivateMethods.controls;
3597
3598        $('input.changedelivery').unbind('click').on('click', function (e) {
3599            if ($(self).is(':checked')) { return false; }
3600            if (!confirm("Are you sure to change the delivery type?")) return false;
3601
3602            cartPrivateMethods.changeDelivery($(this));
3603        });
3604        $(controls.applycoupon).unbind('click').on('click', function (e) {
3605            e.preventDefault();
3606            // Checks this button's own text, not all .btnapplycoupon buttons on the page -
3607            // the coupon selector can render several Apply buttons at once.
3608            var isRemove = $(this).text().trim().toLowerCase() == 'remove';
3609            if (isRemove) {
3610                cartPrivateMethods.removeCoupon($(this));
3611
3612            }
3613            else {
3614                cartPrivateMethods.applyCoupon($(this));
3615
3616            }
3617            return false;
3618        });
3619
3620        $(controls.viewCoupons).unbind('click').on('click', function (e) {
3621            e.preventDefault();
3622            const $popover = $('#couponPopover');
3623            const wasHidden = $popover.hasClass('hide');
3624            $popover.toggleClass('hide');
3625            if (wasHidden) {
3626                cartPrivateMethods.loadAvailableCoupons(); // fetched only now, not on page load
3627            }
3628        });
3629
3630        $(controls.couponPopoverClose).unbind('click').on('click', function (e) {
3631            e.preventDefault();
3632            $('#couponPopover').addClass('hide');
3633        });
3634
3635        $('#chkcheckoutusewallet').unbind('click').on('click', function () {
3636            cartPrivateMethods.applyCoupon($(this));
3637        });
3638
3639        $(controls.clear).unbind('click').on('click', function () {
3640            cartPrivateMethods.clearCart();
3641        });
3642
3643        $(controls.deleteProduct).unbind('click').on('click', function () {
3644            $(this).addClass('processing');
3645            if ($(this).data('id'))
3646                cartPrivateMethods.deleteCart($(this).data('id'), false);
3647            else
3648                cartPrivateMethods.deleteOrder($(this).data('orderid'));
3649        });
3650
3651        $('#podcontainer').unbind('click').on('click', function (e) { $("#rdPaymentMethod_0").prop("checked", 1); $('#frmSubmitCheckout').submit(); });
3652        $('#frmSubmitCheckout').unbind('submit').on('submit', function (e) {
3653            //$(this).find('button.contunuPay_btn').prop('disabled', true);
3654
3655            var result = cartPrivateMethods.validateCheckoutSubmit(this, e);
3656            //if (result)
3657            //    $(".contunuPay_btn").addClass('processing');
3658            //if (!($("#rdPaymentMethod_1").is(":checked"))) {
3659            //    $(this).find('button.contunuPay_btn img').remove();
3660            //    $(this).find('button.contunuPay_btn').prop('disabled', (result == true ? true : false));
3661            //}
3662            return result;
3663        });
3664        $("#btncontinuePay").unbind('click').on('click', function (e) {
3665            $(this).parent().removeClass('m-fixed-button'); // Removes from immediate parent
3666            if ($('.checkout-listing div.not-deliverable-order').length > 0) {
3667                master.showResult('Some items in your order are currently non-deliverable. Please remove these items or update their quantities, then try again.', 'Failure', false);
3668                return;
3669            }
3670            window.scrollTo(0, 0);
3671            return cartPrivateMethods.loadPayment();
3672        });
3673        // 
3674        $("#submitonlinepayment").unbind('click').on('click', function (e) {
3675            $(".submitonlinepaymentWrap").addClass("processing");
3676            return cartPrivateMethods.loadOnlinePayment(this, e);
3677        });
3678        $("#submitonlinepayment-rzp-mob").unbind('click').on('click', function (e) {
3679            $("#submitonlinepayment-rzp-mob").addClass("processing");
3680            return cartPrivateMethods.loadOnlinePayment(this, e);
3681        });
3682        $('#btnsubmitpod').unbind('click').on('click', function (e) {
3683            return cartPrivateMethods.continuePOD();
3684        });
3685        $('#frmsubmitcart').unbind('submit').on('submit', function (e) {
3686            $(this).find('button[type=submit]').addClass('processing');
3687            var _isvalid = cartPrivateMethods.validateCartSubmit(this, e);
3688            $(this).find('button[type=submit] img').remove();
3689            if (_isvalid == false)
3690                $(this).find('button[type=submit]').removeClass('processing');
3691        });
3692        $('#reviewBtn').unbind('click').on('click', function (e) {
3693            master.showResult('Sorry, we are not started accepting orders. Please check back soon.', 'Failure', false);
3694
3695        });
3696
3697        $('#deliveryTypeModal buttton.submitdeliverymethod').unbind('click').on('click', function (e) {
3698            $('#frmsubmitcart').submit();
3699        });
3700
3701        $('#TimeSlotMode_2').unbind('click').on('click', function (e) {
3702            $("#datebox").show();
3703            var color = $("#datebox").is(':hidden') ? '#FF0' : 'white';
3704            $("#changedate").css('color', color);
3705        });
3706        $("#TimeSlotMode_1").click(function () {
3707            $("#datebox").hide();
3708        });
3709        $("#TimeSlotMode_1").click(function () {
3710            $(".hidicon").hide();
3711        });
3712        $("#hidedate").click(function () {
3713            $(".hidicon").show();
3714        });
3715        $('ul.time-slot li.time-slot-item').on('click', function (e) {
3716            var self = $(this);
3717            // the class `active` is added as soon as the button is clicked
3718            if ($(this).hasClass('active'))
3719                cartMethods.setTimeSlot(self, false);
3720            else
3721                cartMethods.setTimeSlot(self, true);
3722        });
3723
3724        $('.form-qty-block').unbind('click').on('click', '.btn-plus, .btn-minus', function (e) {
3725            if ($(this).hasClass('skip-addcart'))
3726                return true;
3727
3728            e.preventDefault();
3729            // Checks if the selected item requires age verification
3730            var needageverification = $(this).data("needageverification");
3731
3732            // needageverification will be either 0 or 1
3733            if (needageverification) {
3734                master.showAgeVerificationModal(true); //shows age verification modal if 1
3735            }
3736            else
3737                cartPrivateMethods.events.onAdd($(this)); //else continue add to cart
3738
3739        });
3740
3741        $(controls.groupButton).unbind('click').on('click', function () {
3742            cartPrivateMethods.events.navigateToGroup($(this));
3743        });
3744
3745        $('.trigerCartMenu').unbind('click').on('click', function () {
3746            event.stopPropagation();
3747            cartMethods.OpenMiniCart();
3748            // Check if the dropdown is currently visible
3749            const isDropdownVisible = $('.Carttoggelwrap').hasClass('active');
3750            if (isDropdownVisible) {
3751                cartPrivateMethods.events.hideCart($(this));
3752            }
3753            else {
3754                cartPrivateMethods.events.showCart($(this));
3755                cartPrivateMethods.events.initialize();
3756            }
3757
3758        });
3759        $('.close-minicart').unbind('click').on('click', function () { cartMethods.CloseMiniCart(); });
3760
3761        $(controls.deleteOutOfStock).unbind('click').on('click', function () {
3762            cartPrivateMethods.deleteCart($(this).data('id'), true);
3763        });
3764
3765        $(controls.removeOrder).unbind('click').on('click', function () {
3766            cartPrivateMethods.deleteOrder($(this).data('orderid'));
3767
3768        });
3769
3770        $('.trigger-notes-modal').unbind('click').on('click', function () {
3771            //fetching orderid from the add button
3772            const orderId = $(this).data('orderid');
3773
3774            // Set the order ID in the modals textarea as a data attribute and show the modal.
3775            $('#order-notes-modal .confirm-add-note').attr('data-orderid', orderId);
3776            $('#order-notes-modal').modal("show");
3777        });
3778        $('.confirm-add-note').unbind('click').on('click', function () {
3779            let Note = $('#noteToSeller').val().trim().substring(0, cartMethods.properties.notesLength);
3780            let OrderId = $(this).data('orderid');
3781            if (Note == '')
3782                return $('#noteToSeller').addClass('error');
3783            if (!OrderId || OrderId === '')
3784                return; //console.error('order_id was ' + OrderId);
3785
3786            let apiData = {
3787                OrderId,
3788                Note
3789            };
3790            onSuccess = function (res) {
3791                $('#order-notes-modal').modal("hide");
3792            };
3793
3794            onError = function (err) {
3795                //console.error(err.result.error);
3796            };
3797
3798            master.ajax.JSONRequest(cartMethods.url.addOrdernote, 'POST', apiData, onSuccess, onError);
3799        });
3800        $('.search_in_other_store').unbind('click').on('click', function () {
3801            var stit_ID = $(this).data('stitid');
3802            onSuccess = function (res) {
3803                //console.log(res)
3804                if (res.status == 1) { //1 for success and 0 for failure.
3805                    let product = res.data;
3806                    //console.log(product)
3807                    var imageUrl = (product.additional_image && product.additional_image.length > 0) ? product.additional_image[0].image_url : '/images/p-no-image.png';
3808                    var html = `<div class="productItemWrap" >
3809                          <div class="offer_wishlist">
3810                            <div
3811                              class="addtowishicon wishlist-block wishlist-${product.stit_ID}-${product.branch_id}"
3812                              data-productid="${product.stit_ID}"
3813                              data-groupid="${product.stit_ID}" 
3814                              data-branchid="${product.branch_id}" 
3815                              data-branchtypeid="${product.branch_type_id}" 
3816                              data-source="1"
3817                            >
3818                              <i class="fa-regular fa-heart"></i>
3819                            </div>
3820                          </div>
3821                          <div class="productImgWrap">
3822                            <div class="productImg">
3823                              <a href="/pd/${product.stit_ID}/${product.branch_id}/${product.branch_type_id}/${encodeURIComponent(product.stit_itemName)}">
3824                                <img
3825                                  src="${imageUrl}"
3826                                    onerror="${this.src = '/images/p-no-image.png'}"
3827                                  alt="${product.stit_SKU}"
3828                                />
3829                              </a>
3830                            </div>
3831                          </div>
3832                          <div class="productItemInfo">
3833                            <div class="productTitle">
3834                              <a href="/pd/${product.stit_ID}/${product.branch_id}/${product.branch_type_id}
3834/${encodeURIComponent(product.stit_itemName)}">
3835                                ${product.stit_itemName}
3836                              </a>
3837                            </div>
3838                            <div class="productPrice">
3839                              <span class="actulPrice">
3840                               <span class="badge"><img src="/images/sponsored-01.svg"></span></span>
3841                              <span class="DisPrice_unitprice">
3842                                <span class="productDisPrice">₹${product.selling_price}</span>
3843                                <i class="expres_delivery" title="Courier Delivery">
3844                                  <img src="https://cdncontent.bitszol.com/images/icons/normal_delivery.svg" />
3845                                </i>
3846                              </span>
3847                            </div>
3848                          </div>
3849                          <div class="addunit_infowrap">
3850                            <div class="form-qty-block addunitWrap addunitWrap-${product.stit_ID}-${product.branch_id}" data-productid="${product.stit_ID}"
3851                              data-groupid="${product.stit_ID}">
3852                              <button
3853                                type="button"
3854                                id="product-minus-${product.stit_ID}-${product.branch_id}"
3855                                class="btn btn-sm btn-minus hide product-tile-minus-${product.stit_ID}-${product.branch_id}"
3856                                data-productid="${product.stit_ID}"
3857                                data-groupid="${product.stit_ID}"
3858                              >
3859                                -
3860                              </button>
3861                              <input
3862                                type="number"
3863                                class="form-control form-control-sm form-qty hide product-tile-qty-${product.stit_ID}-${product.branch_id}"
3864                                step="1"
3865                                min="0"
3866                                max="${product.stock_available}"
3867                                value="0"
3868                                id="product-qty-${product.stit_ID}-${product.branch_id}"
3869                                placeholder="Add"
3870                              />
3871                              <button
3872                                type="button"
3873                                id="product-plus-${product.stit_ID}-${product.branch_id}"
3874                                class="btn btn-sm btn-plus btn-add product-tile-plus-${product.stit_ID}-${product.branch_id}"
3875                                data-productid="${product.stit_ID}"
3876                                data-groupid="${product.stit_ID}"
3877                                data-brid="${product.branch_id}"
3878                                data-brtypeid="${product.branch_type_id}"
3879                                data-needageverification="0"
3880                              >
3881                                <span>Add</span>+
3882                              </button>
3883                            </div>
3884                            <div class="veg_novgsymple"></div>
3885                          </div>
3886                        </div >`;
3887                    $('li').has('a.search_in_other_store[data-stitid="' + stit_ID + '"]').html(html); //injecting the html to the selected view
3888                    cart.rebindEvents();//rebind click handlers so add to cart and other functionalities work as expected on the injected html (no need to re-fetch cart count or Handlebars helpers here).
3889                }
3890                else {
3891                    $('.search_in_other_store[data-stitid="' + stit_ID + '"]').addClass('hide');
3892                    alert(res.message);
3893                }
3894
3895            };
3896
3897            onError = function (err) {
3898                //console.log(err);
3899                $('.search_in_other_store[data-stitid="' + stit_ID + '"]').addClass('hide');
3900                alert('Sorry, No other stores are selling this product!');
3901            };
3902
3903            master.ajax.JSONRequest('/searchInOtherStore', 'POST', stit_ID, onSuccess, onError);
3904        });
3905        $('.auto_remove_items').unbind('click').on('click', async function () {
3906            $(this).addClass('processing');
3907
3908            let promises = [];
3909
3910            $('.product-card.product_outofstock').each(function () {
3911                var $removeBtn = $(this).find('.btn-cart-remove');
3912                var productId = $removeBtn.data('id');
3913
3914                if ($removeBtn.length > 0 && productId) {
3915                    var details = { cart_product_id: productId };
3916
3917                    const promise = master.ajax.JSONRequestPromise(cartMethods.url.deleteCart, 'POST', details);
3918
3919                    promises.push(promise);
3920                }
3921            });
3922            
3923
3924            // Wait for all deleteCart API calls to finish
3925            Promise.all(promises).then(() => {
3926                window.location.reload();
3927            }).catch(err => {
3928                //console.error("Some deleteCart requests failed:", err);
3929            });
3930        });
3931
3932        $('#noteToSeller').attr('maxlength', cartMethods.properties.notesLength);
3933    };
3934
3935
3936
3937    return cartMethods;
3938})();
3939$(function () {
3940    cart.initializePage();
3941});
3942var wishlist = (function () {
3943    var wishlistMethods = {}, wishlistPrivateMethods = {};
3944
3945    wishlistPrivateMethods.events = {};
3946
3947    wishlistMethods.properties = {
3948        wishListItems: { 'items': [] },
3949        isProductDetailsPage: false
3950    };
3951    wishlistPrivateMethods.properties = {
3952        isOtpTriggered: false,
3953        currentInstance: null
3954
3955    };
3956    wishlistMethods.url = {
3957        add: '/addtowishlist',
3958        delete: '/deletefromwishlist',
3959        get: '/wishlist'
3960    };
3961    wishlistPrivateMethods.controls = {
3962        homeWishlistIconBlock: '.wishlist-block',
3963        delete: '.delete-product-from-wishlist',
3964        navigator: '.open-wishlist',
3965        moveFromCart: '.move-to-wishlist',
3966        addToCart: '.addcart-wishlist'
3967    };
3968    wishlistMethods.updateWishLitemsInHomePage = function (wishlistItems = []) {
3969        // Nothing to do if there's no data
3970        if (!Array.isArray(wishlistItems) || wishlistItems.length === 0) {
3971            return;
3972        }
3973
3974        const isPDP = Boolean(wishlistMethods.properties.isProductDetailsPage);
3975
3976        wishlistItems.forEach(({ stit_ID: productId, groupId }) => {
3977            const selector = `.wishlist-${productId}-${groupId}`;
3978            const $btn = $(selector);
3979
3980            if (!$btn.length) {
3981                // element not on this page
3982                return;
3983            }
3984
3985            // Always mark it active
3986            $btn.addClass('active');
3987
3988            // On PDP, also update the tooltip/title
3989            if (isPDP) {
3990                $btn.attr('title', 'Remove from wishlist');
3991            }
3992        });
3993    };
3994    wishlistPrivateMethods.deleteFromWishlist = function (productId, groupId, isRequestFromHome = false) {
3995        const details = { product_id: productId, group_id: groupId };
3996        const baseSelector = `.wishlist-${productId}-${groupId}`;
3997
3998        // cleanup both in success & error
3999        function cleanupProcessing() {
4000            const inst = wishlistPrivateMethods.properties.currentInstance;
4001            if (inst) {
4002                $(inst).removeClass('processing');
4003                wishlistPrivateMethods.properties.currentInstance = null;
4004            }
4005        }
4006
4007        function onSuccess(data) {
4008            cleanupProcessing();
4009
4010            if (data.status !== 'ok') {
4011                //console.warn('Wishlist delete failed:', data);
4012                return;
4013            }
4014
4015            // Always remove the “active” state
4016            $(baseSelector).removeClass('active');
4017
4018            if (wishlistMethods.properties.isProductDetailsPage) {
4019                // On PDP, change the tooltip back
4020                requestAnimationFrame(() => {
4021                    $(baseSelector).attr('title', 'Add to wishlist');
4022                });
4023
4024            } else if (window.location.pathname === '/wishlist') {
4025                // On the wishlist page, just reload
4026                window.location.reload(true);
4027
4028            } else {
4029                // Anywhere else (e.g. home), remove the tile and clear active class
4030                $(`#wishlist-tile-${productId}`).remove();
4031            }
4032        }
4033
4034        function onError(err) {
4035            //console.error('Wishlist delete error:', err);
4036            cleanupProcessing();
4037        }
4038
4039        // Fire it off
4040        master.ajax.JSONRequest(
4041            wishlistMethods.url.delete,
4042            'POST',
4043            details,
4044            onSuccess,
4045            onError
4046        );
4047    };
4048    // Helper: show login modal and focus
4049    function promptLogin() {
4050        $('#login-modal').modal('show');
4051        setTimeout(() => $('#txt-mobile').focus(), 500);
4052    }
4053    // Helper: update a wishlist button’s state
4054    function updateWishlistButton($btn, { active, title }) {
4055        if (active) {
4056            $btn.addClass('active');
4057        } else {
4058            $btn.removeClass('active');
4059        }
4060        if (title) {
4061            $btn.attr('title', title);
4062        }
4063    }
4064    wishlistPrivateMethods.addToWishList = function ($btn, source = 1) {
4065        const productId = $btn.data('productid');
4066        const groupId = $btn.data('groupid');
4067        const branchId = $btn.data('branchid');
4068        const branchTypeId = $btn.data('branchtypeid');
4069        const masterId = $btn.data('id');
4070        const isAuth = String($btn.data('isauthenticated')).toLowerCase() === 'true';
4071        const selector = `.wishlist-${productId}-${groupId}`;
4072
4073        // 1. Authentication guard
4074        if (!isAuth) {
4075            return promptLogin();
4076        }
4077
4078        // 2. Prepare payload
4079        const payload = {
4080            product_id: productId,
4081            group_id: groupId,
4082            branch_id: branchId,
4083            branch_type_id: branchTypeId,
4084            source
4085        };
4086
4087        // 3. AJAX success handler
4088        const onSuccess = data => {
4089            if (data.status !== 'ok') {
4090                //console.warn('Add to wishlist failed', data);
4091                return;
4092            }
4093
4094            // 3a. If we're on the cart page, remove from cart
4095            if (cart.properties.isCartPage) {
4096                cart.deleteItem(masterId);
4097            }
4098
4099            // 3b. Determine UI update
4100            if (wishlistMethods.properties.isProductDetailsPage) {
4101                updateWishlistButton($(selector), {
4102                    active: true,
4103                    title: 'Remove from wishlist'
4104                });
4105            } else {
4106                // Home/catalog context
4107                updateWishlistButton($btn, { active: true });
4108                $btn.closest('.form-qty-block').addClass('disabled');
4109                $(`.notify-bell-${productId}-${groupId}`).addClass('hide');
4110                $(`.notify-check-${productId}-${groupId}`).removeClass('hide');
4111            }
4112        };
4113
4114        // 4. AJAX error handler
4115        const onError = err => {
4116            //console.error('Error adding to wishlist', err);
4117        };
4118
4119        // 5. Fire the request
4120        master.ajax.JSONRequest(
4121            wishlistMethods.url.add,
4122            'POST',
4123            payload,
4124            onSuccess,
4125            onError
4126        );
4127    };
4128    wishlistPrivateMethods.toggleWishlistItem = function ($btn) {
4129        const productId = $btn.data('productid');
4130        const groupId = $btn.data('groupid');
4131        const source = $btn.data('source') || 1;
4132        const isActive = $btn.hasClass('active');
4133        const isPDP = Boolean(wishlistMethods.properties.isProductDetailsPage);
4134
4135        if (isActive) {
4136            // Remove from wishlist
4137            wishlistPrivateMethods.deleteFromWishlist(
4138                productId,
4139                groupId,
4140      /* isRequestFromHome */ !isPDP
4141            );
4142        } else {
4143            // Add to wishlist
4144            wishlistPrivateMethods.addToWishList($btn, source);
4145        }
4146    };
4147    wishlistPrivateMethods.moveFromCart = function (self) {
4148        if (!confirm('Are you sure you want to move this item to wishlist?'))
4149            return false;
4150        wishlistPrivateMethods.addToWishList(self, "1");
4151    };
4152    wishlistPrivateMethods.addToCart = function (self) {
4153        $(self).addClass("processing");
4154        wishlistPrivateMethods.properties.currentInstance = self;
4155        var details = {
4156            cart_product_id: self.data('productid'),
4157            cart_group_id: self.data('groupid'),
4158            cart_order_qty: 1,
4159            cart_branch_id: self.data('branchid'),
4160            branch_type_id: self.data('branchtypeid')
4161        };
4162        cart.addToCart(details, wishlistPrivateMethods.deleteFromWishlist);
4163    };
4164    wishlistPrivateMethods.events.initialize = function () {
4165        var controls = wishlistPrivateMethods.controls;
4166
4167        $(controls.navigator).unbind('click').on('click', function () {
4168            window.location.href = wishlistMethods.url.get;
4169        });
4170
4171        $(controls.homeWishlistIconBlock).unbind('click').on('click', function () {
4172            wishlistPrivateMethods.toggleWishlistItem($(this));
4173        });
4174
4175        $(controls.delete).unbind('click').on('click', function () {
4176            var productId = $(this).data('productid');
4177            var groupId = $(this).data('groupid');
4178            wishlistPrivateMethods.deleteFromWishlist(productId, groupId, false);
4179        });
4180
4181        $(controls.moveFromCart).unbind('click').on('click', function () {
4182            wishlistPrivateMethods.moveFromCart($(this));
4183        });
4184        $(controls.addToCart).unbind('click').on('click', function () {
4185            wishlistPrivateMethods.addToCart($(this));
4186        });
4187    };
4188    wishlistMethods.initializePage = function () {
4189        wishlistPrivateMethods.events.initialize();
4190    };
4191
4192    return wishlistMethods;
4193})();
4194$(function () {
4195    wishlist.initializePage();
4196});
4197var home = (function () {
4198    var homeMethods = {}, homePrivateMethods = {};
4199
4200    homePrivateMethods.events = {};
4201    homeMethods.url = {
4202        cartAndWishlist: '/loadcartandwishlist'
4203    };
4204    homePrivateMethods.url = {
4205        footerContentMini: '/about-us-mini'
4206    };
4207
4208    homePrivateMethods.controls = {
4209        businessType: '#drp-business-type',
4210        businessTypeTile: '.business-type-tile',
4211        offer: '.offer-slide',
4212        footerAboutUs: '#aboutus-footer'
4213    };
4214
4215    homePrivateMethods.loadCartAndWishlist = function () {
4216        master.properties.isLoadingCartAndWishlist = true;
4217        onSuccess = function (result) {
4218            master.properties.isLoadingCartAndWishlist = false;
4219            master.properties.hasLoadedCartAndWishlist = true;
4220            if (result) {
4221                if (result.catitems)
4222                    cart.properties.cartItems.items = result.catitems;
4223                if (result.catitems.length > 0)
4224                    cart.updateCartButton();
4225                if (result.wishlistitems.length > 0)
4226                    wishlist.updateWishLitemsInHomePage(result.wishlistitems);
4227            }
4228        };
4229        onError = function (data) {
4230            master.properties.isLoadingCartAndWishlist = false;
4231            master.properties.hasLoadedCartAndWishlist = true;
4232        };
4233        master.ajax.JSONRequest(homeMethods.url.cartAndWishlist, 'GET', {}, onSuccess, onError);
4234    };
4235
4236    homePrivateMethods.events.initialize = function () {
4237        $(homePrivateMethods.controls.businessType).unbind('change').on('change', function () {
4238            window.location.href = '/bt/' + $(this).val() + '/' + $(this).children("option").filter(":selected").text();
4239        });
4240    };
4241
4242    homeMethods.initializePage = function () {
4243        homePrivateMethods.events.initialize();
4244        homePrivateMethods.loadCartAndWishlist();
4245        //homePrivateMethods.loadFooterAboutUs();
4246    };
4247
4248    return homeMethods;
4249})();
4250$(function () {
4251    home.initializePage();
4252});

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.