PageSourceSearch

https://www.m1.com.sg/etc.clientlibs/M1/components/corpcomponents/…-98f8e1964446602bc728f87b6d2acbbc-lc.min.js

js m1.com.sg collected 2026-09-24 08:51:23 UTC 45,382 bytes, 1,111 lines download raw bytes

1(function ($) {
2  $(function () {
3    console.log('Header V2 script loaded');
4
5    $('.menu-arrow').on('click', function () {
6      $(this).toggleClass('rotate-180');
7      $(this).closest('li').find('ul').toggleClass('level-three-menu');
8    });
9
10    $('.mobile-menu-icon').on('click', function () {
11      $('.menu-open-box').toggleClass('left-0');
12      $('.overlaySection').removeClass('hidden');
13    });
14
15    $('.back-to-main-menu').on('click', function () {
16      $('.menu-open-box').removeClass('left-0');
17      $('.mobile-level-two-menu').removeClass('left-0');
18      $('.overlaySection').addClass('hidden');
19    });
20
21    // Mobile: toggle menu
22    $('.open-sub-menu-mobile').on('click', function (e) {
23      e.preventDefault();
24      $(this)
25        .parents('.has-mobile-menu')
26        .find('.mobile-level-two-menu')
27        .addClass('left-0');
28      let getMenuText = $(this)
29        .parents('.has-mobile-menu')
30        .find('.level-one-menu')
31        .text();
32      $(this)
33        .parents('.has-mobile-menu')
34        .find('.submenu-title')
35        .text(getMenuText);
36    });
37
38    $('.back-level-one-menu').on('click', function () {
39      $('.mobile-level-two-menu').removeClass('left-0');
40    });
41
42    $('.desktop-menu .has-submenu').on('hover', function () {
43      $('.overlaySection').removeClass('hidden');
44    });
45
46    $('.desktop-menu .has-submenu').hover(
47      function () {
48        $('.overlaySection').removeClass('hidden'); // Add 'active' when hovered
49        $('.react-popover').fadeOut();
50      },
51      function () {
52        $('.overlaySection').addClass('hidden'); // Remove 'active' when not hovered
53      }
54    );
55
56    $('.m1-id-field').hide();
57    $('.m1-id-field-response').hide();
58    $('.otp-field').hide();
59    $('.login-success').hide();
60    $('.limit-exceed-error').hide();
61    $('.m1-id-not-found').hide();
62    $('.m1loader').hide();
63    $('.logged-in-banner').hide();
64    let otpDisabled = $('#react-tiny-popover-container').data('otp-disable'); //false;
65    let javaBaseURL = $('#react-tiny-popover-container').data('javabase'); //"https://apimuat.m1.com.sg/web2.0";
66    let javaApimKey = $('#react-tiny-popover-container').data('java-apim'); //"dfdc2098a2cc49e59f790b97170829fb";
67
68    let getB2CURL = $('#react-tiny-popover-container').data('b2curl'); //"https://loginuat.m1.com.sg/M1UAT.onmicrosoft.com/oauth2/v2.0/";
69    let getClientID = $('#react-tiny-popover-container').data('client-id'); //"2a681942-f2e0-45f6-905c-c86b91d09a9b";
70    let getclientSecretId = $('#react-tiny-popover-container').data(
71      'client-secret-id'
72    ); //"aQC8Q~C-DHSiJY5pU.JkVrofph6WpML2Pfh7Yclj";
73    let getReturnUrl = $('#react-tiny-popover-container').data('callback'); //"https://uatneww.m1.com.sg/content/M1/us/web/shop/sign-up/step.html";
74
75    $('.login-action-reset').on('click', function () {
76      $('.email-error').text('');
77      $('#emailid').val('').removeClass('error-border');
78      $('#nricid').val('').removeClass('error-border');
79      $('.login-with-email').show();
80      $('.otp-field').hide();
81      $('.m1-id-field').hide();
82      $('.m1-id-field-response').hide();
83      $('.m1-id-not-found').hide();
84      $('.limit-exceed-error').hide();
85      $('.login-success').hide();
86      $('.m1loader').hide();
87      $('.resend-otp')
88        .addClass('pointer-events-none text-neutral-gray')
89        .removeClass('text-primary-orange cursor-pointer');
90      $('.otp-error').text('');
91      $('.pincode-input-text').val('');
92      $('.resend-otp').removeClass('resend-done');
93    });
94
95    let getLoginInfo = sessionStorage.getItem('customerInfo') ? true : false;
96
97    if (getLoginInfo) {
98      $('.after-login').show();
99      $('.before-login').hide();
100      $('.guest-banner').hide();
101      $('.logged-in-banner').show();
102    } else {
103      $('.after-login').hide();
104      $('.before-login').show();
105      $('.guest-banner').show();
106      $('.logged-in-banner').hide();
107    }
108
109    let getVoucherCount = sessionStorage.getItem('voucherCount');
110    let getOfferDesc = $('.after-login .offers-popover-content').text();
111    if (getVoucherCount) {
112      $('.after-login .offers-popover-content').html(
113        getOfferDesc.replaceAll('{{totalVoucher}}', `<span class="set-voucher-count">${getVoucherCount}</span>`)
114      );
115      $('.set-voucher-count').text(getVoucherCount);
116    } else {
117      $('.after-login .offers-popover-content').html(
118        getOfferDesc.replaceAll('{{totalVoucher}}', `<span class="set-voucher-count">${$('.promo-voucher-list').length}</span>`)
119      );
120      $('.set-voucher-count').text($('.promo-voucher-list').length);
121    }
122
123    function loginAction(width) {
124      let getLoginInfo = sessionStorage.getItem('customerInfo') ? true : false;
125      if (getLoginInfo) {
126        $('.after-login').show();
127        $('.before-login').hide();
128      } else {
129        $('.after-login').hide();
130        $('.before-login').show();
131      }
132      if (width > 1023) {
133        $('.react-popover').fadeIn();
134      } else {
135        $('.react-popover').fadeToggle();
136      }
137    }
138
139    $('.login-action').on('mouseover', function (e) {
140      if ($(window).width() > 1023) {
141        loginAction($(window).width());
142      }
143    });
144
145    $('.login-action').on('click', function () {
146      if ($(window).width() < 1024) {
147        loginAction($(window).width());
148      }
149    });
150
151    // $(document).on('mousedown', function (e) {
152    //     if (!$(e.target).closest('.react-popover').length) {
153    //         $('.react-popover').hide();
154    //     }
155    // });
156
157    $(document).on('.modal-overlay', 'click', function () {
158      $('.login-action-reset').click();
159    });
160
161    $(document).on('click', function (e) {
162      if (
163        $(window).width() > 1023 &&
164        $(e.target).closest('.react-popover').length === 0
165      ) {
166        $('.react-popover').fadeOut();
167      }
168    });
169
170    $('.login-action-open').on('click', function () {
171      console.log('login-action-open clicked');
172      $('.react-popover').fadeOut();
173      new bootstrap.Modal($('#login')).show();
174    });
175
176    $('.back-to-login').on('click', function () {
177      $('.m1-id-field-response').hide();
178      $('#emailid').val('');
179      $('.login-with-email').show();
180    });
181
182    $('.forgot-m1-id').on('click', function () {
183      $('.login-with-email').hide();
184      $('#nricid').val('');
185      $('.m1-id-field').show();
186    });
187
188    $('#nricid').on('blur', function (e) {
189      e.preventDefault();
190      const nric = $(this).val();
191      if (nric === '') {
192        $('.email-error-nric').text('NRIC/FIN Number required');
193        $('#nricid').addClass('error-border');
194        return false;
195      } else if (IsNRIC(nric) === false) {
196        $('.email-error-nric').text(
197          'Invalid NRIC/FIN format. Please check again'
198        );
199        $('#nricid').addClass('error-border');
200        return false;
201      } else {
202        $('.email-error-nric').text('');
203        $('#nricid').removeClass('error-border');
204        return true;
205      }
206      return false;
207    });
208
209    $('.pincode-input-text').on('paste', function (e) {
210      e.preventDefault();
211      var pastedData = (e.originalEvent || e).clipboardData.getData('text');
212      pastedData = pastedData.trim();
213      if (!/^\d{6}$/.test(pastedData)) {
214        $('.otp-error').text('Invalid OTP. Please enter a valid 6-digit OTP.');
215        return;
216      }
217      $('.pincode-input-text').each(function (index) {
218        $(this).val(pastedData[index]);
219      });
220    });
221
222    $('.pincode-input-text').keyup(function (e) {
223      var index = $(this).index('input');
224      var inputs = $('.pincode-input-text');
225      if (e.keyCode == 8) {
226        var index = inputs.index(this);
227        if (index != 0)
228          inputs
229            .eq(index - 1)
230            .val('')
231            .focus();
232      } else {
233        $('input')
234          .eq(index + 1)
235          .focus();
236      }
237    });
238
239    $('#nricid').on('blur', function (e) {
240      e.preventDefault();
241      const nric = $(this).val();
242      if (nric === '') {
243        $('.email-error-nric').text('NRIC/FIN Number required');
244        $('#nricid').addClass('error-border');
245        return false;
246      } else if (IsNRIC(nric) === false) {
247        $('.email-error-nric').text(
248          'Invalid NRIC/FIN format. Please check again'
249        );
250        $('#nricid').addClass('error-border');
251        return false;
252      } else {
253        $('.email-error-nric').text('');
254        $('#nricid').removeClass('error-border');
255        return true;
256      }
257      return false;
258    });
259
260    $('#emailid').on('blur', function (e) {
261      e.preventDefault();
262      const email = $(this).val();
263      if (email === '') {
264        $('.email-error').text('Email ID required');
265        $('#emailid').addClass('error-border');
266        return false;
267      } else if (IsEmail(email) === false) {
268        $('.email-error').text('Enter Valid EmailID');
269        $('#emailid').addClass('error-border');
270        return false;
271      } else {
272        $('.email-error').text('');
273        $('#emailid').removeClass('error-border');
274        return true;
275      }
276      return false;
277    });
278
279    function IsNRIC(nric) {
280      const regex = /^[a-zA-Z][0-9]{7}[a-zA-Z]+$/;
281      if (!regex.test(nric)) {
282        return false;
283      } else {
284        return true;
285      }
286    }
287
288    function IsEmail(email) {
289      const regex =
290        /^([a-zA-Z0-9_\.\-\+])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
291      if (!regex.test(email)) {
292        return false;
293      } else {
294        return true;
295      }
296    }
297
298    function showLoader(show) {
299      if (show) {
300        $('.m1loader').css('display', 'flex');
301      } else {
302        $('.m1loader').hide();
303      }
304    }
305
306    function ajaxCall(url, data, method) {
307      let getCustomerInfo = JSON.parse(sessionStorage.getItem('customerInfo'));
308      return $.ajax({
309        url: url.includes('onmicrosoft') ? url : javaBaseURL + url,
310        headers: {
311          'apim-subscription-key': javaApimKey,
312          'content-type': 'application/json',
313          Token: getCustomerInfo?.access_token
314            ? getCustomerInfo.access_token
315            : '',
316        },
317        method: method,
318        dataType: 'json',
319        data: method.toUpperCase() === 'GET' ? data : JSON.stringify(data),
320        processData: method.toUpperCase() === 'GET',
321        contentType:
322          method.toUpperCase() === 'GET' ? false : 'application/json',
323      });
324    }
325
326    let timerLimit = 1; // for example, 2 minutes
327    let intervalHandle = null;
328
329    function startCountdown(timerLimit) {
330      let secondsRemaining = timerLimit * 60;
331
332      // Clear any previous interval
333      if (intervalHandle) clearInterval(intervalHandle);
334
335      intervalHandle = setInterval(function () {
336        // clear OTP message on every tick
337        $('.otp-error').text('');
338
339        let min = Math.floor(secondsRemaining / 60);
340        let sec = secondsRemaining - min * 60;
341        if (sec < 10) sec = '0' + sec;
342        let message = '0' + min.toString() + ':' + sec;
343
344        $('#countdown').text(message);
345
346        if (secondsRemaining === 0) {
347          $('.otp-error').text(
348            'OTP has expired. Please request for a new one.'
349          );
350          clearInterval(intervalHandle);
351          $('.resend-otp')
352            .removeClass('pointer-events-none text-neutral-gray')
353            .addClass('text-primary-orange cursor-pointer');
354        }
355        secondsRemaining--;
356      }, 1000);
357    }
358
359    $('.resend-otp').on('click', function () {
360      // Reset the countdown timer
361      $('.email-login').click(); // Trigger the email login click event to resend OTP
362      $(this)
363        .addClass('pointer-events-none text-neutral-gray resend-done')
364        .removeClass('text-primary-orange cursor-pointer');
365      // clearInterval(intervalHandle);
366      // startCountdown(timerLimit);
367
368      // Clear OTP input fields
369      $('.pincode-input-text').val('');
370
371      // Optionally, you can also show a message or perform an AJAX call to resend the OTP
372      $('.otp-error').text('');
373    });
374
375    var emailResponse = null;
376    $('.email-login').on('click', function (e) {
377      e.preventDefault();
378      const email = $('#emailid').val().trim();
379      if (!email) {
380        $('.email-error').text('Email ID required');
381        return;
382      }
383      if (!IsEmail(email)) {
384        $('.email-error').text('Enter Valid EmailID');
385        return;
386      }
387      $('.email-error').text('');
388      $('#emailid').removeClass('error-border');
389      // Proceed with AJAX call or further processing
390      showLoader(true);
391      let data = {
392        emailID: email,
393        planType: 'NEWLINE',
394        onlyEmailRequired: 'true',
395      };
396
397      ajaxCall('/login/sendOTP', data, 'POST')
398        .done(function (response) {
399          // Handle success
400          console.log('Success:', response);
401          console.log('Success 111:', response?.verificationKey);
402          showLoader(false);
403          if (response?.verificationKey) {
404            emailResponse = response;
405            sessionStorage.setItem('customerLogin', JSON.stringify(response));
406            if (otpDisabled) {
407              idHintTokenCall(emailResponse);
408            } else {
409              if ($('.resend-otp').hasClass('resend-done')) {
410                startCountdown(timerLimit);
411              } else {
412                $('.login-with-email').hide();
413                $('.otp-email').text(email);
414                $('.otp-field').show();
415                startCountdown(timerLimit);
416              }
417            }
418          } else if (
419            response?.message === 'UPPER_LIMIT_EXCEEDED' ||
420            response?.message === 'LOWER_LIMIT_EXCEEDED'
421          ) {
422            $('.limit-exceed-error').show();
423            $('.login-with-email').hide();
424            $('.otp-field').hide();
425          } else {
426            if (response?.error?.errorCode === '400') {
427              $('.email-error').text('Somthing went wrong. Please try again.');
428            } else if (response?.statusCode === 429) {
429              $('.email-error').text(
430                'Oops! Looks like you have requested for the OTP too many times. Please try again later.'
431              );
432            } else {
433              if (
434                response?.error &&
435                response?.error?.errorMessage === 'PROSPECT_CUSTOMER'
436              ) {
437                $('.email-error').text(
438                  'Check that you have entered the correct email or sign up as a New customer.'
439                );
440              } else {
441                $('.email-error').text(
442                  response?.error
443                    ? response?.error?.errorDescription
444                    : response?.message
445                );
446              }
447            }
448          }
449        })
450        .fail(function (error) {
451          // Handle error
452          showLoader(false);
453          console.error('Error:', error);
454          $('.email-error').text(
455            error?.response?.errorCode ? 'M1 ID is incorrect' : error?.message
456          );
457          $('#emailid').addClass('error-border');
458        });
459    });
460
461    $('.m1-id-login').on('click', function (e) {
462      e.preventDefault();
463      const nric = $('#nricid').val().trim();
464      if (!nric) {
465        $('.email-error-nric').text('NRIC/FIN Number required');
466        $('#nricid').addClass('error-border');
467        return;
468      }
469      if (!IsNRIC(nric)) {
470        $('.email-error-nric').text('Enter Valid NRIC/FIN Number');
471        $('#nricid').addClass('error-border');
472        return;
473      }
474      $('.email-error-nric').text('');
475      $('#nricid').removeClass('error-border');
476
477      // Proceed with AJAX call or further processing
478      showLoader(true);
479      let data = {
480        customerIdValue: nric,
481        isForgotM1Id: 'true',
482      };
483      ajaxCall('/login/sendOTP', data, 'POST')
484        .done(function (response) {
485          // Handle success
486          console.log('Success:', response);
487          if (response) {
488            showLoader(false);
489            nricResponse = response;
490            if (
491              response?.emailID &&
492              response?.emailID?.indexOf('@dummy') > -1
493            ) {
494              $('.email-id-not-found').show();
495              $('.login-with-email').hide();
496            } else {
497              if (response?.emailID) {
498                $('.m1-id-field').hide();
499                $('.masked-m1-id').text(response?.emailID);
500                $('.m1-id-field-response').show();
501              } else {
502                $('.email-error-nric').text(
503                  response?.error ? 'M1 ID is incorrect' : response?.message
504                );
505              }
506            }
507          }
508        })
509        .fail(function (error) {
510          // Handle error
511          showLoader(false);
512          console.error('Error:', error);
513        });
514    });
515
516    $('.submit-otp').on('click', function (e) {
517      e.preventDefault();
518      $('.otp-error').text('');
519      let getLoginInfo = JSON.parse(sessionStorage.getItem('customerLogin'));
520      console.log('getLoginInfo', getLoginInfo);
521      const otp = $('.pincode-input-text')
522        .map(function () {
523          return $(this).val();
524        })
525        .get()
526        .join('');
527      if (otp.length < 6) {
528        $('.otp-error').text('Please enter a valid 6-digit OTP');
529        return;
530      }
531
532      showLoader(true);
533      let data = {
534        emailID: $('#emailid').val(),
535        verificationKey: getLoginInfo.verificationKey,
536        otp: otp,
537      };
538      ajaxCall('/login/verifyOTP', data, 'POST')
539        .done(function (response) {
540          // Handle success
541          console.log('Success:', response);
542          showLoader(false);
543          if (response) {
544            if (response?.error) {
545              $('.otp-error').text(
546                response?.error
547                  ? 'M1 ID is incorrect'
548                  : response?.errorDescription
549              );
550            } else if (response?.result === false) {
551              $('.otp-error').text(
552                response?.error
553                  ? response?.error?.errorDescription
554                  : response?.message
555              );
556            } else {
557              showLoader(true);
558              authorizeB2CLogin(response?.token);
559            }
560          }
561        })
562        .fail(function (error) {
563          // Handle error
564          console.error('Error:', error);
565          showLoader(false);
566          $('.otp-error').text(
567            error?.response?.errorCode ? 'M1 ID is incorrect' : error?.message
568          );
569        });
570    });
571
572    async function authorizeB2CLogin(resToken) {
573      showLoader(true);
574      const res = await fetch(
575        `${getB2CURL}authorize?client_id=${getClientID}&scope=${getClientID}+offline_access+openid&response_type=code&redirect_uri=${getReturnUrl}&state=12345678&nonce=DefaultNonce&resource=${getClientID}&p=B2C_1A_M1_BlueSky_CBP&id_token_hint=${resToken}`
576      );
577      // Code fails before you ever get here and check res.status
578      console.log('res', res);
579      const newLocation = res.url;
580      console.log('newLocation', newLocation);
581      let url = new URL(newLocation);
582      let AuthCode = url.searchParams.get('code');
583      if (AuthCode) {
584        B2CLoginTokenCall(AuthCode);
585      }
586    }
587
588    function B2CLoginTokenCall(AuthCode) {
589      showLoader(true);
590      ajaxCall(
591        `${getB2CURL}token`,
592        {
593          client_secret: getclientSecretId,
594          grant_type: 'authorization_code',
595          redirect_uri: getReturnUrl,
596          code: AuthCode,
597          client_id: getClientID,
598          p: 'B2C_1A_M1_BlueSky_CBP',
599          scope: getClientID,
600          offline_access: 'openid',
601        },
602        'GET'
603      )
604        .done(function (response) {
605          // Handle successful token response
606          console.log('Token Response:', response);
607          showLoader(false);
608          const decoded = parseJwt(response.access_token);
609          let data = {
610            emailID: $('#emailid').val(),
611            access_token: response.access_token,
612            customerId: decoded?.sub,
613            customerData: JSON.parse(JSON.stringify(decoded)),
614          };
615          sessionStorage.setItem('customerInfo', JSON.stringify(data));
616          console.log('decoded JWT', decoded);
617          console.log('data', data);
618          $('.login-with-email').hide();
619          $('.otp-field').hide();
620          $('.login-success').show();
621          $('.before-login').hide();
622          $('.after-login').show();
623          $('.guest-banner').hide();
624          $('.logged-in-banner').show();
625          let getDesc = $('.after-login .offers-popover-content').text();
626          if (getDesc && getDesc.includes('{{totalVoucher}}')) {
627            $('.after-login .offers-popover-content').html(
628              getDesc.replaceAll('{{totalVoucher}}', `<span class="set-voucher-count">${$('.promo-voucher-list').length}</span>`)
629            );
630            $('.set-voucher-count').text($('.promo-voucher-list').length);
631          }
632        })
633        .fail(function (error) {
634          // Handle token error
635          console.error('Token Error:', error);
636          showLoader(false);
637        });
638    }
639
640    $('.log-out').on('click', function () {
641      sessionStorage.removeItem('customerInfo');
642      sessionStorage.removeItem('customerLogin');
643      sessionStorage.removeItem('voucherCount');
644      $('.after-login').hide();
645      $('.guest-banner').show();
646      $('.logged-in-banner').hide();
647      $('#emailid').val('');
648      $('#nricid').val('');
649      $('.email-error').text('');
650      $('.email-error-nric').text('');
651    });
652
653    function parseJwt(token) {
654      var base64Url = token.split('.')[1];
655      var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
656      var jsonPayload = decodeURIComponent(
657        atob(base64)
658          .split('')
659          .map(function (c) {
660            return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
661          })
662          .join('')
663      );
664
665      return JSON.parse(jsonPayload);
666    }
667
668    function idHintTokenCall(emailResponse) {
669      console.log('emailResponse', emailResponse);
670      showLoader(true);
671      let data = {
672        emailID: $('#emailid').val(),
673        isSingPass: false,
674      };
675      ajaxCall('/login/id-hint-token', data, 'POST')
676        .done(function (response) {
677          // Handle successful token response
678          console.log('Token Response:', response);
679          if (response) {
680            showLoader(false);
681            if (response && response?.error) {
682              if (
683                response?.error?.errorCode === '400' ||
684                response?.error?.errorCode === '404'
685              ) {
686                $('.email-error').text(
687                  'Somthing went wrong. Please try again.'
688                );
689              }
690            }
691            if (response?.token) {
692              // GET B2C call to get AuthCode
693              authorizeB2CLogin(response?.token);
694            } else {
695              $('.m1-id-not-found').show();
696              $('.login-with-email').hide();
697            }
698          }
699        })
700        .fail(function (error) {
701          // Handle token error
702          console.error('Token Error:', error);
703          showLoader(false);
704        });
705    }
706
707    // Fetch offer popup
708    $('.offers-button').on('click', function () {
709      $('.offersDropdown .dropdown-content').toggle();
710      $('.offersDropdown .dropdown-icon').toggleClass('rotate-180');
711    });
712
713    $(document).on('click', '.offersDropdown .dropdown-content .item', function () {
714      $('.offersDropdown .dropdown-content').hide();
715      $('.offersDropdown .dropdown-icon').removeClass('rotate-180');
716      $('.offersDropdown .dropdown-customRadio').removeClass('dropdownActive');
717      $('.offersDropdown .dropdown-customRadioInner').removeClass('dropdownActiveInner');
718      $(this).find('.dropdown-customRadio').addClass('dropdownActive');
719      $(this)
720        .find('.dropdown-customRadioInner')
721        .addClass('dropdownActiveInner');
722      $('.selected-line').text($(this).find('.line-no').text());
723      let getSACID = $(this).data('sac');
724      retrieveUserOffers(getSACID);
725    });
726
727    function retrieveAllLines() {
728      showLoader(true);
729      console.log('sessionStorage', sessionStorage.getItem('customerInfo'));
730      let getCustomerInfo = JSON.parse(sessionStorage.getItem('customerInfo'));
731      console.log('getCustomerInfo', getCustomerInfo);
732      $('.no-offer-found').hide();
733      $('.selected-line').text('New Line');
734      $('.dynamic-lines').empty();
735      $('.offers-list .offers-list-data').empty();
736      ajaxCall(
737        '/shoppingcart/offers/retrieve-all-lines?emailID=' +
738        getCustomerInfo?.emailID +
739        '&B2C_GUID=' +
740        getCustomerInfo?.customerId,
741        '',
742        'GET'
743      )
744        .done(function (response) {
745          // Handle successful token response
746          console.log('retrieve-all-lines Response:', response);
747          showLoader(false);
748          if (response?.error) {
749          } else {
750            // Populate dropdown with lines
751            $('.custom-dropdown').data('id-number', response?.idNumber);
752            $('.custom-dropdown').data('id-type', response?.idType);
753            let linesHtml = '';
754            let retrieveAllLinesApi = response;
755            let finalLines = [];
756            if (
757              retrieveAllLinesApi &&
758              retrieveAllLinesApi?.BANs &&
759              retrieveAllLinesApi?.BANs.length > 0 &&
760              retrieveAllLinesApi?.BANs[0]?.Lines &&
761              retrieveAllLinesApi?.BANs[0]?.Lines.length > 0
762            ) {
763              retrieveAllLinesApi?.BANs.map((obj) => {
764                if (obj?.Lines && obj?.Lines.length > 0) {
765                  obj.Lines.forEach(function (objjj) {
766                    if (
767                      objjj.assetStatus === 'Active' &&
768                      objjj.provisioningStatus === 'Active'
769                    ) {
770                      finalLines.push(objjj);
771                    }
772                  });
773                }
774              });
775            }
776            if (finalLines?.length > 0) {
777              finalLines.forEach(function (line) {
778                let formattedLine = line.MSISDN.replace(
779                  /(\d{4})(\d{4})/,
780                  '$1 $2'
781                );
782                linesHtml += `<div class="item flex flex-row items-center" data-sac="${line.SACId}" data-line="${line.MSISDN}">
783                                            <div class="dropdown-customRadio">
784                                                <div class="dropdown-customRadioInner"></div>
785                                            </div>
786                                            <span class="line-no">${formattedLine}</span>
787                                          </div>`;
788              });
789              $('.dynamic-lines').html(linesHtml);
790              $('.selected-line').text(
791                finalLines[0]?.MSISDN?.replace(/(\d{4})(\d{4})/, '$1 $2')
792              );
793              $(
794                '.dropdown-content .dynamic-lines .item:first .dropdown-customRadio'
795              ).addClass('dropdownActive');
796              $(
797                '.dropdown-content .dynamic-lines .item:first .dropdown-customRadioInner'
798              ).addClass('dropdownActiveInner');
799              retrieveUserOffers(finalLines[0]?.SACId);
800            } else {
801              $('.dropdown-content .new-line .dropdown-customRadio').addClass(
802                'dropdownActive'
803              );
804              $(
805                '.dropdown-content .new-line .dropdown-customRadioInner'
806              ).addClass('dropdownActiveInner');
807              $('.selected-line').text('New Line');
808              retrieveUserOffers();
809            }
810          }
811        })
812        .fail(function (error) {
813          // Handle token error
814          console.error('Token Error:', error);
815          showLoader(false);
816        });
817    }
818
819    function setSGTDateZone(date) {
820      const dateNew = new Date(date);
821
822      // Convert to UTC
823      const options = { timeZone: 'UTC' };
824      const utcDate = new Date(dateNew.toLocaleString('en-US', options));
825
826      // Format date as "dd MMM yyyy"
827      const day = String(utcDate.getDate()).padStart(2, '0');
828      const monthNames = [
829        'Jan',
830        'Feb',
831        'Mar',
832        'Apr',
833        'May',
834        'Jun',
835        'Jul',
836        'Aug',
837        'Sep',
838        'Oct',
839        'Nov',
840        'Dec',
841      ];
842      const month = monthNames[utcDate.getMonth()];
843      const year = utcDate.getFullYear();
844
845      const formattedDate = `${day} ${month} ${year}`;
846
847      console.log('datee==', formattedDate);
848      return formattedDate;
849    }
850
851    function retrieveUserOffers(sacId) {
852      showLoader(true);
853      let getCustomerInfo = JSON.parse(sessionStorage.getItem('customerInfo'));
854      console.log('getCustomerInfo', getCustomerInfo);
855      let getLoginInfo = JSON.parse(sessionStorage.getItem('customerLogin'));
856      console.log('getLoginInfo', getLoginInfo);
857      let data = {
858        userIds: [
859          {
860            user_id: getLoginInfo.cac,
861          },
862          {
863            user_id: sacId,
864          },
865        ],
866        customerInfo: {
867          customerPriIdNo: $('.custom-dropdown').data('id-number'),
868          customerPriIdType: $('.custom-dropdown').data('id-type'),
869          customerId: getCustomerInfo?.customerId,
870          activeOffer: true,
871          planType: '',
872          orderType: '-',
873        },
874      };
875      if (!sacId) {
876        data.userIds.pop(); // Remove the second user_id if sacId is not provided
877      }
878      console.log('data', data);
879      ajaxCall('/customer/offers/retrieve-user-offers', data, 'POST')
880        .done(function (response) {
881          // Handle success
882          console.log('Success:', response);
883          if (response) {
884            if (response?.error?.errorCode) {
885            } else {
886              const voucherArr = response;
887              let voucherCount = 0;
888              let offersHtml = '';
889              if (
890                voucherArr &&
891                voucherArr.offerResponse &&
892                voucherArr.offerResponse.length > 0
893              ) {
894                voucherArr.offerResponse.forEach(function (offer) {
895                  console.log('offerResponse offer', offer);
896                  let offerDate = setSGTDateZone(offer.redemption_end_date);
897                  offersHtml += `<div class="py-24 promo-voucher-list list-none relative w-full border-b border-neutral-gray" data-offer-title="${offer.title}" data-offer-date="${offerDate}" data-offer-description="${offer.description}">
898                                                <div class="w-6 h-6">
899                                                   <svg class="fill-current w-6 h-6 text-primary-orange" fill="" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
900                                                      <path
901                                                          fill-rule="evenodd"
902                                                          clip-rule="evenodd"
903                                                          d="M17.016 8.085c.478.28.807.609 1.004 1.004v.008c.675 1.201.222 2.748-1.004 3.43-.395.23-.584.708-.436 1.11l.033.149a2.245 2.245 0 0 1 0 1.538 2.487 2.487 0 0 1-3.151 1.604l-.132-.033a.908.908 0 0 0-1.12.428c-.279.477-.608.806-1.003 1.004-.378.214-.79.312-1.201.312-.889 0-1.761-.477-2.23-1.316-.23-.395-.708-.584-1.11-.436l-.149.033a2.248 2.248 0 0 1-1.539 0 2.48 2.48 0 0 1-1.604-3.15l.033-.132a.907.907 0 0 0-.428-1.119c-.477-.28-.807-.609-1.004-1.003a2.505 2.505 0 0 1-.206-1.917c.19-.65.617-1.185 1.21-1.514.395-.23.584-.707.436-1.11l-.033-.148a2.247 2.247 0 0 1 0-1.539 2.48 2.48 0 0 1 3.151-1.604l.132.033a.908.908 0 0 0 1.12-.427c.279-.478.608-.807 1.003-1.004 1.21-.675 2.748-.222 3.431.995.23.395.708.584 1.111.436l.148-.033a2.248 2.248 0 0 1 1.539 0 2.48 2.48 0 0 1 1.604 3.15l-.033.14a.9.9 0 0 0 .428 1.111Zm-.749 3.052c.198-.098.305-.214.363-.386h-.017a.937.937 0 0 0 .09-.724.909.909 0 0 0-.452-.56 2.53 2.53 0 0 1-1.185-2.97l.041-.082a.748.748 0 0 0 0-.534.939.939 0 0 0-1.176-.625l-.14.032a2.515 2.515 0 0 1-2.962-1.217 1.063 1.063 0 0 0-.37-.37.898.898 0 0 0-.7-.082.91.91 0 0 0-.56.452 2.532 2.532 0 0 1-2.97 1.185l-.132-.033a.818.818 0 0 0-.56 0 .942.942 0 0 0-.617 1.176l.034.14A2.534 2.534 0 0 1 3.769 9.5c-.148.099-.28.222-.37.379a.922.922 0 0 0 .37 1.266 2.53 2.53 0 0 1 1.185 2.97l-.033.107a.794.794 0 0 0 0 .551.942.942 0 0 0 1.177.617l.14-.033c.246-.074.501-.107.748-.107.946 0 1.794.51 2.222 1.325.09.148.214.28.37.37.206.123.46.148.7.082a.909.909 0 0 0 .559-.452 2.532 2.532 0 0 1 2.97-1.185l.132.033c.19.066.37.066.56 0a.94.94 0 0 0 .617-1.176l-.033-.14a2.46 2.46 0 0 1 1.184-2.97ZM11.322 8.03c.3-.299.76-.299 1.06 0l-.014.008c.3.299.3.758 
9030 1.057l-3.635 3.626a.256.256 0 0 1-.08.08l-.015.015a.76.76 0 0 1-1.053-.08.743.743 0 0 1-.176-.54.768.768 0 0 1 .256-.518l3.657-3.648Zm.9 2.739c-.636 0-1.111.475-1.111 1.111s.475 1.111 1.111 1.111 1.111-.49 1.111-1.11c0-.622-.49-1.112-1.11-1.112ZM7.778 7.806c.62 0 1.11.49 1.11 1.111 0 .62-.474 1.111-1.11 1.111a1.084 1.084 0 0 1-1.111-1.11c0-.637.49-1.112 1.11-1.112Z"
904                                                          fill=""
905                                                      ></path>
906                                                  </svg>
907                                                </div>
908                                                <div class="promo-voucher-action w-full">
909                                                    <div class="flex flex-col">
910                                                        <div class="inline-block items-center"><span class="text-16 font-dinBold">${offer.title}</span></div>
911                                                        <div class="text-12 flex items-center align-middle gap-x-2 text-primary-black"><span class="py-16 leading-none">Valid till: ${offerDate}</span></div>
912                                                    </div>
913                                                    <div class="show-offer-detail">
914                                                        <svg class="fill-current mt-1 w-5 h-5 fill-current cursor-pointer text-primary-orange" fill="" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
915                                                            <g id="chevron">
916                                                                <path
917                                                                    id="glyph"
918                                                                    fill-rule="evenodd"
919                                                                    clip-rule="evenodd"
920                                                                    d="M8.12001 2.33L16.88 11.19C17.32 11.63 17.32 12.35 16.88 12.8L8.12001 21.67C7.68001 22.11 6.97001 22.11 6.53001 21.67C6.09001 21.23 6.09001 20.51 6.53001 20.06L14.49 12L6.53001 3.94C6.09001 3.5 6.09001 2.78 6.53001 2.33C6.97001 1.89 7.68001 1.89 8.12001 2.33Z"
921                                                                    fill=""
922                                                                    stroke=""
923                                                                    stroke-width="0"
924                                                                ></path>
925                                                            </g>
926                                                        </svg>
927                                                    </div>
928                                                </div>
929                                            </div>`;
930                });
931              }
932              if (
933                voucherArr &&
934                voucherArr.voucherResponse &&
935                voucherArr.voucherResponse.length > 0
936              ) {
937                voucherArr.voucherResponse.forEach(function (offer) {
938                  console.log('voucherResponse offer', offer);
939                  let getDesc = 'Applicable on Early Re-contract Fee &/or upfront device payment for Bespoke Contract. Unused voucher value will be forfeited.';
940                  if (offer.offerName.toLowerCase().includes('early')) {
941                    getDesc = 'Get $250 Early Re-contract Fee waiver with $59.95 Bespoke Contract Plan. Or up to $350 Early Re-contract Fee waiver with $75.95 & above Bespoke Contract Plan.'
942                  }
943                  offersHtml += `<div class="py-24 promo-voucher-list list-none relative w-full border-b border-neutral-gray" data-offer-title="${offer.offerName
944                    }" data-offer-date="${offer.offerEndDate
945                    }" data-offer-description="${getDesc}">
946                                                <div class="w-6 h-6">
947                                                    <svg class="fill-current w-6 h-6 text-primary-orange" fill="" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
948                                                      <path
949                                                          fill-rule="evenodd"
950                                                          clip-rule="evenodd"
951                                                          d="M22 10.04C21.89 10.01 21.76 10 21.64 10C20.54 10 19.64 10.9 19.64 12C19.64 13.1 20.54 14 21.64 14C21.76 14 21.88 13.98 22 13.96V19C22 20.1 21.1 21 20 21H4C2.9 21 2 20.1 2 19V13.96C2.11 13.99 2.24 14 2.36 14C3.46 14 4.36 13.1 4.36 12C4.36 10.9 3.46 10 2.36 10C2.24 10 2.12 10.02 2 10.04V5C2 3.9 2.9 3 4 3H20C21.1 3 22 3.9 22 5V10.04ZM17.64 12C17.64 10.38 18.61 8.98 20 8.35V5.5C20 5.22 19.78 5 19.5 5H4.5C4.22 5 4 5.22 4 5.5V8.35C5.39 8.98 6.36 10.38 6.36 12C6.36 13.62 5.39 15.02 4 15.65V18.5C4 18.78 4.22 19 4.5 19H19.5C19.78 19 20 18.78 20 18.5V15.65C18.61 15.02 17.64 13.62 17.64 12ZM15.6473 8.21541C1
9515.2568 7.82488 14.6236 7.82488 14.2331 8.21541L8.20485 14.2436C7.81432 14.6342 7.81432 15.2673 8.20485 15.6579L8.2968 15.7498C8.68732 16.1403 9.32049 16.1403 9.71101 15.7498L15.7392 9.72157C16.1298 9.33105 16.1298 8.69788 15.7392 8.30736L15.6473 8.21541ZM10.04 9.53003C10.04 10.3585 9.36847 11.03 8.54004 11.03C7.71161 11.03 7.04004 10.3585 7.04004 9.53003C7.04004 8.7016 7.71161 8.03003 8.54004 8.03003C9.36847 8.03003 10.04 8.7016 10.04 9.53003ZM15.46 15.97C16.2884 15.97 16.96 15.2984 16.96 14.47C16.96 13.6415 16.2884 12.97 15.46 12.97C14.6315 12.97 13.96 13.6415 13.96 14.47C13.96 15.2984 14.6315 15.97 15.46 15.97Z"
952                                                          fill=""
953                                                      ></path>
954                                                  </svg>
955                                                </div>
956                                                <div class="promo-voucher-action w-full">
957                                                    <div class="flex flex-col">
958                                                        <div class="inline-block items-center"><span class="text-16 font-dinBold">${offer.offerName
959                    }</span></div>
960                                                        <div class="text-12 flex items-center align-middle gap-x-2 text-primary-black"><span class="py-16 leading-none">Valid till: ${offer.offerEndDate?.replaceAll(
961                      '-',
962                      ' '
963                    )}</span></div>
964                                                    </div>
965                                                    <div class="show-offer-detail">
966                                                        <svg class="fill-current mt-1 w-5 h-5 fill-current cursor-pointer text-primary-orange" fill="" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
967                                                            <g id="chevron">
968                                                                <path
969                                                                    id="glyph"
970                                                                    fill-rule="evenodd"
971                                                                    clip-rule="evenodd"
972                                                                    d="M8.12001 2.33L16.88 11.19C17.32 11.63 17.32 12.35 16.88 12.8L8.12001 21.67C7.68001 22.11 6.97001 22.11 6.53001 21.67C6.09001 21.23 6.09001 20.51 6.53001 20.06L14.49 12L6.53001 3.94C6.09001 3.5 6.09001 2.78 6.53001 2.33C6.97001 1.89 7.68001 1.89 8.12001 2.33Z"
973                                                                    fill=""
974                                                                    stroke=""
975                                                                    stroke-width="0"
976                                                                ></path>
977                                                            </g>
978                                                        </svg>
979                                                    </div>
980                                                </div>
981                                            </div>`;
982                });
983              }
984              $('.offers-list .offers-list-data').html(offersHtml);
985              if ($('.promo-voucher-list').length > 0) {
986                voucherCount = $('.promo-voucher-list').length;
987              }
988              sessionStorage.setItem('voucherCount', voucherCount);
989              let getDesc = $('.after-login .offers-popover-content').text();
990              if (getDesc && getDesc.includes('{{totalVoucher}}')) {
991                $('.after-login .offers-popover-content').html(
992                  getDesc.replaceAll('{{totalVoucher}}', `<span class="set-voucher-count">${voucherCount}</span>`)
993                );
994              }
995              $('.set-voucher-count').text($('.promo-voucher-list').length);
996              $('.offers-list .promo-voucher-list').each(function (element) {
997                let getDate = $(this).data('validate-date');
998                if (getDate) {
999                  let offerDate = setSGTDateZone(getDate);
1000                  $(this)
1001                    .find('.promo-voucher-action .offer-date')
1002                    .text(`Valid till: ${offerDate}`);
1003                }
1004              });
1005            }
1006            showLoader(false);
1007          }
1008        })
1009        .fail(function (error) {
1010          // Handle error
1011          showLoader(false);
1012          $('.offers-list .offers-list-data').empty();
1013          $('.no-offer-found').css('display', 'flex');
1014          console.error('Error:', error);
1015        });
1016    }
1017
1018    const urlMappings = window.OFFER_URL_MAPPINGS || [];
1019
1020    let matchedCTA = null;
1021
1022    const findMatchingCTA = (input, ctaData = []) => {
1023      if (!input || !Array.isArray(ctaData) || ctaData.length === 0)
1024        return null;
1025
1026      const normalizedInput = String(input).toLowerCase().replace(/\s+/g, '');
1027
1028      return (
1029        ctaData.find((item) => {
1030          if (!item?.keyword) return false;
1031
1032          const parts = item.keyword
1033            .split('&&')
1034            .map((k) => k.trim())
1035            .filter(Boolean);
1036
1037          return parts.every((part) => {
1038            const normalizedKeyword = part.toLowerCase().replace(/\s+/g, '');
1039            return normalizedInput.includes(normalizedKeyword);
1040          });
1041        }) || null
1042      );
1043    };
1044
1045    $(document).on('click', '.show-offer-detail', function () {
1046      let getDesc = $(this)
1047        .closest('.promo-voucher-list')
1048        .data('offer-description');
1049      matchedCTA = findMatchingCTA(getDesc, urlMappings || []);
1050
1051      if (!matchedCTA) {
1052        $('.offer-redirect').text('Close');
1053      } else {
1054        $('.offer-redirect').text(matchedCTA.ctaLabel || 'Go there');
1055      }
1056
1057      $('#offer-section').hide();
1058      $('.offer-detail-title').text(
1059        $(this).closest('.promo-voucher-list').data('offer-title')
1060      );
1061      $('.offer-detail-description li').text(
1062        $(this).closest('.promo-voucher-list').data('offer-description')
1063      );
1064      $('.offer-detail-date').text(
1065        $(this).closest('.promo-voucher-list').data('offer-date')
1066      );
1067      $('.offer-details-container').show();
1068    });
1069
1070    $('.offer-action-reset').on('click', function () {
1071      new bootstrap.Modal($('#fetch-offer-popup')).hide();
1072      $('.offer-details-container').hide();
1073      $('#offer-section').show();
1074      $('.offers-list .offers-list-data').empty();
1075      $('.offersDropdown .dropdown-content').hide();
1076    });
1077
1078    $('.close-offer-details').on('click', function () {
1079      $('.offer-details-container').hide();
1080      $('#offer-section').show();
1081    });
1082
1083    $('.see-offers').on('click', function () {
1084      new bootstrap.Modal($('#fetch-offer-popup')).show();
1085      $('.react-popover').fadeOut();
1086      retrieveAllLines();
1087    });
1088
1089    $('.reload-offer').on('click', function () {
1090      retrieveAllLines();
1091    });
1092
1093    $('.offer-redirect').on('click', function () {
1094      console.log('matchedCTA', matchedCTA);
1095      if (!matchedCTA) {
1096        $('.offer-details-container').hide();
1097        $('#offer-section').show();
1098        return;
1099      }
1100      window.location.href = matchedCTA.ctaURL;
1101    });
1102
1103    $('.login-success-action').on('click', function () {
1104      $('.login-action-reset').click();
1105      new bootstrap.Modal($('#fetch-offer-popup')).show();
1106      retrieveAllLines();
1107    });
1108
1109    //  Man Icon Changes End -WEB-9619
1110  });
1111})(jQuery);

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.