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"> </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"> </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.