PageSourceSearch

https://www.thyesengplumbing.com/account/register

html thyesengplumbing.com collected 2026-10-06 19:08:15 UTC 106,670 bytes, 3,464 lines download raw bytes

1<!doctype html>
2<!--[if lt IE 7]><html class="no-js lt-ie9 lt-ie8 lt-ie7" lang="en"> <![endif]-->
3<!--[if IE 7]><html class="no-js lt-ie9 lt-ie8" lang="en"> <![endif]-->
4<!--[if IE 8]><html class="no-js lt-ie9" lang="en"> <![endif]-->
5<!--[if IE 9 ]><html class="ie9 no-js"> <![endif]-->
6<!--[if (gt IE 9)|!(IE)]><!--> <html class="no-js"> <!--<![endif]-->
7<head>
8
9  <!-- Basic page needs ================================================== -->
10  <meta charset="utf-8">
11  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
12
13  
14  <link rel="icon" href="https://cdn.store-assets.com/s/39481/f/1112552.png" />
15  
16
17  <!-- Title and description ================================================== -->
18  <title>
19  Login &ndash; TS Bathroom Mall - Your One Stop Bathroom Solutions Need
20  </title>
21
22  
23
24  <!-- Social meta ================================================== -->
25  
26
27  <meta property="og:type" content="website">
28  <meta property="og:title" content="Login">
29  <meta property="og:url" content="https://www.thyesengplumbing.com/account/login">
30  
31  <meta property="og:image" content="https://cdn.store-assets.com/s/39481/f/1112531.png?width=350&format=webp">
32  <meta property="og:image:secure_url" content="https://cdn.store-assets.com/s/39481/f/1112531.png?width=350&format=webp">
33  
34
35
36<meta property="og:description" content="Shop online for bathroom needs. Brands like Johnson Suisse, Inno, AIMER, Techplas and etc. Choices from stainless steel tank, WC, basin, towel rack, water filter, water filter catridge, poly tank (HDPE tank), solar panel tank, solar water heater system, electric water heater, plumbing, johnson suisse, Inno, econax, aimer, zelia, buteline, PE Tank, stainless steel sink, sink, york, stainless steel fitting, bathtub, hansen, bina UPVC pipe">
37<meta property="og:site_name" content="TS Bathroom Mall - Your One Stop Bathroom Solutions Need">
38
39
40
41  <meta name="twitter:card" content="summary">
42
43
44
45  <meta name="twitter:site" content="@">
46
47
48
49
50
51  <!-- Helpers ================================================== -->
52  <link rel="canonical" href="https://www.thyesengplumbing.com/account/login">
53  <meta name="viewport" content="width=device-width,initial-scale=1">
54  <meta name="theme-color" content="">
55
56  <!-- CSS ================================================== -->
57  <link href="https://store-themes.easystore.co/39481/themes/336/assets/timber.css?t=1787072412" rel="stylesheet" type="text/css" media="screen" />
58  <link href="https://store-themes.easystore.co/39481/themes/336/assets/theme.css?t=1787072412" rel="stylesheet" type="text/css" media="screen" />
59
60  
61
62
63
64
65  
65<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js" type="text/javascript" ></script>
65
66  <!-- Header hook for plugins ================================================== -->
67  
68<!-- ScriptTags -->
69<script>window.__st={p: "customers",cid: null,cem: null,cph: null,cfn: null,cln: null,cge: null,cdb: null,ccc: null};</script>
69<script src='/assets/events.js'></script>
69<script>(function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(d.getElementById(id))return;js=d.createElement(s);js.id=id;js.src='https://connect.facebook.net/en_US/sdk/xfbml.customerchat.js#xfbml=1&version=v6.0&autoLogAppEvents=1';fjs.parentNode.insertBefore(js,fjs);}(document,'script','facebook-jssdk'));</script>
69<script>(function(){function asyncLoad(){var urls=['/assets/facebook-pixel.js?v=1.2.1605084597','/assets/traffic.js?v=1','https://apps.easystore.co/zopim-live-chat/script.js?shop=lcw8807257666.easy.co','https://apps.easystore.co/marketplace/shopee-malaysia/script.js?shop=lcw8807257666.easy.co'];for(var i=0;i<urls.length;i++){var s=document.createElement('script');s.type='text/javascript';s.async=true;s.src=urls[i];var x=document.getElementsByTagName('script')[0];x.parentNode.insertBefore(s, x);}}window.attachEvent ? window.attachEvent('onload', asyncLoad) : window.addEventListener('load', asyncLoad, false);})();</script>
69
70<!-- /ScriptTags -->
71
72
73  
74<!--[if lt IE 9]>
75<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.2/html5shiv.min.js" type="text/javascript" ></script>
vendor: 2 bytes, line 75
75
76<script src="https://store-themes.easystore.co/39481/themes/336/assets/respond.min.js?t=1787072412" type="text/javascript" ></script>
76
77<link href="https://store-themes.easystore.co/39481/themes/336/assets/respond-proxy.html" id="respond-proxy" rel="respond-proxy" />
78<link href="//www.thyesengplumbing.com/search?q=dba8240407e3ea0f0b023a2030b01159" id="respond-redirect" rel="respond-redirect" />
79<script src="//www.thyesengplumbing.com/search?q=dba8240407e3ea0f0b023a2030b01159" type="text/javascript"></script>
79
80<![endif]-->
81
82
83
84  
84<script src="https://store-themes.easystore.co/39481/themes/336/assets/modernizr.min.js?t=1787072412" type="text/javascript" ></script>
84
85
86  
87  
88    
88<script src="/assets/shop_common.js" type="text/javascript" ></script>
88
89    
89<script src="/assets/customer_area.js" type="text/javascript" ></script>
89
90  
91  
91<script>
92  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
93  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
94  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
95  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
96
97  ga('create', '', 'auto','myTracker');
98  ga('myTracker.send', 'pageview');
99
100  </script>
100
101  
102<!-- Snippet:global/head: Google Search Console -->
103<meta name="google-site-verification" content="RR2uZSdoCkvDnFqgezIYJ0UpVLFx8C3FOnY9Qbphxw8" />
104<!-- /Snippet -->
105
106<!-- Snippet:global/head: Shopee Malaysia -->
107<link type="text/css" rel="stylesheet" href="https://apps.easystore.co/assets/css/marketplace/main.css?v1.71">
108<!-- /Snippet -->
109
110</head>
111
112<body id="login" class="template-customers" >
113  
114<!-- Snippet:global/body_start: Announcement Bar -->
115<style type="text/css">
116  body {
117    background-position: top 45px center;
118  }
119
120  div#announcement-bar-top {
121    height: 45px;
122  }
123
124  span .announcement-close-button {
125    text-align: center;
126    display: -webkit-flex;
127    display: -moz-flex;
128    display: -ms-flex;
129    display: -o-flex;
130    display: inline-block;
131    align-items: center;
132    flex-wrap: wrap;
133    justify-content: center;
134  }
135
136  #announcementBar_countdown:empty {
137    display: none;
138  }
139
140
141  .announcementBar_timer {
142    margin: 5px 0px;
143  }
144
145  .announcementBar_timer.style_1,
146  .announcementBar_timer.style_2 {
147    display: -webkit-inline-flex;
148    display: -moz-inline-flex;
149    display: -ms-inline-flex;
150    display: -o-inline-flex;
151    display: inline-flex;
152    align-items: center;
153    padding: 5px 8px;
154    margin: 3px 0px 3px 10px;
155    border-radius: 8px;
156    font-weight: bold;
157  }
158
159  .announcementBar_timer.style_1>div,
160  .announcementBar_timer.style_2>div {
161    margin: 0 5px;
162    line-height: 1;
163  }
164
165  .announcementBar_timer.style_1 small,
166  .announcementBar_timer.style_2 small {
167    display: block;
168    font-size: 55%;
169    line-height: 1;
170  }
171
172  .announcementBar_timer.style_2 {
173    flex-direction: row;
174  }
175
176  .announcementBar_timer.style_2>div {
177    position: relative;
178  }
179
180  .announcementBar_timer.style_2>div:not(:last-child):after {
181    position: absolute;
182    content: ':';
183    top: 0;
184    right: 0;
185    margin-right: -7px;
186  }
187
188  .announcementBar_timer.style_3 {
189    display: -webkit-inline-flex;
190    display: -moz-inline-flex;
191    display: -ms-inline-flex;
192    display: -o-inline-flex;
193    display: inline-flex;
194    align-items: center;
195    border-radius: 5px;
196    padding: 5px 5px;
197    margin-left: 10px;
198    font-weight: bold;
199  }
200
201  .announcementBar_timer.style_3>div {
202    margin: 0 3px;
203    line-height: 1;
204  }
205
206  .announcementBar_timer.style_3 small {
207    font-weight: bold;
208    line-height: 1.1;
209    font-size: 65%;
210  }
211
212  .announcement-close-button {
213    position: relative;
214    width: 24px;
215    height: 24px;
216    opacity: 1;
217    background: #000;
218    border-radius: 50%;
219    cursor: pointer;
220    top: 30%;
221  }
222
223  .announcement-close-button:hover {
224    opacity: 0.6;
225  }
226
227  .announcement-close-button:before,
228  .announcement-close-button:after {
229    position: absolute;
230    left: 11px;
231    top: 5px;
232    content: ' ';
233    height: 14px;
234    width: 2px;
235    background-color: #fff;
236    border-radius: 3px;
237  }
238
239  .announcement-close-button:before {
240    transform: rotate(45deg);
241  }
242
243  .announcement-close-button:after {
244    transform: rotate(-45deg);
245  }
246
247  .announcement-bar-button {
248    padding: 4px 8px;
249    vertical-align: baseline;
250    border-radius: 5px;
251    margin-left: 10px;
252    opacity: 1;
253    line-height: 1.1;
254    text-decoration: none;
255    display: inline-block;
256    font-weight: 500;
257  }
258
259  .announcement-bar-button:hover {
260    opacity: 0.8;
261  }
262
263  .announcement-bar-direction-button {
264    cursor: pointer;
265    padding: 0px 8px;
266  }
267
268  .announcement-bar-direction-button:hover {
269    opacity: 0.8;
270  }
271
272  slider-announcement-bar-app {
273    display: block;
274    text-align: center;
275    margin: 0px;
276    padding: 6px 10px;
277    border-top: 1px dashed transparent;
278    border-bottom: 1px dashed transparent;
279    width: 100%;
280  }
281
282  slider-announcement-bar-app ul::-webkit-scrollbar {
283    height: 0.4rem;
284    width: 0.4rem;
285    display: none;
286  }
287
288  slider-announcement-bar-app ul {
289    position: relative;
290    display: flex;
291    overflow-x: auto;
292    -ms-overflow-style: none;
293    /* IE 11 */
294    scrollbar-width: none;
295    /* Firefox 64 */
296    scroll-snap-type: x mandatory;
297    scroll-behavior: smooth;
298    /* scroll-padding-left: 1rem; */
299    -webkit-overflow-scrolling: touch;
300    margin-bottom: 0;
301    padding: 0;
302    list-style: none;
303    align-items: center;
304  }
305
306  slider-announcement-bar-app ul li {
307    width: 100vw;
308    scroll-snap-align: start;
309    flex-shrink: 0;
310  }
311</style>
312
313<input type="hidden" id="total_announcement_left" name="total_announcement_left" value="1">
314<input type="hidden" id="locale" name="locale" value="en_US">
315<div id="announcement-bar-top">&nbsp;</div>
316
317<slider-announcement-bar-app id="announcement-bar" name="announcement-bar" style="
318    border: unset;
319    padding: 4px 0px;
320    margin: 0px;
321    z-index:2999;
322    background:rgb(233, 69, 69);
323    color:rgb(255, 255, 255);
324    position: fixed; top: 0;
325">
326
327  <div style="
328    display: flex;
329    justify-content: space-between;
330    align-items: center;
331    padding: 0px 0px;
332    border-top: 0px;
333    border-bottom: 0px;
334    border-color: transparent;
335  ">
336    <div style="height: 24px;">
337          </div>
338
339    <ul style="flex-grow: 2; margin: 0px;">
340            <li id="announcement_bar_0" style="
341          display: flex;
342          justify-content: center;
343          align-items: center;
344          flex-wrap: wrap;
345          margin: 0px;
346          width: 100%;
347          word-wrap: break-word;
348        ">
349        For long pipe, sanitary wares, water tank or septic tank order kindly chat with us and let us know your quantity and location at 0129838831 before place order to determine shipping fees
350                        <input type="hidden" id="expired_at_0" name="expired_at_0" value="">
351      </li>
352          </ul>
353
354    <div style="display: flex;">
355                  <span id="announcement-close-button" name="announcement-close-button" class="announcement-close-button" style="margin-right: 10px;"></span>
356          </div>
357  </div>
358
359
360</slider-announcement-bar-app>
361
362<script>
363  (function() {
364
365    const loadScript = function(url, callback) {
366      const script = document.createElement("script");
367      script.type = "text/javascript";
368      // If the browser is Internet Explorer.
369      if (script.readyState) {
370        script.onreadystatechange = function() {
371          if (script.readyState == "loaded" || script.readyState == "complete") {
372            script.onreadystatechange = null;
373            callback();
374          }
375        };
376        // For any other browser.
377      } else {
378        script.onload = function() {
379          callback();
380        };
381      }
382      script.src = url;
383      document.getElementsByTagName("head")[0].appendChild(script);
384    };
385
386    const announcementBarAppJS = function($) {
387
388      $('#announcement-bar-top').css('height', $('#announcement-bar').outerHeight());
389
390      $('#announcement-close-button').on('click', function() {
391        $('#announcement-bar, #announcement-bar-top').animate({
392          marginTop: '-=' + $('#announcement-bar').outerHeight() + 'px'
393        }, 200, 'linear');
394      });
395    }
396
397    if (typeof jQuery === 'undefined') {
398      loadScript('//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js', function() {
399        jQuery = jQuery.noConflict(true);
400        announcementBarAppJS(jQuery);
401      });
402    } else {
403      announcementBarAppJS(jQuery);
404    }
405
406  })();
407
408  setInterval(function() {
409    const total_announcement = "1"
410    var total_announcement_left = $("#total_announcement_left").val();
411
412    for (let i = 0; i <= total_announcement; i++) {
413      const startDate = new Date();
414      const endDateStr = $("#expired_at_" + i).val();
415      const endDate = endDateStr == undefined ? new Date() : new Date(endDateStr.replace(/-/g, "/"));
416      const seconds = (endDate.getTime() - startDate.getTime()) / 1000;
417
418      const days = parseInt(seconds / 86400);
419      const hours = parseInt((seconds % 86400) / 3600);
420      const mins = parseInt((seconds % 86400 % 3600) / 60);
421      const secs = parseInt((seconds % 86400 % 3600) % 60);
422
423      // use to translate countdown unit
424      // (translate based on the preferred language when save announcement bar setting)
425      String.prototype.translate = function() {
426        try {
427          if ($("#locale").val() == "zh_TW") {
428            if (this.toString() === 'day') {
429              return "天";
430            }
431            if (this.toString() === 'hour') {
432              return "小時";
433            }
434            if (this.toString() === 'min') {
435              return "分鐘";
436            }
437            if (this.toString() === 'sec') {
438              return "秒";
439            }
440          } else {
441            if (this.toString() === 'day') {
442              if (days > 0) {
443                return "Days";
444              } else {
445                return "Day";
446              }
447            } else if (this.toString() === 'hour') {
448              if (hours > 0) {
449                return "Hours";
450              } else {
451                return "Hour";
452              }
453            } else if (this.toString() === 'min') {
454              if (mins > 0) {
455                return "Mins";
456              } else {
457                return "Min";
458              }
459            } else if (this.toString() === 'sec') {
460              if (secs > 0) {
461                return "Secs";
462              } else {
463                return "Sec";
464              }
465            }
466          }
467        } catch (error) {
468          console.log("Some errors heres", error);
469        }
470      };
471
472      const announcementBar_countdown = document.getElementById("announcementBar_countdown_" + i);
473      if (announcementBar_countdown && seconds > 0) {
474
475        $(announcementBar_countdown).show()
476        announcementBar_countdown.innerHTML = `
477          <div>
478            ${days} <small>${'day'.translate()}</small>
479          </div>
480          <div>
481            ${hours} <small>${'hour'.translate()}</small>
482          </div>
483          <div>
484            ${mins} <small>${'min'.translate()}</small>
485          </div>
486          <div>
487            ${secs} <small>${'sec'.translate()}</small>
488          </div>
489        `;
490        $('#announcement-bar-top').css('height', $('#announcement-bar').outerHeight());
491
492
493      } else if (announcementBar_countdown && seconds <= 0) {
494        $("#announcement_bar_" + i).remove();
495        total_announcement_left = total_announcement_left - 1;
496        $("#total_announcement_left").val(total_announcement_left);
497      }
498    }
499
500    showOrHide(total_announcement_left);
501  }, 1000);
502
503
504  function showOrHide(total_announcement_left) {
505    if (total_announcement_left <= 1) {
506      $("#previous-announcement-bar-button,#next-announcement-bar-button").hide();
507    } else {
508      $("#previous-announcement-bar-button,#next-announcement-bar-button").show();
509    }
510
511    if (total_announcement_left == 0) {
512      $("#announcement-close-button").hide();
513      $("#announcement-bar").hide();
514      $('#announcement-bar-top').hide();
515    }
516  };
517
518  let annoucementBarAutoMoveInterval = '';
519  class AnnouncementBarAppSlider extends HTMLElement {
520    constructor() {
521      super();
522      this.slider = this.querySelector('ul');
523      this.sliderItems = this.querySelectorAll('li');
524      this.prevButton = this.querySelector('a[name="previous"]');
525      this.nextButton = this.querySelector('a[name="next"]');
526
527      if (!this.slider || !this.nextButton) return;
528
529      const resizeObserver = new ResizeObserver(entries => this.initPages());
530      resizeObserver.observe(this.slider);
531
532      this.slider.addEventListener('scroll', this.update.bind(this));
533      this.prevButton.addEventListener('click', this.onButtonClick.bind(this));
534      this.nextButton.addEventListener('click', this.onButtonClick.bind(this));
535
536
537    }
538
539    initPages() {
540      const sliderItemsToShow = Array.from(this.sliderItems).filter(element => element.clientWidth > 0);
541      this.sliderLastItem = sliderItemsToShow[sliderItemsToShow.length - 1];
542      if (sliderItemsToShow.length === 0) return;
543      this.slidesPerPage = Math.floor(this.slider.clientWidth / sliderItemsToShow[0].clientWidth);
544      this.totalPages = sliderItemsToShow.length - this.slidesPerPage + 1;
545      this.update();
546      let self = this
547      var total_announcement_left = $("#total_announcement_left").val();
548      annoucementBarAutoMoveInterval = setInterval(function() {
549        if (total_announcement_left > 1) {
550          self.moveSlide('next')
551        }
552      }, 5000)
553    }
554
555    update() {
556      this.currentPage = Math.round(this.slider.scrollLeft / this.sliderLastItem.clientWidth) + 1;
557    }
558
559    onButtonClick(event) {
560      event.preventDefault();
561      let self = this;
562      self.moveSlide(event.currentTarget.name);
563    }
564
565
566    moveSlide(move_to) {
567
568      clearInterval(annoucementBarAutoMoveInterval);
569      let self = this;
570      annoucementBarAutoMoveInterval = setInterval(function() {
571        self.moveSlide('next');
572      }, 5000)
573
574      if (move_to === 'previous' && this.currentPage === 1) {
575        this.slider.scrollTo({
576          left: this.sliderLastItem.clientWidth * (this.totalPages - 1)
577        });
578      } else if (move_to === 'next' && this.currentPage === this.totalPages) {
579        this.slider.scrollTo({
580          left: 0
581        });
582      } else {
583        const slideScrollPosition = move_to === 'next' ? this.slider.scrollLeft + this.sliderLastItem
584          .clientWidth : this.slider.scrollLeft - this.sliderLastItem.clientWidth;
585        this.slider.scrollTo({
586          left: slideScrollPosition
587        });
588      }
589    }
590
591  }
592
593  customElements.define('slider-announcement-bar-app', AnnouncementBarAppSlider);
594</script>
594
595
596<!-- /Snippet -->
597
598<!-- Snippet:global/body_start: Console Extension -->
599<div id='es_console' style='display: none;'>39481</div>
600<!-- /Snippet -->
601
602
603  <style>
604  .search-modal__form{
605    position: relative;
606  }
607  
608  .dropdown-wrapper {
609    position: relative;
610  }
611  
612  .dropdown-wrapper:hover .dropdown {
613    display: block;
614  }
615  
616  .dropdown {
617    display: none;
618    position: absolute;
619    top: 100%;
620    left: -20px;
621    width: 100%;
622    padding: 8px 0;
623    margin: 0;
624    background-color: #fff;
625    z-index: 1000;
626    border-radius: 5px;
627    border: 1px solid rgba(var(--color-foreground), 1);
628    border-top: none;
629    overflow-x: hidden;
630    overflow-y: auto;
631    max-height: 350px;
632    min-width: 150px;
633    box-shadow: 0 0 5px rgba(0,0,0,0.1);
634  }
635    
636  .dropdown li,.dropdown a{
637    display: block;
638  }
639  .dropdown a{
640    text-decoration: none;
641    padding: 2px 10px;
642    color: #000 !important;
643  }
644  
645  .dropdown-item {
646    padding: 0.4rem 2rem;
647    cursor: pointer;
648    line-height: 1.4;
649    overflow: hidden;
650    text-overflow: ellipsis;
651    white-space: nowrap;
652  }
653  
654  .dropdown-item:hover{
655    background-color: #f3f3f3;
656  }
657  
658  .search__input.is-focus{
659    border-radius: 15px;
660    border-bottom-left-radius: 0;
661    border-bottom-right-radius: 0;
662    border: 1px solid rgba(var(--color-foreground), 1);
663    border-bottom: none;
664    box-shadow: none;
665  }
666  
667  .clear-all {
668    text-align: right;
669    padding: 0 2rem 0.2rem;
670    line-height: 1;
671    font-size: 70%;
672    margin-bottom: -2px;
673  }
674  
675  .clear-all:hover{
676    background-color: #fff;
677  }
678  
679  .referral-notification {
680    position: absolute;
681    top: 100%;
682    right: -12px;
683    background: white;
684    border: 1px solid #e0e0e0;
685    border-radius: 8px;
686    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
687    width: 280px;
688    z-index: 1000;
689    padding: 16px;
690    margin-top: 8px;
691    font-size: 14px;
692    line-height: 1.4;
693  }
694  
695  .referral-notification::before {
696    content: '';
697    position: absolute;
698    top: -8px;
699    right: 20px;
700    width: 0;
701    height: 0;
702    border-left: 8px solid transparent;
703    border-right: 8px solid transparent;
704    border-bottom: 8px solid white;
705  }
706  
707  .referral-notification::after {
708    content: '';
709    position: absolute;
710    top: -9px;
711    right: 20px;
712    width: 0;
713    height: 0;
714    border-left: 8px solid transparent;
715    border-right: 8px solid transparent;
716    border-bottom: 8px solid #e0e0e0;
717  }
718  
719  .referral-notification h4 {
720    margin: 0 0 8px 0;
721    color: #2196F3;
722    font-size: 16px;
723    font-weight: 600;
724  }
725  
726  .referral-notification p {
727    margin: 0 0 12px 0;
728    color: #666;
729  }
730  
731  .referral-notification .referral-code {
732    background: #f5f5f5;
733    padding: 8px;
734    border-radius: 4px;
735    font-family: monospace;
736    font-size: 13px;
737    text-align: center;
738    margin: 8px 0;
739    border: 1px solid #ddd;
740  }
741  
742  .referral-notification .close-btn {
743    position: absolute;
744    top: 8px;
745    right: 8px;
746    background: none;
747    border: none;
748    font-size: 18px;
749    color: #999;
750    cursor: pointer;
751    padding: 0;
752    width: 20px;
753    height: 20px;
754    line-height: 1;
755  }
756  
757  .referral-notification .close-btn:hover {
758    color: #333;
759  }
760  
761  .referral-notification .action-btn {
762    background: #2196F3;
763    color: white;
764    border: none;
765    padding: 8px 16px;
766    border-radius: 4px;
767    cursor: pointer;
768    font-size: 12px;
769    margin-right: 8px;
770    margin-top: 8px;
771  }
772  
773  .referral-notification .action-btn:hover {
774    background: #1976D2;
775  }
776  
777  .referral-notification .dismiss-btn {
778    background: transparent;
779    color: #666;
780    border: 1px solid #ddd;
781    padding: 8px 16px;
782    border-radius: 4px;
783    cursor: pointer;
784    font-size: 12px;
785    margin-top: 8px;
786  }
787  
788  .referral-notification .dismiss-btn:hover {
789    background: #f5f5f5;
790  }
791  .referral-modal__dialog {
792    transform: translate(-50%, 0);
793    transition: transform var(--duration-default) ease, visibility 0s;
794    z-index: 10000;
795    position: fixed;
796    top: 20vh;
797    left: 50%;
798    width: 100%;
799    max-width: 350px;
800    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
801    border-radius: 12px;
802    background-color: #fff;
803    color: #000;
804    padding: 20px;
805    text-align: center;
806  }
807  .modal-overlay.referral-modal-overlay {
808    position: fixed;
809    top: 0;
810    left: 0;
811    width: 100%;
812    height: 100%;
813    background-color: rgba(0, 0, 0, 0.7);
814    z-index: 2001;
815    display: block;
816    opacity: 1;
817    transition: opacity var(--duration-default) ease, visibility 0s;
818  }
819</style>
820
821<div class="header-bar">
822  <div class="wrapper medium-down--hide">
823    <div class="large--display-table">
824
825      <div class="header-bar__left large--display-table-cell">
826
827        
828
829        
830
831        
832          
833            <div class="header-bar__module header-bar__search">
834              
835  <form action="/search" method="get" class="header-bar__search-form clearfix" role="search">
836    
837    <button type="submit" class="btn icon-fallback-text header-bar__search-submit">
838      <span class="icon icon-search" aria-hidden="true"></span>
839      <span class="fallback-text">Search</span>
840    </button>
841    <input type="search" name="q" value="" aria-label="Search" class="header-bar__search-input" placeholder="Search" autocomplete="off">
842    <div class="dropdown" id="searchDropdown"></div>
843    <input type="hidden" name="search_history" id="search_history">
844  </form>
845
846
847<script>
848  var _search_history_listings = ""
849  if(_search_history_listings != "") localStorage.setItem('searchHistory', JSON.stringify(_search_history_listings));
850
851  function clearAll() {
852    localStorage.removeItem('searchHistory');
853  
854    var customer = "";
855    if(customer) {
856      // Your logic to clear all data or call an endpoint
857      fetch('/account/search_histories', {
858          method: 'DELETE',
859          headers: {
860            "Content-Type": "application/json",
861            "X-Requested-With": "XMLHttpRequest"
862          },
863          body: JSON.stringify({
864            _token: "CfeJEOxOvhUxEgvKeM0ruK5x6bNBCUp3YcMNjaAT"
865          }),
866      })
867      .then(response => response.json())
868    }
869  }
870  // End - store view history in local storage
871  
872  // search history dropdown  
873  var searchInputs = document.querySelectorAll('input[type=search]');
874  
875  if(searchInputs.length > 0) {
876    
877    searchInputs.forEach((searchInput)=>{
878    
879      searchInput.addEventListener('focus', function() {
880        var searchDropdown = searchInput.closest('form').querySelector('#searchDropdown');
881        searchDropdown.innerHTML = ''; // Clear existing items
882  
883        // retrieve data from local storage
884        var searchHistoryData = JSON.parse(localStorage.getItem('searchHistory')) || [];
885  
886        // Convert JSON to string
887        var search_history_json = JSON.stringify(searchHistoryData);
888  
889        // Set the value of the hidden input
890        searchInput.closest('form').querySelector("#search_history").value = search_history_json;
891  
892        // create dropdown items
893        var clearAllItem = document.createElement('div');
894        clearAllItem.className = 'dropdown-item clear-all';
895        clearAllItem.textContent = 'Clear';
896        clearAllItem.addEventListener('click', function() {
897            clearAll();
898            searchDropdown.style.display = 'none';
899            searchInput.classList.remove('is-focus');
900        });
901        searchDropdown.appendChild(clearAllItem);
902  
903        // create dropdown items
904        searchHistoryData.forEach(function(item) {
905          var dropdownItem = document.createElement('div');
906          dropdownItem.className = 'dropdown-item';
907          dropdownItem.textContent = item.term;
908          dropdownItem.addEventListener('click', function() {
909            searchInput.value = item.term;
910            searchDropdown.style.display = 'none';
911          });
912          searchDropdown.appendChild(dropdownItem);
913        });
914  
915        if(searchHistoryData.length > 0){
916          // display the dropdown
917          searchInput.classList.add('is-focus');
918          document.body.classList.add('search-input-focus');
919          searchDropdown.style.display = 'block';
920        }
921      });
922  
923      searchInput.addEventListener("focusout", (event) => {
924        var searchDropdown = searchInput.closest('form').querySelector('#searchDropdown');
925        searchInput.classList.remove('is-focus');
926        searchDropdown.classList.add('transparent');
927        setTimeout(()=>{
928          searchDropdown.style.display = 'none';
929          searchDropdown.classList.remove('transparent');
930          document.body.classList.remove('search-input-focus');
931        }, 400);
932      });
933    })
934  }
935  // End - search history dropdown
936</script>
936
937            </div>
938          
939        
940
941      </div>
942
943      <div class="header-bar__right large--display-table-cell">
944        
945          <ul class="header-bar__module header-bar__module--list" style="position: relative;">
946            
947              
948              
949                <li>
950                  <a href="/account/login">Log in</a>
951                </li><li>OR</li>
952                
953              
954              
955                <li>
956                <a href="/account/register">Create account</a>
957                </li>
958                
959              
960
961              <!-- Referral Notification Popup for Desktop -->
962              <div id="referralNotification" class="referral-notification" style="display: none;">
963                <button class="close-btn" onclick="dismissReferralNotification()">&times;</button>
964                <div style="text-align: center; margin-bottom: 16px;">
965                  <div style="width: 100px; height: 100px; margin: 0 auto;">
966                    <img src="https://resources.easystore.co/storefront/icons/channels/vector_referral_program.svg">
967                  </div>
968                </div>
969                <p id="referralSignupMessage" style="text-align: center; font-size: 14px; color: #666; margin: 0 0 20px 0;">
970                  Your friend gifted you   credit! Sign up now to redeem.
971                </p>
972                <div style="text-align: center;">
973                  <button class="btn" onclick="goToSignupPage()" style="width: 100%; color: #fff;">
974                    Sign Up
975                  </button>
976                </div>
977              </div>
978            
979          </ul>
980        
981        
982
983
984
985        <div class="header-bar__module">
986          <span class="header-bar__sep" aria-hidden="true"></span>
987          <a href="/cart" class="cart-page-link">
988            <span class="icon icon-cart header-bar__cart-icon" aria-hidden="true"></span>
989          </a>
990        </div>
991
992        <div class="header-bar__module">
993          
994          <a href="/cart" class="cart-page-link">
995            Cart<span class="hidden-count">:</span>
996            <span class="cart-count header-bar__cart-count hidden-count">0</span>
997          </a>
998        </div>
999
1000        
1001          
1002        
1003
1004      </div>
1005    </div>
1006  </div>
1007  <div class="wrapper large--hide" style="padding: 5px 30px 0;">
1008    <button type="button" class="mobile-nav-trigger" id="MobileNavTrigger">
1009      <span class="icon icon-hamburger" aria-hidden="true"></span>
1010      Menu
1011    </button>
1012
1013    
1014      
1015        <!-- Referral Notification Modal for Mobile -->
1016        <details-modal class="referral-modal" id="referralMobileModal">
1017          <details>
1018            <summary class="referral-modal__toggle" aria-haspopup="dialog" aria-label="Open referral modal" style="display: none;">
1019            </summary>
1020            <div class="modal-overlay referral-modal-overlay"></div>
1021            <div class="referral-modal__dialog" role="dialog" aria-modal="true" aria-label="Referral notification">
1022              <div class="referral-modal__content">
1023                <button type="button" class="modal__close-button" aria-label="Close" onclick="closeMobileReferralModal()" style="position: absolute; top: 16px; right: 16px; background: none; border: none; font-size: 24px; cursor: pointer;">
1024                  &times;
1025                </button>
1026
1027                <div style="margin-bottom: 24px;">
1028                  <div style="width: 120px; height: 120px; margin: 0 auto 20px;">
1029                    <img src="https://resources.easystore.co/storefront/icons/channels/vector_referral_program.svg" style="width: 100%; height: 100%;">
1030                  </div>
1031                </div>
1032
1033                <p id="referralSignupMessageMobile" style="font-size: 16px; color: #333; margin: 0 0 30px 0; line-height: 1.5;">
1034                  Your friend gifted you   credit! Sign up now to redeem.
1035                </p>
1036
1037                <button type="button" class="btn" onclick="goToSignupPageFromMobile()" style="width: 100%; color: #fff;">
1038                  Sign Up
1039                </button>
1040              </div>
1041            </div>
1042          </details>
1043        </details-modal>
1044      
1045    
1046   
1047
1048    <a href="/cart" class="cart-page-link mobile-cart-page-link">
1049      <span class="icon icon-cart header-bar__cart-icon" aria-hidden="true"></span>
1050      Cart
1051      <span class="cart-count  hidden-count">0</span>
1052    </a>
1053     <div class="mobile-cart-page-link" style="margin-right: 20px;">
1054      
1055
1056
1057
1058    </div>
1059  </div>
1060  <ul id="MobileNav" class="mobile-nav large--hide">
1061  <li class="mobile-nav__link">
1062    
1063      <div class="header-bar__module header-bar__search">
1064        
1065  <form action="/search" method="get" class="header-bar__search-form clearfix" role="search">
1066    
1067    <button type="submit" class="btn icon-fallback-text header-bar__search-submit">
1068      <span class="icon icon-search" aria-hidden="true"></span>
1069      <span class="fallback-text">Search</span>
1070    </button>
1071    <input type="search" name="q" value="" aria-label="Search" class="header-bar__search-input" placeholder="Search" autocomplete="off">
1072    <div class="dropdown" id="searchDropdown"></div>
1073    <input type="hidden" name="search_history" id="search_history">
1074  </form>
1075
1076
1077<script>
1078  var _search_history_listings = ""
1079  if(_search_history_listings != "") localStorage.setItem('searchHistory', JSON.stringify(_search_history_listings));
1080
1081  function clearAll() {
1082    localStorage.removeItem('searchHistory');
1083  
1084    var customer = "";
1085    if(customer) {
1086      // Your logic to clear all data or call an endpoint
1087      fetch('/account/search_histories', {
1088          method: 'DELETE',
1089          headers: {
1090            "Content-Type": "application/json",
1091            "X-Requested-With": "XMLHttpRequest"
1092          },
1093          body: JSON.stringify({
1094            _token: "CfeJEOxOvhUxEgvKeM0ruK5x6bNBCUp3YcMNjaAT"
1095          }),
1096      })
1097      .then(response => response.json())
1098    }
1099  }
1100  // End - store view history in local storage
1101  
1102  // search history dropdown  
1103  var searchInputs = document.querySelectorAll('input[type=search]');
1104  
1105  if(searchInputs.length > 0) {
1106    
1107    searchInputs.forEach((searchInput)=>{
1108    
1109      searchInput.addEventListener('focus', function() {
1110        var searchDropdown = searchInput.closest('form').querySelector('#searchDropdown');
1111        searchDropdown.innerHTML = ''; // Clear existing items
1112  
1113        // retrieve data from local storage
1114        var searchHistoryData = JSON.parse(localStorage.getItem('searchHistory')) || [];
1115  
1116        // Convert JSON to string
1117        var search_history_json = JSON.stringify(searchHistoryData);
1118  
1119        // Set the value of the hidden input
1120        searchInput.closest('form').querySelector("#search_history").value = search_history_json;
1121  
1122        // create dropdown items
1123        var clearAllItem = document.createElement('div');
1124        clearAllItem.className = 'dropdown-item clear-all';
1125        clearAllItem.textContent = 'Clear';
1126        clearAllItem.addEventListener('click', function() {
1127            clearAll();
1128            searchDropdown.style.display = 'none';
1129            searchInput.classList.remove('is-focus');
1130        });
1131        searchDropdown.appendChild(clearAllItem);
1132  
1133        // create dropdown items
1134        searchHistoryData.forEach(function(item) {
1135          var dropdownItem = document.createElement('div');
1136          dropdownItem.className = 'dropdown-item';
1137          dropdownItem.textContent = item.term;
1138          dropdownItem.addEventListener('click', function() {
1139            searchInput.value = item.term;
1140            searchDropdown.style.display = 'none';
1141          });
1142          searchDropdown.appendChild(dropdownItem);
1143        });
1144  
1145        if(searchHistoryData.length > 0){
1146          // display the dropdown
1147          searchInput.classList.add('is-focus');
1148          document.body.classList.add('search-input-focus');
1149          searchDropdown.style.display = 'block';
1150        }
1151      });
1152  
1153      searchInput.addEventListener("focusout", (event) => {
1154        var searchDropdown = searchInput.closest('form').querySelector('#searchDropdown');
1155        searchInput.classList.remove('is-focus');
1156        searchDropdown.classList.add('transparent');
1157        setTimeout(()=>{
1158          searchDropdown.style.display = 'none';
1159          searchDropdown.classList.remove('transparent');
1160          document.body.classList.remove('search-input-focus');
1161        }, 400);
1162      });
1163    })
1164  }
1165  // End - search history dropdown
1166</script>
1166
1167      </div>
1168    
1169  </li>
1170  
1171  
1172  
1173  <li class="mobile-nav__link" aria-haspopup="true">
1174    
1175      <a href="/" class="mobile-nav">
1176        Home
1177      </a>
1178    
1179  </li>
1180  
1181  
1182  <li class="mobile-nav__link" aria-haspopup="true">
1183    
1184    
1185      <a href="/collections/all" class="mobile-nav__sublist-trigger">
1186        Products
1187        <span class="icon-fallback-text mobile-nav__sublist-expand">
1188  <span class="icon icon-plus" aria-hidden="true"></span>
1189  <span class="fallback-text">+</span>
1190</span>
1191<span class="icon-fallback-text mobile-nav__sublist-contract">
1192  <span class="icon icon-minus" aria-hidden="true"></span>
1193  <span class="fallback-text">-</span>
1194</span>
1195      </a>
1196      <ul class="mobile-nav__sublist">
1197        <li class="mobile-nav__sublist-link">
1198          <a href="/collections/all" >Products</a>
1199        </li>  
1200        
1201          <li class="mobile-nav__sublist-link">
1202            <a href="/collections/water-pump" >Water Pump</a>
1203          </li>
1204        
1205          <li class="mobile-nav__sublist-link">
1206            <a href="/collections/sanitary-wares" >Sanitary Wares</a>
1207          </li>
1208        
1209          <li class="mobile-nav__sublist-link">
1210            <a href="/collections/plumbing-valve" >Plumbing Valve</a>
1211          </li>
1212        
1213          <li class="mobile-nav__sublist-link">
1214            <a href="/collections/water-tank---sewerage-tank" >Water Tank & Sewerage Tank</a>
1215          </li>
1216        
1217          <li class="mobile-nav__sublist-link">
1218            <a href="/collections/water-heater" >Water Heater</a>
1219          </li>
1220        
1221          <li class="mobile-nav__sublist-link">
1222            <a href="/collections/water-pipes-and-fittings" >Water Pipes and Fittings</a>
1223          </li>
1224        
1225          <li class="mobile-nav__sublist-link">
1226            <a href="/collections/wholesales-price" >Wholesales Price</a>
1227          </li>
1228        
1229      </ul>
1230    
1231  </li>
1232  
1233  
1234  <li class="mobile-nav__link" aria-haspopup="true">
1235    
1236      <a href="/pages/about-us" class="mobile-nav">
1237        About Us
1238      </a>
1239    
1240  </li>
1241  
1242  
1243  <li class="mobile-nav__link" aria-haspopup="true">
1244    
1245      <a href="/pages/catalogue" class="mobile-nav">
1246        Catalogue
1247      </a>
1248    
1249  </li>
1250  
1251
1252  
1253
1254  
1255    
1256      
1257      <li class="mobile-nav__link">
1258        <a href="/account/login">Log in</a>
1259      </li>
1260      
1261      <li class="mobile-nav__link">
1262        <a href="/account/register">Create account</a>
1263      </li>
1264      
1265    
1266  
1267  
1268</ul>
1269</div>
1270
1271<script>
1272  // referral notification popup
1273  const referralMessageTemplate = 'Your friend gifted you __CURRENCY_CODE__ __CREDIT_AMOUNT__ credit! Sign up now to redeem.';
1274  const shopPrefix = 'RM ';
1275
1276  function getCookie(name) {
1277    const value = `; ${document.cookie}`;
1278    const parts = value.split(`; ${name}=`);
1279    if (parts.length === 2) return parts.pop().split(';').shift();
1280    return null;
1281  }
1282
1283  function removeCookie(name) {
1284    document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;
1285  }
1286
1287  function showReferralNotification() {
1288    const referralCode = getCookie('customer_referral_code');
1289    
1290    
1291    const customerReferralCode = null;
1292    
1293    
1294    const activeReferralCode = referralCode || customerReferralCode;
1295    const referralData = JSON.parse(localStorage.getItem('referral_notification_data')) || {};
1296    
1297    if (referralData.timestamp && referralData.expirationDays) {
1298      const expirationTime = referralData.timestamp + (referralData.expirationDays * 24 * 60 * 60 * 1000);
1299      if (Date.now() > expirationTime) {
1300        localStorage.removeItem('referral_notification_data');
1301        return;
1302      }
1303    }
1304    
1305    if (referralData.dismissed) return;
1306    
1307    if (activeReferralCode) {
1308      if (referralData.creditAmount) {
1309        displayReferralNotification(referralData.creditAmount);
1310      } else {
1311        fetchReferralCampaignData(activeReferralCode);
1312      }
1313    }
1314  }
1315    
1316  function fetchReferralCampaignData(referralCode) {
1317    fetch(`/customer/referral_program/campaigns/${referralCode}`)
1318      .then(response => {
1319        if (!response.ok) {
1320          throw new Error('Network response was not ok');
1321        }
1322        return response.json();
1323      })
1324      .then(data => {
1325        let refereeCreditAmount = null;
1326        if (data.data.campaign && data.data.campaign.referral_rules) {
1327          const refereeRule = data.data.campaign.referral_rules.find(rule => 
1328            rule.target_type === 'referee' && 
1329            rule.event_name === 'customer/create' && 
1330            rule.entitlement && 
1331            rule.entitlement.type === 'credit'
1332          );
1333          
1334          if (refereeRule) {
1335            refereeCreditAmount = refereeRule.entitlement.amount;
1336          }
1337        }
1338        
1339        const referralData = JSON.parse(localStorage.getItem('referral_notification_data')) || {};
1340        referralData.creditAmount = refereeCreditAmount;
1341        referralData.dismissed = referralData.dismissed || false;
1342        referralData.timestamp = Date.now();
1343        referralData.expirationDays = 3;
1344        localStorage.setItem('referral_notification_data', JSON.stringify(referralData));
1345        
1346        displayReferralNotification(refereeCreditAmount);
1347      })
1348      .catch(error => {
1349        removeCookie('customer_referral_code');
1350      });
1351  }
1352    
1353  function displayReferralNotification(creditAmount = null) {
1354    const isMobile = innerWidth <= 749;
1355    
1356    if (isMobile) {
1357      const mobileModal = document.querySelector('#referralMobileModal details');
1358      const mobileMessageElement = document.getElementById('referralSignupMessageMobile');
1359      
1360      if (mobileModal && mobileMessageElement) {
1361        if (creditAmount) {
1362          const finalMessage = referralMessageTemplate
1363            .replace('__CREDIT_AMOUNT__', creditAmount)
1364            .replace('__CURRENCY_CODE__', shopPrefix);
1365          
1366          mobileMessageElement.textContent = finalMessage;
1367        }
1368        
1369        mobileModal.setAttribute('open', '');
1370      }
1371    } else {
1372      const notification = document.getElementById('referralNotification');
1373      
1374      if (notification) {
1375        if (creditAmount) {
1376          const messageElement = document.getElementById('referralSignupMessage');
1377          if (messageElement) {
1378            const finalMessage = referralMessageTemplate
1379              .replace('__CREDIT_AMOUNT__', creditAmount)
1380              .replace('__CURRENCY_CODE__', shopPrefix);
1381            
1382            messageElement.textContent = finalMessage;
1383          }
1384        }
1385        
1386        notification.style.display = 'block';
1387      }
1388    }
1389  }
1390
1391  showReferralNotification();
1392
1393  addEventListener('beforeunload', function() {
1394    const referralData = JSON.parse(localStorage.getItem('referral_notification_data')) || {};
1395    
1396    if (referralData.creditAmount !== undefined) {
1397      referralData.creditAmount = null;
1398      localStorage.setItem('referral_notification_data', JSON.stringify(referralData));
1399    }
1400  });
1401
1402  function closeReferralNotification() {
1403    const notification = document.getElementById('referralNotification');
1404    if (notification) {
1405      notification.style.display = 'none';
1406    }
1407  }
1408
1409  function dismissReferralNotification() {
1410    const referralData = JSON.parse(localStorage.getItem('referral_notification_data')) || {};
1411    
1412    referralData.dismissed = true;
1413    referralData.timestamp = referralData.timestamp || Date.now();
1414    referralData.expirationDays = referralData.expirationDays || 3;
1415    
1416    localStorage.setItem('referral_notification_data', JSON.stringify(referralData));
1417    
1418    closeReferralNotification();
1419  }
1420
1421  function goToSignupPage() {
1422    location.href = '/account/register';
1423    dismissReferralNotification();
1424  }
1425
1426  function closeMobileReferralModal() {
1427    const mobileModal = document.querySelector('#referralMobileModal details');
1428    if (mobileModal) {
1429      mobileModal.removeAttribute('open');
1430    }
1431    
1432    const referralData = JSON.parse(localStorage.getItem('referral_notification_data')) || {};
1433    referralData.dismissed = true;
1434    referralData.timestamp = referralData.timestamp || Date.now();
1435    referralData.expirationDays = referralData.expirationDays || 3;
1436    localStorage.setItem('referral_notification_data', JSON.stringify(referralData));
1437  }
1438
1439  function goToSignupPageFromMobile() {
1440    location.href = '/account/register';
1441    closeMobileReferralModal();
1442  }
1443  // End - referral notification popup
1444</script>
1444
1445
1446  <header class="site-header" role="banner">
1447
1448    <div class="wrapper">
1449
1450      
1451
1452      <div class="grid--full">
1453        <div class="grid__item">
1454          
1455            <div class="h1 site-header__logo" itemscope itemtype="http://schema.org/Organization">
1456          
1457            
1458              <a href="/" class="logo-wrapper" itemprop="url">
1459                <img src="https://cdn.store-assets.com/s/39481/f/1112531.png?width=350&format=webp" alt="TS Bathroom Mall - Your One Stop Bathroom Solutions Need" itemprop="logo">
1460              </a>
1461            
1462          
1463            </div>
1464          
1465          
1466            <p class="header-message large--hide">
1467              <small></small>
1468            </p>
1469          
1470        </div>
1471      </div>
1472      <div class="grid--full medium-down--hide">
1473        <div class="grid__item">
1474          
1475<ul class="site-nav" id="AccessibleNav">
1476  
1477    
1478    
1479      <li >
1480        <a href="/"  class="site-nav__link">Home</a>
1481      </li>
1482    
1483  
1484    
1485    
1486      
1487      <li class="site-nav--has-dropdown" aria-haspopup="true">
1488        <a href="/collections/all"  class="site-nav__link">
1489          Products
1490          <span class="icon-fallback-text">
1491            <span class="icon icon-arrow-down" aria-hidden="true"></span>
1492          </span>
1493        </a>
1494        <ul class="site-nav__dropdown">
1495          
1496            
1497            
1498              
1499              <li class="site-nav--has-dropdown">
1500                <a href="/collections/water-pump"  class="site-nav__link">
1501                  Water Pump
1502                  <span class="icon-fallback-text">
1503                    <span class="icon icon-arrow-right" aria-hidden="true"></span>
1504                  </span>
1505                </a>
1506                <ul class="site-nav__dropdown">
1507                  
1508                    
1509                    
1510                      <li >
1511                        <a href="/collections/cnp"  class="site-nav__link">CNP</a>
1512                      </li>
1513                    
1514                  
1515                </ul>
1516              </li>
1517            
1518          
1519            
1520            
1521              
1522              <li class="site-nav--has-dropdown">
1523                <a href="/collections/sanitary-wares"  class="site-nav__link">
1524                  Sanitary Wares
1525                  <span class="icon-fallback-text">
1526                    <span class="icon icon-arrow-right" aria-hidden="true"></span>
1527                  </span>
1528                </a>
1529                <ul class="site-nav__dropdown">
1530                  
1531                    
1532                    
1533                      
1534                      <li class="site-nav--has-dropdown">
1535                        <a href="/collections/sericite"  class="site-nav__link">
1536                          Sericite
1537                          <span class="icon-fallback-text">
1538                            <span class="icon icon-arrow-right" aria-hidden="true"></span>
1539                          </span>
1540                        </a>
1541                        <ul class="site-nav__dropdown">
1542                          
1543                            <li>
1544                              <a href="/collections/sericite-urinal-bowl"  class="site-nav__link">Sericite Urinal Bowl</a>
1545                            </li>
1546                          
1547                            <li>
1548                              <a href="/collections/sericite-wc"  class="site-nav__link">Sericite WC</a>
1549                            </li>
1550                          
1551                            <li>
1552                              <a href="/collections/sericite-basin"  class="site-nav__link">Sericite Basin</a>
1553                            </li>
1554                          
1555                        </ul>
1556                      </li>
1557                    
1558                  
1559                    
1560                    
1561                      
1562                      <li class="site-nav--has-dropdown">
1563                        <a href="/collections/inno"  class="site-nav__link">
1564                          Inno
1565                          <span class="icon-fallback-text">
1566                            <span class="icon icon-arrow-right" aria-hidden="true"></span>
1567                          </span>
1568                        </a>
1569                        <ul class="site-nav__dropdown">
1570                          
1571                            <li>
1572                              <a href="/collections/inno-squatting-pan"  class="site-nav__link">Inno Squatting Pan</a>
1573                            </li>
1574                          
1575                            <li>
1576                              <a href="/collections/inno-urinal-bowl"  class="site-nav__link">Inno Urinal Bowl</a>
1577                            </li>
1578                          
1579                            <li>
1580                              <a href="/collections/inno-wc"  class="site-nav__link">Inno WC</a>
1581                            </li>
1582                          
1583                            <li>
1584                              <a href="/collections/inno-basin"  class="site-nav__link">Inno Basin</a>
1585                            </li>
1586                          
1587                        </ul>
1588                      </li>
1589                    
1590                  
1591                </ul>
1592              </li>
1593            
1594          
1595            
1596            
1597              
1598              <li class="site-nav--has-dropdown">
1599                <a href="/collections/plumbing-valve"  class="site-nav__link">
1600                  Plumbing Valve
1601                  <span class="icon-fallback-text">
1602                    <span class="icon icon-arrow-right" aria-hidden="true"></span>
1603                  </span>
1604                </a>
1605                <ul class="site-nav__dropdown">
1606                  
1607                    
1608                    
1609                      <li >
1610                        <a href="/collections/gkm"  class="site-nav__link">GKM</a>
1611                      </li>
1612                    
1613                  
1614                    
1615                    
1616                      <li >
1617                        <a href="/collections/city-valve"  class="site-nav__link">City Valve</a>
1618                      </li>
1619                    
1620                  
1621                    
1622                    
1623                      <li >
1624                        <a href="/collections/g-kent-valve"  class="site-nav__link">g-Kent Valve</a>
1625                      </li>
1626                    
1627                  
1628                    
1629                    
1630                      <li >
1631                        <a href="/collections/york-check-valve"  class="site-nav__link">YORK Check Valve</a>
1632                      </li>
1633                    
1634                  
1635                    
1636                    
1637                      <li >
1638                        <a href="/collections/lye"  class="site-nav__link">LYE</a>
1639                      </li>
1640                    
1641                  
1642                    
1643                    
1644                      <li >
1645                        <a href="/collections/water-meter"  class="site-nav__link">Water Meter</a>
1646                      </li>
1647                    
1648                  
1649                    
1650                    
1651                      <li >
1652                        <a href="/collections/pipe-repair-clamp"  class="site-nav__link">Pipe Repair Clamp</a>
1653                      </li>
1654                    
1655                  
1656                    
1657                    
1658                      <li >
1659                        <a href="/collections/others"  class="site-nav__link">Others</a>
1660                      </li>
1661                    
1662                  
1663                </ul>
1664              </li>
1665            
1666          
1667            
1668            
1669              
1670              <li class="site-nav--has-dropdown">
1671                <a href="/collections/water-tank---sewerage-tank"  class="site-nav__link">
1672                  Water Tank &amp; Sewerage Tank
1673                  <span class="icon-fallback-text">
1674                    <span class="icon icon-arrow-right" aria-hidden="true"></span>
1675                  </span>
1676                </a>
1677                <ul class="site-nav__dropdown">
1678                  
1679                    
1680                    
1681                      
1682                      <li class="site-nav--has-dropdown">
1683                        <a href="/collections/polytank"  class="site-nav__link">
1684                          POLYTANK
1685                          <span class="icon-fallback-text">
1686                            <span class="icon icon-arrow-right" aria-hidden="true"></span>
1687                          </span>
1688                        </a>
1689                        <ul class="site-nav__dropdown">
1690                          
1691                            <li>
1692                              <a href="/collections/camel"  class="site-nav__link">CAMEL</a>
1693                            </li>
1694                          
1695                            <li>
1696                              <a href="/collections/buffalo"  class="site-nav__link">BUFFALO</a>
1697                            </li>
1698                          
1699                            <li>
1700                              <a href="/collections/king-kong"  class="site-nav__link">KING KONG</a>
1701                            </li>
1702                          
1703                            <li>
1704                              <a href="/collections/hercules"  class="site-nav__link">HERCULES</a>
1705                            </li>
1706                          
1707                            <li>
1708                              <a href="/collections/compact"  class="site-nav__link">COMPACT</a>
1709                            </li>
1710                          
1711                        </ul>
1712                      </li>
1713                    
1714                  
1715                    
1716                    
1717                      
1718                      <li class="site-nav--has-dropdown">
1719                        <a href="/collections/kossan-water-tank"  class="site-nav__link">
1720                          Kossan Water Tank
1721                          <span class="icon-fallback-text">
1722                            <span class="icon icon-arrow-right" aria-hidden="true"></span>
1723                          </span>
1724                        </a>
1725                        <ul class="site-nav__dropdown">
1726                          
1727                            <li>
1728                              <a href="/collections/kossan-square-tank"  class="site-nav__link">Kossan Square Tank</a>
1729                            </li>
1730                          
1731                            <li>
1732                              <a href="/collections/kossan-round-tank"  class="site-nav__link">Kossan Round Tank</a>
1733                            </li>
1734                          
1735                            <li>
1736                              <a href="/collections/kossan-rectangular-tank"  class="site-nav__link">Kossan Rectangular Tank</a>
1737                            </li>
1738                          
1739                        </ul>
1740                      </li>
1741                    
1742                  
1743                    
1744                    
1745                      
1746                      <li class="site-nav--has-dropdown">
1747                        <a href="/collections/king-kong-stainless-steel-tank"  class="site-nav__link">
1748                          King Kong Stainless Steel Tank
1749                          <span class="icon-fallback-text">
1750                            <span class="icon icon-arrow-right" aria-hidden="true"></span>
1751                          </span>
1752                        </a>
1753                        <ul class="site-nav__dropdown">
1754                          
1755                            <li>
1756                              <a href="/collections/king-kong-horizontal-with-stand"  class="site-nav__link">King Kong Horizontal With Stand</a>
1757                            </li>
1758                          
1759                            <li>
1760                              <a href="/collections/king-kong-vertical-round-bottom-with-stand"  class="site-nav__link">King Kong Vertical Round Bottom With Stand</a>
1761                            </li>
1762                          
1763                            <li>
1764                              <a href="/collections/king-kong-vertical-flat-bottom-without-stand"  class="site-nav__link">King Kong Vertical Flat Bottom Without Stand</a>
1765                            </li>
1766                          
1767                        </ul>
1768                      </li>
1769                    
1770                  
1771                    
1772                    
1773                      <li >
1774                        <a href="/collections/septic-tank"  class="site-nav__link">Septic Tank</a>
1775                      </li>
1776                    
1777                  
1778                </ul>
1779              </li>
1780            
1781          
1782            
1783            
1784              
1785              <li class="site-nav--has-dropdown">
1786                <a href="/collections/water-heater"  class="site-nav__link">
1787                  Water Heater
1788                  <span class="icon-fallback-text">
1789                    <span class="icon icon-arrow-right" aria-hidden="true"></span>
1790                  </span>
1791                </a>
1792                <ul class="site-nav__dropdown">
1793                  
1794                    
1795                    
1796                      <li >
1797                        <a href="/collections/solar-heater"  class="site-nav__link">Solar Heater</a>
1798                      </li>
1799                    
1800                  
1801                    
1802                    
1803                      <li >
1804                        <a href="/collections/instant-water-heater"  class="site-nav__link">Instant Water Heater</a>
1805                      </li>
1806                    
1807                  
1808                    
1809                    
1810                      <li >
1811                        <a href="/collections/heater-storage-tank"  class="site-nav__link">Heater Storage Tank</a>
1812                      </li>
1813                    
1814                  
1815                </ul>
1816              </li>
1817            
1818          
1819            
1820            
1821              
1822              <li class="site-nav--has-dropdown">
1823                <a href="/collections/water-pipes-and-fittings"  class="site-nav__link">
1824                  Water Pipes and Fittings
1825                  <span class="icon-fallback-text">
1826                    <span class="icon icon-arrow-right" aria-hidden="true"></span>
1827                  </span>
1828                </a>
1829                <ul class="site-nav__dropdown">
1830                  
1831                    
1832                    
1833                      <li >
1834                        <a href="/collections/pvc-pipes--sirim-"  class="site-nav__link">PVC Pipes (Sirim)</a>
1835                      </li>
1836                    
1837                  
1838                    
1839                    
1840                      <li >
1841                        <a href="/collections/pvc-pipes--non-sirim-"  class="site-nav__link">PVC Pipes (Non Sirim)</a>
1842                      </li>
1843                    
1844                  
1845                    
1846                    
1847                      <li >
1848                        <a href="/collections/pvc-fittings"  class="site-nav__link">PVC Fittings</a>
1849                      </li>
1850                    
1851                  
1852                    
1853                    
1854                      <li >
1855                        <a href="/collections/upvc-underground-pipe--sirim-"  class="site-nav__link">Underground Pipe (Sirim)</a>
1856                      </li>
1857                    
1858                  
1859                    
1860                    
1861                      <li >
1862                        <a href="/collections/upvc-pipes--sirim-"  class="site-nav__link">UPVC Pipes (Sirim)</a>
1863                      </li>
1864                    
1865                  
1866                    
1867                    
1868                      <li >
1869                        <a href="/collections/upvc-pipes--non-sirim-"  class="site-nav__link">UPVC Pipes (Non Sirim)</a>
1870                      </li>
1871                    
1872                  
1873                    
1874                    
1875                      <li >
1876                        <a href="/collections/upvc-underground-fittings"  class="site-nav__link">Underground Fittings</a>
1877                      </li>
1878                    
1879                  
1880                    
1881                    
1882                      <li >
1883                        <a href="/collections/upvc-swv-fittings"  class="site-nav__link">UPVC SWV Fittings</a>
1884                      </li>
1885                    
1886                  
1887                    
1888                    
1889                      <li >
1890                        <a href="/collections/buteline-pipes---fittings"  class="site-nav__link">Buteline Pipes & Fittings</a>
1891                      </li>
1892                    
1893                  
1894                    
1895                    
1896                      <li >
1897                        <a href="/collections/hansen-fittings"  class="site-nav__link">Hansen Fittings</a>
1898                      </li>
1899                    
1900                  
1901                    
1902                    
1903                      <li >
1904                        <a href="/collections/gf-ppr-pipes---fittings"  class="site-nav__link">GF PPR Pipes & Fittings</a>
1905                      </li>
1906                    
1907                  
1908                    
1909                    
1910                      <li >
1911                        <a href="/collections/kembla-copper-pipes"  class="site-nav__link">Kembla Copper Pipes</a>
1912                      </li>
1913                    
1914                  
1915                    
1916                    
1917                      <li >
1918                        <a href="/collections/hubless-pipes-and-fittings"  class="site-nav__link">Hubless Pipes and Fittings</a>
1919                      </li>
1920                    
1921                  
1922                    
1923                    
1924                      <li >
1925                        <a href="/collections/conex-copper-fittings"  class="site-nav__link">Conex Copper Fittings</a>
1926                      </li>
1927                    
1928                  
1929                    
1930                    
1931                      <li >
1932                        <a href="/collections/delcop-copper-welding-fittings"  class="site-nav__link">DELCOP Copper Welding Fittings</a>
1933                      </li>
1934                    
1935                  
1936                    
1937                    
1938                      <li >
1939                        <a href="/collections/gi-fittings"  class="site-nav__link">GI Fittings</a>
1940                      </li>
1941                    
1942                  
1943                    
1944                    
1945                      <li >
1946                        <a href="/collections/gi-pipes"  class="site-nav__link">GI Pipes</a>
1947                      </li>
1948                    
1949                  
1950                    
1951                    
1952                      <li >
1953                        <a href="/collections/gi-aa-pipes"  class="site-nav__link">GI AA Pipes</a>
1954                      </li>
1955                    
1956                  
1957                    
1958                    
1959                      <li >
1960                        <a href="/collections/stainless-steel-pipe"  class="site-nav__link">Stainless Steel Pipe</a>
1961                      </li>
1962                    
1963                  
1964                    
1965                    
1966                      <li >
1967                        <a href="/collections/stainless-steel-fittings"  class="site-nav__link">Stainless Steel Fittings</a>
1968                      </li>
1969                    
1970                  
1971                    
1972                    
1973                      <li >
1974                        <a href="/collections/techplas"  class="site-nav__link">Techplas</a>
1975                      </li>
1976                    
1977                  
1978                    
1979                    
1980                      <li >
1981                        <a href="/collections/others-1"  class="site-nav__link">Others</a>
1982                      </li>
1983                    
1984                  
1985                </ul>
1986              </li>
1987            
1988          
1989            
1990            
1991              
1992              <li class="site-nav--has-dropdown">
1993                <a href="/collections/wholesales-price"  class="site-nav__link">
1994                  Wholesales Price
1995                  <span class="icon-fallback-text">
1996                    <span class="icon icon-arrow-right" aria-hidden="true"></span>
1997                  </span>
1998                </a>
1999                <ul class="site-nav__dropdown">
2000                  
2001                    
2002                    
2003                      <li >
2004                        <a href="/collections/wholesale-upvc-swv-fittings"  class="site-nav__link">Wholesale UPVC SWV Fittings</a>
2005                      </li>
2006                    
2007                  
2008                    
2009                    
2010                      <li >
2011                        <a href="/collections/wholesale-upvc-pipes--sirim-"  class="site-nav__link">Wholesale UPVC Pipes (Sirim)</a>
2012                      </li>
2013                    
2014                  
2015                    
2016                    
2017                      <li >
2018                        <a href="/collections/wholesale-buteline-fittings"  class="site-nav__link">Wholesale Buteline Fittings</a>
2019                      </li>
2020                    
2021                  
2022                </ul>
2023              </li>
2024            
2025          
2026        </ul>
2027      </li>
2028    
2029  
2030    
2031    
2032      <li >
2033        <a href="/pages/about-us"  class="site-nav__link">About Us</a>
2034      </li>
2035    
2036  
2037    
2038    
2039      <li >
2040        <a href="/pages/catalogue"  class="site-nav__link">Catalogue</a>
2041      </li>
2042    
2043  
2044  
2045</ul>
2046        </div>
2047      </div>
2048
2049      
2050
2051    </div>
2052  </header>
2053  
2054  <main class="wrapper main-content" role="main">
2055    <div class="grid">
2056      
2057       <div class="grid__item medium-down--hide large--one-quarter">
2058         <hr class="hr--small hr--clear">
2059      		 <nav>
2060          		<font size="5"> <hr><b>Category<br></b></font>    
2061              
2062              	<a href="/collections/water-pump">Water Pump</a><br>
2063              
2064              	<a href="/collections/sanitary-wares">Sanitary Wares</a><br>
2065              
2066              	<a href="/collections/plumbing-valve">Plumbing Valve</a><br>
2067              
2068              	<a href="/collections/water-tank---sewerage-tank">Water Tank & Sewerage Tank</a><br>
2069              
2070              	<a href="/collections/water-heater">Water Heater</a><br>
2071              
2072              	<a href="/collections/water-pipes-and-fittings">Water Pipes and Fittings</a><br>
2073              
2074              	<a href="/collections/wholesales-price">Wholesales Price</a><br>
2075              
2076        		<hr>
2077					</nav>
2078     		</div>
2079      
2080        <div class="grid__item large--three-quarters">
vendor: 94 bytes, lines 2080-2084
2080
2081          
2082
2083          
2084<script src="https://www.recaptcha.net/recaptcha/enterprise.js?render=
20846LdMNdIqAAAAALegJp7y4weVcCIlnwmIN8TWseEF
vendor: 12 bytes, line 2084
2084"></script>
2085<link rel="preload" href="https://store-themes.easystore.co/39481/themes/336/assets/customer.css?t=1787072412" as="style" onload="this.onload=null;this.rel='stylesheet'">
2086<style>
2087  main.main-content .field > label{
2088    display: none;
2089  }
2090  .h3{
2091    font-size: 18px;
2092  }
2093  .button--full-width{
2094    width: 100%;
2095  }
2096  .tab-wrapper{
2097    display: inline-flex;
2098    justify-content: center;
2099    align-items: center;
2100    margin: 10px auto 20px;
2101    background-color: #eaeaea;
2102    border-radius: 200px;
2103    padding: 5px;
2104    gap: 10px;
2105  }
2106  .tab-wrapper .tab-label {
2107    display: inline-block;
2108    min-width: 130px;
2109    padding: 8px 15px;
2110    border-radius: 100px;
2111    cursor: pointer;
2112    font-size: 17px;
2113    line-height: 1.1;
2114    user-select: none;
2115    margin: 0;
2116    color: #000;
2117  }
2118  #register-tos a {
2119    display: inline;
2120  }
2121  @media screen and (max-width: 400px){
2122    .tab-wrapper .tab-label {
2123      min-width: 110px;
2124    }
2125  }
2126  .tab-wrapper input[type='radio']:checked + .tab-label {
2127    background-color: #fff;
2128    box-shadow: 2px 2px 25px -10px #333;
2129  }
2130
2131  @media screen and (min-width: 500px){
2132    .large--five-twelfths{
2133      min-width: 420px;
2134    }
2135  }
2136</style>
2137
2138
2139
2140
2141<div class="customer login section-width-control small-width large--five-twelfths text-center wrapper">
2142  <div class="card">
2143    <h1 id="login" tabindex="-1" class="mb-0">
2144      Welcome
2145    </h1>
2146    <p class="h3 mt-0">
2147      
2148        Sign up or log in to continue
2149      
2150    </p>
2151    <div>
2152      
2153
2154      
2155
2156      
2157
2158      
2159
2160      
2161
2162      
2163
2164      
2165
2166      
2167
2168      
2169      <div class="tab-wrapper">
2170        <div>
2171          <input type="radio" name="type" id="tab-register" class="hide hidden" checked>
2172          <label for="tab-register" class="tab-label">
2173            Sign up
2174          </label>
2175        </div>
2176        <div>
2177          <input type="radio" name="type" id="tab-login" class="hide hidden">
2178          <label for="tab-login" class="tab-label">
2179            Login
2180          </label>
2181        </div>
2182      </div>
2183      
2184
2185      <form id="form-login" action="/account/auth" method="post" class="mt-2">
2186        <input type="hidden" name="_token" value="CfeJEOxOvhUxEgvKeM0ruK5x6bNBCUp3YcMNjaAT">
2187        <input type="hidden" name="location_id" value="">
2188        <input type="hidden" name="staff_id" value="">
2189        <input type="hidden" id="recaptchaResponse" name="g-recaptcha-response">
2190
2191        
2192        <div id="error-content"></div>
2193
2194        <div class="field">
2195          <input
2196            type="text"
2197            name="customer[email_or_phone]"
2198            id="CustomerDetail"
2199            autocorrect="off"
2200            autocapitalize="off"
2201            placeholder="Email"
2202            required
2203          >
2204          <label for="CustomerDetail">
2205            Email
2206          </label>
2207        </div>
2208
2209        <button
2210          type="submit"
2211          form="form-login"
2212          class="btn button--full-width g-recaptcha">
2213          Continue
2214        </button>
2215
2216        <div class="button-snippet">
2217                          
2218        </div>
2219
2220        
2221
2222        <div id="register-tos">
2223          By signing up, I agree to the TS Bathroom Mall - Your One Stop Bathroom Solutions Need's <a target="_blank" href="/legal/terms-of-service">Terms of Service</a>, <a target="_blank" href="/legal/privacy-policy">Privacy Policy</a>, <a target="_blank" href="/legal/refund-policy">Refund Policy</a> and <a target="_blank" href="/legal/delivery">Delivery</a>.
2224        </div>
2225
2226      </form>
2227    </div>
2228  </div>
2229
2230</div>
2231
2232
2233
2234<script>
2235  const register_tab = document.querySelector('#tab-register');
2236  const login_tab = document.querySelector('#tab-login');
2237  const register_tos = document.querySelector('#register-tos');
2238  const isRegistrationEnabled = "1";
2239
2240  if (register_tab) {
2241    register_tab.addEventListener('click', function() {
2242      if (register_tos) {
2243        register_tos.style.display = 'block';
2244      }
2245    });
2246  }
2247  if (login_tab) {
2248    login_tab.addEventListener('click', function() {
2249      if (register_tos) {
2250        register_tos.style.display = 'none';
2251      }
2252    });
2253  }
2254
2255  const methodSwitchBtn = document.getElementById('phone-login-btn');
2256  if (methodSwitchBtn) {
2257    methodSwitchBtn.onclick = function () {
2258      var type = (register_tab && register_tab.checked) ? 'register' : 'login';
2259      window.location.href = '/account/login?method=phone&type=' + type;
2260    };
2261  }
2262
2263  let lastPathSegment = window.location.pathname.split('/').filter(segment => segment.length > 0).pop();
2264  
2265  // Redirect to login if trying to access register when self registration is disabled
2266  if (!isRegistrationEnabled) {
2267    if (lastPathSegment === 'register') {
2268      window.location.href = '/account/login';
2269    } else if (lastPathSegment === 'login' || lastPathSegment === 'auth') {
2270      if (register_tos) {
2271        register_tos.style.display = 'none';
2272      }
2273    } 
2274  } else {
2275    // Only proceed with tab logic if not redirecting
2276    if(lastPathSegment === 'login') {
2277      if (login_tab) {
2278        login_tab.checked = true;
2279      }
2280      if (register_tos) {
2281        register_tos.style.display = 'none';
2282      }
2283    } else {
2284      if (register_tos) {
2285        register_tos.style.display = 'block';
2286      }
2287    }
2288  }
2289
2290  const emailPattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
2291  const phonePattern = /^(?:\+?\d{1,3}[\s-]?)?(?:\d{1,14}[\s-]?){1,5}$/;
2292
2293  let form = document.querySelector('#form-login'),
2294      input = document.querySelector('#CustomerDetail'),
2295      error_content = document.querySelector('#error-content');
2296
2297
2298  // One attempt at a time: the reCAPTCHA wait below is async, so without
2299  // this a double-click starts two continuations and posts the form twice.
2300  var submitting = false;
2301
2302  form.addEventListener('submit', async function (event) {
2303    // preventDefault FIRST: a re-entrant submit must still be cancelled, or the
2304    // browser performs a native post with no captcha token.
2305    event.preventDefault();
2306    if (submitting) return;
2307
2308    let input_value = input.value
2309    error_content.innerHTML = '';
2310    if (!input_value.match(emailPattern) && !input_value.match(phonePattern)) {
2311      error_content.innerHTML = `<div class="errors note">Invalid Email or Phone</div>`;
2312      return false;
2313    }
2314
2315    submitting = true;
2316    document.querySelector('#form-login .btn').classList.add('btn--loading','loading');
2317
2318    // reCAPTCHA is unreachable from some regions (google.com is blocked in
2319    // mainland China). Fail open the same way checkout and forgot-password do:
2320    // submit without a token rather than leave the button spinning forever.
2321    try {
2322      if (window.grecaptcha && typeof window.grecaptcha.enterprise === 'object') {
2323        // The loader defines a stub {ready} synchronously and fetches the real
2324        // implementation asynchronously, so execute() may not exist yet.
2325        // ready() queues until it does; the timeout stops a bundle that never
2326        // arrives from hanging the button.
2327        await new Promise(function (resolve) {
2328          setTimeout(resolve, 3000);
2329          try { grecaptcha.enterprise.ready(resolve); } catch (e) { resolve(); }
2330        });
2331
2332        const token = await grecaptcha.enterprise.execute('6LdMNdIqAAAAALegJp7y4weVcCIlnwmIN8TWseEF', { action: 'LOGIN' });
2333        document.getElementById('recaptchaResponse').value = token;
2334      }
2335    } catch (e) { /* fail open */ }
2336
2337    document.getElementById('form-login').submit();
2338  });
2339
2340
2341</script>
2341
2342
2343
2344          
2345        </div>
2346    </div>
2347
2348  </main>
2349
2350  <footer class="site-footer small--text-center" role="contentinfo">
2351
2352    <div class="wrapper">
2353
2354      <div class="grid-uniform">
2355
2356        
2357        
2358        
2359        
2360          
2361        
2362        
2363        
2364          
2365        
2366        
2367        
2368
2369        
2370            
2371          
2372
2373        
2374
2375        
2376          <div class="grid__item large--one-half medium--one-half">
2377            
2378            <h4>Quick Links</h4>
2379            
2380            <ul class="site-footer__links">
2381              
2382                <li><a href="http://cp.easystore.my/" >Back to Control Panel</a></li>
2383              
2384              
2385            </ul>
2386          </div>
2387        
2388
2389        
2390          <div class="grid__item large--one-half medium--one-half">
2391            <h4>Follow Us</h4>
2392              
2393              <ul class="inline-list social-icons">
2394  
2395    <li>
2396      <a class="icon-fallback-text" href="https://twitter.com/" title="TS Bathroom Mall - Your One Stop Bathroom Solutions Need on Twitter" target="_blank">
2397        <span class="icon icon-twitter" aria-hidden="true"></span>
2398        <span class="fallback-text">Twitter</span>
2399      </a>
2400    </li>
2401  
2402  
2403    <li>
2404      <a class="icon-fallback-text" href="https://www.facebook.com/" title="TS Bathroom Mall - Your One Stop Bathroom Solutions Need on Facebook" target="_blank">
2405        <span class="icon icon-facebook" aria-hidden="true"></span>
2406        <span class="fallback-text">Facebook</span>
2407      </a>
2408    </li>
2409  
2410  
2411    <li>
2412      <a class="icon-fallback-text" href="https://www.pinterest.com/" title="TS Bathroom Mall - Your One Stop Bathroom Solutions Need on Pinterest" target="_blank">
2413        <span class="icon icon-pinterest" aria-hidden="true"></span>
2414        <span class="fallback-text">Pinterest</span>
2415      </a>
2416    </li>
2417  
2418  
2419    <li>
2420      <a class="icon-fallback-text" href="https://plus.google.com/" title="TS Bathroom Mall - Your One Stop Bathroom Solutions Need on Google Plus" rel="publisher" target="_blank">
2421        <span class="icon icon-google_plus" aria-hidden="true"></span>
2422        <span class="fallback-text">Google</span>
2423      </a>
2424    </li>
2425  
2426  
2427    <li>
2428      <a class="icon-fallback-text" href="https://instagram.com/" title="TS Bathroom Mall - Your One Stop Bathroom Solutions Need on Instagram" target="_blank">
2429        <span class="icon icon-instagram" aria-hidden="true"></span>
2430        <span class="fallback-text">Instagram</span>
2431      </a>
2432    </li>
2433  
2434  
2435    <li>
2436      <a class="icon-fallback-text" href="https://www.tumblr.com/" title="TS Bathroom Mall - Your One Stop Bathroom Solutions Need on Tumblr" target="_blank">
2437        <span class="icon icon-tumblr" aria-hidden="true"></span>
2438        <span class="fallback-text">Tumblr</span>
2439      </a>
2440    </li>
2441  
2442  
2443    <li>
2444      <a class="icon-fallback-text" href="https://www.youtube.com/" title="TS Bathroom Mall - Your One Stop Bathroom Solutions Need on YouTube" target="_blank">
2445        <span class="icon icon-youtube" aria-hidden="true"></span>
2446        <span class="fallback-text">YouTube</span>
2447      </a>
2448    </li>
2449  
2450  
2451    <li>
2452      <a class="icon-fallback-text" href="https://vimeo.com/" title="TS Bathroom Mall - Your One Stop Bathroom Solutions Need on Vimeo" target="_blank">
2453        <span class="icon icon-vimeo" aria-hidden="true"></span>
2454        <span class="fallback-text">Vimeo</span>
2455      </a>
2456    </li>
2457  
2458  
2459  
2460</ul>
2461
2462          </div>
2463        
2464      </div>
2465
2466      <hr class="hr--small hr--clear">
2467
2468      
2469        <div class="grid">
2470          
2471           <div class="grid__item text-center">
2472             <ul class="inline-list payment-icons">
2473                
2474                  <li>
2475                    <span class="icon-fallback-text">
2476                      <span class="icon icon-visa" aria-hidden="true"></span>
2477                      <span class="fallback-text">Visa</span>
2478                    </span>
2479                  </li>
2480                
2481                
2482                  <li>
2483                    <span class="icon-fallback-text">
2484                      <span class="icon icon-master" aria-hidden="true"></span>
2485                      <span class="fallback-text">Master</span>
2486                    </span>
2487                  </li>
2488                
2489                
2490                
2491                
2492                
2493             </ul>
2494           </div>
2495           
2496           
2497           <div class="grid__item text-center">
2498             <ul class="inline-list payment-icons">
2499               
2500                  <li>
2501                  <img src="https://s3.dualstack.ap-southeast-1.amazonaws.com/eesb.public/images/payment/payments_bank-transfer.svg" alt="payment_bank-transfer">
2502                  </li>
2503               
2504                  <li>
2505                  <img src="https://s3.dualstack.ap-southeast-1.amazonaws.com/eesb.public/images/payment/payments_ipay88.svg" alt="payment_ipay88">
2506                  </li>
2507               
2508                  <li>
2509                  <img src="https://s3.dualstack.ap-southeast-1.amazonaws.com/eesb.public/images/payment/payments_maybankqrpay.svg" alt="payment_maybankqrpay">
2510                  </li>
2511               
2512             </ul>
2513           </div>
2514          
2515         
2516         </div>
2517       
2518
2519       <div class="grid">
2520         <div class="grid__item text-center">
2521           <p class="site-footer__links">Copyright © 2018 TS Bathroom Mall - Your One Stop Bathroom Solutions Need. E-commerce Powered by <a href="http://www.easystore.co/?utm_source=storefront&utm_medium=sf_ref_footer&utm_campaign=sf_ref">EasyStore</a></p>
2522           
2523           <p class="site-footer__links">
2524            
2525            
2526              
2527                <a href="/legal/terms-of-service">Terms of Service</a>
2528              
2529              
2530            
2531              
2532                | <a href="/legal/privacy-policy">Privacy Policy</a>
2533              
2534              
2535            
2536              
2537                | <a href="/legal/refund-policy">Refund Policy</a>
2538              
2539              
2540            
2541              
2542                | <a href="/legal/delivery">Delivery</a>
2543              
2544              
2545            
2546           </p>
2547           
2548         </div>
2549       </div>
2550
2551    </div>
2552  </footer>
2553
2554  
2555
2556  
2556<script src="https://store-themes.easystore.co/39481/themes/336/assets/fastclick.min.js?t=1787072412" type="text/javascript" ></script>
2556
2557  
2557<script src="https://store-themes.easystore.co/39481/themes/336/assets/timber.js?t=1787072412" type="text/javascript" ></script>
2557
2558  
2558<script src="https://store-themes.easystore.co/39481/themes/336/assets/theme.js?t=1787072412" type="text/javascript" ></script>
2558
2559
2560  
2561
2562  
2563
2564  
2565
2566<script src="/assets/currencies.js" type="text/javascript" ></script>
vendor: 2 bytes, line 2566
2566
2567<script src="/assets/jquery.currencies.min.js" type="text/javascript" ></script>
vendor: 2 bytes, line 2567
2567
2568<script src="/assets/currencies_format.js" type="text/javascript" ></script>
2568
2569
2570<script>
2571Currency.format = "money_with_currency_format";
2572var shopCurrency = 'MYR';
2573var selectedCurrency = '';
2574
2575
2576  Currency.convert = function(amount, from, to) {
2577    return amount;
2578  };
2579
2580  
2581if( $.cookie("currency") == null ){
2582  
2583  if( selectedCurrency != false ) {
2584
2585  Currency.convertAll(shopCurrency, selectedCurrency);
2586  jQuery('.selected-currency').text(Currency.currentCurrency);  
2587
2588  }
2589
2590}
2591
2592/* Sometimes merchants change their shop currency, let's tell our JavaScript file */
2593// Currency.moneyFormats[shopCurrency].money_with_currency_format = "";
2594// Currency.moneyFormats[shopCurrency].money_format = "RM  {{amount}} ";
2595  
2596/* Default currency */
2597var defaultCurrency = 'MYR';
2598  
2599/* Cookie currency */
2600var cookieCurrency = Currency.cookie.read();
2601
2602  cookieCurrency = shopCurrency;
2603
2604$("input[name=current_currency]").val(cookieCurrency);
2605if(cookieCurrency == null){
2606  cookieCurrency = shopCurrency;
2607  Currency.cookie.write(shopCurrency);
2608}
2609/* Fix for customer account pages */
2610jQuery('span.money span.money').each(function() {
2611  jQuery(this).parents('span.money').removeClass('money');
2612});
2613/* Saving the current price */
2614jQuery('span.money').each(function() {
2615  jQuery(this).attr('data-currency-MYR', jQuery(this).html());
2616});
2617// If there's no cookie.
2618if (cookieCurrency == null) {
2619  if (shopCurrency !== defaultCurrency) {
2620    Currency.convertAll(shopCurrency, defaultCurrency);
2621  }
2622  else {
2623    Currency.currentCurrency = defaultCurrency;
2624  }
2625}
2626// If the cookie value does not correspond to any value in the currency dropdown.
2627else if (jQuery('[name=currencies]').size() && jQuery('[name=currencies] option[value=' + cookieCurrency + ']').size() === 0) {
2628  Currency.currentCurrency = shopCurrency;
2629  Currency.cookie.write(shopCurrency);
2630}
2631else if (cookieCurrency === shopCurrency) {
2632  Currency.currentCurrency = shopCurrency;
2633  Currency.convertAll(shopCurrency, cookieCurrency);
2634}
2635else {
2636  Currency.convertAll(shopCurrency, cookieCurrency);
2637}
2638jQuery('[name=currencies]').val(Currency.currentCurrency).change(function() {
2639  var newCurrency = jQuery(this).val();
2640  
2641  
2642    Currency.cookie.write(newCurrency)
2643    if ('customers' == 'cart') {
2644      const params = new URLSearchParams(window.location.search);
2645      params.set('delete_cache', 1);
2646      window.location.search = params;
2647    } else {
2648      window.location.reload();
2649    }
2650  
2651});
2652var original_selectCallback = window.selectCallback;
2653var selectCallback = function(variant, selector) {
2654  var currencies = null;
2655  original_selectCallback(variant, selector);
2656  if(typeof jQuery('[name=currencies]').val() == "undefined"){
2657    currencies = shopCurrency;
2658  }
2659  else{
2660    currencies = jQuery('[name=currencies]').val();
2661  }
2662  Currency.convertAll(shopCurrency, currencies);
2663  jQuery('.selected-currency').text(Currency.currentCurrency);
2664};
2665$('body').on('ajaxCart.afterCartLoad', function(cart) {
2666  Currency.convertAll(shopCurrency, jQuery('[name=currencies]').val());
2667  jQuery('.selected-currency').text(Currency.currentCurrency);  
2668});
2669jQuery('.selected-currency').text(Currency.currentCurrency);
2670</script>
2670
2671
2672
2673
2674<!-- Snippet:global/body_end: Product Label -->
2675<script>
2676		$(".product-label-badge").parent().find(".badge--sale").remove();
2677		</script>
2677
2678		
2679		<style>
2680		.product-label-badge-text {
2681			display: table-cell;
2682			vertical-align: middle;
2683			padding: 2px 8px 0;
2684			border-radius: 50%;
2685		}
2686		.product-label-badge{
2687			display: table;
2688			position: absolute;
2689			width: 60px;
2690			height: 60px;
2691			border-radius: 50%;
2692			font-weight: bold;
2693			text-align: center;
2694			font-size: .75em;
2695			line-height: 1.1;
2696			z-index: 10;
2697		}
2698
2699		.product-label-position{
2700			top: -12px;
2701			right: -12px;
2702		}
2703		</style>
2704<!-- /Snippet -->
2705<script>
2706
2707  /*
2708
2709    ------
2710    Events
2711    ------
2712
2713    pages/viewed
2714
2715    customers/signup
2716
2717    customers/login
2718
2719    products/searched
2720
2721    collections/viewed
2722
2723    products/viewed
2724
2725    products/shared
2726
2727    wishlists/item_added
2728
2729    carts/items_added
2730
2731    carts/viewed
2732
2733    carts/item_removed
2734
2735    checkouts/initiated
2736
2737    checkouts/shipping_info_added
2738
2739    checkouts/payment_info_added
2740
2741    checkouts/completed
2742
2743    orders/placed
2744
2745    orders/purchased
2746
2747    payments/captured
2748
2749    payments/failed
2750
2751  */
2752
2753  window.__latest_cart = window.__latest_cart || null;
2754
2755  const _selector = document.querySelector.bind(document),
2756        _selectorAll = document.querySelectorAll.bind(document)
2757
2758  document.addEventListener('DOMContentLoaded', (event) => {
2759
2760    const default_currency = getCookie("currency")
2761    const customer_id = window.__st.cid
2762    const template    = window.__st.p
2763
2764    onPageView()
2765
2766    //-----------------------//
2767    //        Configs        //
2768    //-----------------------//
2769
2770    window.dataLayer = window.dataLayer || []
2771
2772    Array.prototype.last = Array.prototype.last || function() {
2773      return this[this.length - 1] || null
2774    }
2775
2776    Array.prototype.first = Array.prototype.first || function() {
2777      return this[0] || null
2778    }
2779
2780    //----------------------//
2781    //       Triggers       //
2782    //----------------------//
2783
2784    const XHR = window.XMLHttpRequest
2785
2786    function xhr() {
2787
2788      const xhr = new XHR()
2789
2790      xhr.addEventListener("readystatechange", function() {
2791
2792        if(xhr.readyState != 4) return
2793
2794        try {
2795
2796          const response_url = xhr.responseURL
2797
2798          if (response_url.includes("cart/add")) {
2799
2800            window.__latest_cart = JSON.parse(xhr.response)
2801
2802            onCartItemsAdded() // ok
2803
2804          }
2805
2806          if (response_url.includes("cart/remove_item_quantity")) {
2807
2808            window.__latest_cart = JSON.parse(xhr.response)
2809
2810            onCartItemRemoved() // ok
2811
2812          }
2813
2814          if (response_url.includes("new_cart?retrieve=true")) {
2815
2816            result = JSON.parse(xhr.response)
2817
2818            if (result.cart) {
2819              window.__latest_cart = result.cart
2820            }
2821
2822          }
2823
2824        } catch(e) {
2825
2826          console.error(e)
2827
2828        }
2829
2830      }, false);
2831
2832      return xhr
2833
2834    }
2835
2836    window.XMLHttpRequest = xhr
2837
2838    switch(template) {
2839
2840      case 'cart': onCartView() // ok
2841      break
2842      case 'product': onProductView() // ok
2843      break
2844      case 'collection': onCollectionView() // ok
2845      break
2846      case 'blog': onBlogView()
2847      break
2848      case 'article': onArticleView()
2849      break
2850      case 'payment_completed': onOrderPlace()
2851      break
2852      case 'payment_fail': onPaymentFail()
2853      break
2854
2855    }
2856
2857    // _selector('form[action="/checkout/payments"]').addEventListener("submit", onPaymentInfoAdded(_selector('form[action="/checkout/payments"]')))
2858    if (_selector('form[action="/checkout/detail"]'))                            _selector('form[action="/checkout/detail"]').addEventListener("submit", ()=>{onShippingInfoAdded(_selector('form[action="/checkout/detail"]'))})  // ok
2859    if (_selector('form[action="/checkout/shipping"]'))                          _selector('form[action="/checkout/shipping"]').addEventListener("submit", ()=>{onShippingInfoAdded(_selector('form[action="/checkout/shipping"]'))})  // ok
2860    if (_selector('form[action="/account/register"]'))                           _selector('form[action="/account/register"]').addEventListener("submit", onSignUp)  // ok
2861    if (_selector('form[action="/account/login"]'))                              _selector('form[action="/account/login"]').addEventListener("submit", onLogin)  // ok
2862    if (_selector('form[action="/search"]'))                                     _selector('form[action="/search"]').addEventListener("submit", onProductSearch()) // ok
2863    if (_selector('#line-login-btn'))                                            _selector('#line-login-btn').addEventListener('click', onLineLogin) // ok
2864    if (_selector('#PlaceOrder'))                                                _selector('#PlaceOrder').addEventListener("click", ()=>{onCheckoutComplete(_selector('form[action="/checkout/payments"]'))});  // ok
2865    if (_selector('#add_wishlist'))                                              _selector('#add_wishlist').addEventListener("click", onWishlistItemAdded) // ok
2866    if (_selectorAll('a[href="/account/logout"]'))                               _selectorAll('a[href="/account/logout"]').forEach(logoutButton => logoutButton.addEventListener("click", onLogout)) // ok
2867    if (_selector('.CartDrawerTrigger.cart-page-link'))                          _selector('.CartDrawerTrigger.cart-page-link').addEventListener("click", onCartView) // ok
2868    if (_selector('.CartDrawerTrigger.cart-page-link.mobile-cart-page-link'))    _selector('.CartDrawerTrigger.cart-page-link.mobile-cart-page-link').addEventListener("click", onCartView) // ok
2869    if (_selectorAll('a[class^="share-"]'))                                      _selectorAll('a[class^="share-"]').forEach(shareButton => shareButton.addEventListener("click", ()=>{onProductShare(shareButton)}) ) // ok
2870    if (_selectorAll('[name$="checkout"]'))                                      _selectorAll('[name$="checkout"]').forEach(checkoutButton => checkoutButton.addEventListener("click", onCheckoutInitiate))
2871
2872    // For append elements
2873    const bodyMutationObserver = new MutationObserver(() => {
2874      if (_selector('#form__spc #PlaceOrder'))             _selector('#form__spc #PlaceOrder').addEventListener("click", onSinglePageCheckout) // ok
2875      if (_selectorAll('[name$="checkout"]'))              _selectorAll('[name$="checkout"]').forEach(checkoutButton => checkoutButton.addEventListener("click", onCheckoutInitiate))
2876    });
2877    bodyMutationObserver.observe(_selector("body"), {subtree: true, childList: true});
2878
2879    //------------------------------//
2880    //        Event handlers        //
2881    //------------------------------//
2882
2883    function onPageView() {
2884
2885      EasyStore.Event.dispatch('pages/viewed', {
2886        page: {
2887          type: template,
2888          title: document.title,
2889          description: _selector('meta[name=description]') ? _selector('meta[name=description]').getAttribute('content') : null,
2890          url: location.href,
2891        }
2892      })
2893
2894    }
2895
2896    function onSignUp() {
2897
2898      const email_regex = new RegExp(/^[a-zA-Z0-9.!#$%&"*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/)
2899      const phone_regex = new RegExp(/^(\+?6?01)[0-46-9]-*[0-9]{7,8}$/)
2900
2901      const email_or_phone = _selector(`input[name="customer[email_or_phone]"]`).value.replace("+", "").replace(/\s+/, "")
2902
2903      let data = {}
2904
2905      if (email_regex.test(email_or_phone)) {
2906        data.method = 'email'
2907        data.email = email_or_phone
2908      }
2909
2910      if (phone_regex.test(email_or_phone)) {
2911        data.method = "phone"
2912        data.phone = email_or_phone
2913      }
2914
2915      if (!data.method) return
2916
2917      EasyStore.Event.dispatch('customers/signup', data)
2918
2919    }
2920
2921    function onLogin() {
2922
2923      const email_regex = new RegExp(/^[a-zA-Z0-9.!#$%&"*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/)
2924      const phone_regex = new RegExp(/^(\+?6?01)[0-46-9]-*[0-9]{7,8}$/)
2925
2926      const email_or_phone = _selector(`input[name="customer[email_or_phone]"]`).value.replace("+", "").replace(/\s+/, "")
2927
2928      let data = {}
2929
2930      if (email_regex.test(email_or_phone)) {
2931        data.method = 'email'
2932        data.email = email_or_phone
2933      }
2934
2935      if (phone_regex.test(email_or_phone)) {
2936        data.method = "phone"
2937        data.phone = email_or_phone
2938      }
2939
2940      if (!data.method) return
2941
2942      EasyStore.Event.dispatch('customers/login', data)
2943
2944    }
2945
2946    function onLineLogin() {
2947
2948      EasyStore.Event.dispatch('customers/login', { method: 'line' })
2949
2950    }
2951
2952    function onLogout() {
2953
2954      EasyStore.Event.dispatch('customers/logout', { customer_id })
2955
2956    }
2957
2958    function onBlogView() {
2959
2960      const blog = ""
2961
2962      EasyStore.Event.dispatch('blogs/viewed', { blog })
2963
2964    }
2965
2966    function onArticleView() {
2967
2968      const article = ""
2969
2970      EasyStore.Event.dispatch('articles/viewed', { article })
2971
2972    }
2973
2974    function onProductSearch() {
2975
2976      const query = _selector('input[name=q]').value
2977
2978      if (!query) return
2979
2980      EasyStore.Event.dispatch('products/searched', { query })
2981
2982    }
2983
2984    function onCollectionView() {
2985
2986      const collection = ""
2987
2988      EasyStore.Event.dispatch('collections/viewed', { collection })
2989
2990    }
2991
2992    function onProductView() {
2993
2994      const product = ""
2995
2996      EasyStore.Event.dispatch("products/viewed", { product })
2997
2998    }
2999
3000    function onProductShare(el) {
3001
3002      const product = ""
3003
3004      const channel = el.getAttribute("class").split("-").last()
3005
3006      EasyStore.Event.dispatch('products/shared', { product, channel })
3007
3008    }
3009
3010    function onWishlistItemAdded() {
3011
3012      let product  = ""
3013      const quantity = _selector("#Quantity").value
3014
3015      EasyStore.Event.dispatch('wishlists/item_added', { product })
3016
3017    }
3018
3019    async function onCartItemsAdded() {
3020
3021      const cart = await getCart()
3022
3023      if(cart && cart.items != undefined && cart.items.length > 0) {
3024
3025        EasyStore.Event.dispatch('carts/item_added', { cart })
3026
3027      }
3028
3029    }
3030
3031    async function onCartView() {
3032
3033      const cart = await getCart()
3034
3035      EasyStore.Event.dispatch('carts/viewed', { cart })
3036
3037    }
3038
3039    async function onCartItemRemoved() {
3040
3041      const cart = await getCart()
3042
3043      cart.items = []
3044
3045      if(cart) {
3046
3047        EasyStore.Event.dispatch('carts/item_removed', { cart })
3048
3049      }
3050
3051    }
3052
3053    async function onCheckoutInitiate() {
3054
3055      const cart = await getCart()
3056
3057      EasyStore.Event.dispatch('checkouts/initiated', { cart })
3058
3059    }
3060
3061    async function onShippingInfoAdded(form) {
3062      let checkout = getCheckout()
3063
3064      let form_data = {}
3065      new FormData(form).forEach((value, key) => form_data[key] = value)
3066
3067      let shipping_tier = null
3068
3069      if (form_data.type && form_data.type.startsWith("r_pickup")) {
3070        shipping_tier = `Pickup - ${form_data.pick_location}`
3071      }
3072
3073      if (form_data.s_id) {
3074        shipping_tier = _selector(`input[id='`+form_data.s_id+`']`).getAttribute("data-shipping-name")
3075      }
3076
3077      if (!shipping_tier) return
3078
3079      EasyStore.Event.dispatch('checkouts/shipping_info_added', { checkout, shipping_tier })
3080
3081    }
3082
3083    async function onPaymentInfoAdded(form) {
3084
3085      let checkout = getCheckout()
3086
3087      let payment_type = new FormData(form).get('payment_method')
3088
3089      EasyStore.Event.dispatch("checkouts/payment_info_added", { checkout, payment_type })
3090
3091    }
3092
3093    async function onOrderPlace() {
3094
3095      let cart_token  = getCookie("cart_js")
3096      let previous_cart_token = getCookie("previous_cart_ga4_js")
3097
3098      if (previous_cart_token && previous_cart_token == cart_token) {
3099        // Prevent duplicate purchase tracking
3100        return
3101      }
3102
3103      let order = getOrder()
3104
3105      EasyStore.Event.dispatch('orders/placed', { order })
3106
3107      if(order.is_manual_payment) {
3108
3109        EasyStore.Event.dispatch('orders/purchased', { order })
3110
3111      }
3112
3113      const last_transaction = order.transactions.last()
3114
3115      if (last_transaction.status) {
3116
3117        EasyStore.Event.dispatch('orders/purchased', { order })
3118        EasyStore.Event.dispatch('payments/captured', { order })
3119
3120      }
3121
3122    }
3123
3124    async function onPaymentFail() {
3125
3126      const order = getOrder()
3127
3128      EasyStore.Event.dispatch('payments/failed', { order })
3129
3130    }
3131
3132    async function onCheckoutComplete(form) {
3133
3134      onPaymentInfoAdded(form)
3135
3136      const checkout = getCheckout()
3137
3138      EasyStore.Event.dispatch('checkouts/completed', { checkout })
3139
3140    }
3141
3142    async function onSinglePageCheckout() {
3143
3144      // let checkout = $("[data-app-checkout]").data("app-checkout")
3145
3146      let checkout = getCheckout()
3147
3148      // const payment_type = _selector("#app_spc_payment_method").find(`[class*="label-content"]`).first().find("b").first().text()
3149      const payment_type = _selector("#app_spc_payment_method").getElementsByClassName('label-content')[0].getElementsByTagName('b')[0].innerHTML
3150
3151      const shipping_method = _selector("#delivery_method").value
3152
3153      let shipping_tier = null
3154      let app_spc_customer_info_label = _selector("#app_spc_customer_info").getElementsByClassName('label-content')
3155      if (shipping_method == "shipping") {
3156        shipping_tier = app_spc_customer_info_label[app_spc_customer_info_label.length - 1].getElementsByTagName('b')[0].innerHTML
3157      }
3158
3159      if (shipping_method == "pickup") {
3160        shipping_tier = app_spc_customer_info_label[0].innerHTML
3161      }
3162
3163      if (shipping_tier) {
3164
3165        EasyStore.Event.dispatch('checkouts/shipping_info_added', {
3166          checkout,
3167          shipping_tier,
3168        })
3169
3170      }
3171
3172      if (payment_type) {
3173
3174        EasyStore.Event.dispatch('checkouts/payment_info_added', {
3175          checkout,
3176          payment_type,
3177        })
3178
3179      }
3180
3181      EasyStore.Event.dispatch('checkouts/completed', { checkout })
3182
3183    }
3184
3185  })
3186
3187
3188  //-----------------------//
3189  //       Functions       //
3190  //-----------------------//
3191
3192  function getCookie(name) {
3193
3194    name += "="
3195
3196    decodedCookie = decodeURIComponent(document.cookie)
3197
3198    ca = decodedCookie.split(";")
3199
3200    for(i = 0; i < ca.length; i++) {
3201      c = ca[i]
3202      while (c.charAt(0) == " ") {
3203        c = c.substring(1)
3204      }
3205      if (c.indexOf(name) == 0) {
3206        return c.substring(name.length, c.length)
3207      }
3208    }
3209
3210    return ""
3211
3212  }
3213
3214  const parsePrice = price => {
3215    if(typeof price === 'string') {
3216      return parseFloat(price.split(',').join(''))
3217    }
3218
3219    return price
3220  }
3221
3222  const requestCart = async (method, data) => {
3223
3224  let response = await fetch('/cart.json', {method: 'GET',headers: {'Content-Type': 'application/json'}})
3225    result = await response.json()
3226
3227    return result.cart
3228
3229  }
3230  const getCart = async (latest = false) => {
3231
3232    let cart = window.__latest_cart
3233
3234    const cart_invalid = !cart || !cart.items || (cart.total_price > 0 && !cart.items.length)
3235
3236    if(latest || cart_invalid) {
3237      cart = await requestCart()
3238    }
3239
3240    cart.items = cart.items || []
3241
3242    return mapCart(cart)
3243
3244  }
3245
3246  const getCheckout = async () => {
3247    mapCheckout(window.__latest_cart || await requestCart())
3248  }
3249
3250  const getOrder = async () => {
3251    mapOrder(window.__latest_cart || await requestCart())
3252  }
3253
3254  //-----------------------//
3255  //        Mappers        //
3256  //-----------------------//
3257
3258  const fallbackAttribute = (object, attribute) => {
3259
3260    if(!Array.isArray(attribute)) {
3261      attribute = [attribute]
3262    }
3263
3264    let final_value = null
3265
3266    do {
3267
3268      final_value = object[attribute.shift()]
3269
3270    } while(!final_value && attribute.length)
3271
3272    return final_value
3273
3274  }
3275
3276  const map = (object, mapper) => {
3277
3278    const newObject = {}
3279
3280    for(const key in mapper) {
3281
3282      // Handle different keys between new and old format
3283      newObject[key] = fallbackAttribute(object, mapper[key])
3284
3285      // Cast price to float
3286      if(newObject[key] && ['price', 'amount', 'discount', 'discounts'].some(x => key.endsWith(x))) {
3287        newObject[key] = parsePrice(newObject[key])
3288      }
3289
3290      if(newObject[key] === undefined) {
3291        delete newObject[key]
3292      }
3293
3294    }
3295
3296    return newObject
3297
3298  }
3299
3300  const mapCart = cart => {
3301
3302    const oldCart = cart
3303
3304    const mapper = {
3305      id: 'id',
3306      currency: 'currency',
3307      item_count: 'item_count',
3308      items: 'items',
3309      total_price: 'total_price',
3310      latest_items: 'latest_items'
3311    }
3312
3313    cart = map(cart, mapper)
3314
3315    const discounts = (oldCart.storewide_discounts || []).concat((oldCart.voucher_discounts || []))
3316
3317    cart.discount_applications = discounts.map(discount => ({
3318      title: discount.voucher_code || null,
3319      value: parsePrice(discount.amount),
3320    }))
3321
3322    cart.original_total_price = cart.items.length
3323    ? cart.items
3324      .map(item => item.original_price)
3325      .reduce((sum, price) => sum + price)
3326    : 0
3327
3328    cart.total_discount = cart.discount_applications.length
3329    ? cart.discount_applications
3330      .map(discount => parsePrice(discount.value))
3331      .reduce((sum, value) => sum + value)
3332    : 0
3333
3334    cart.items = cart.items.map(item => mapLineItem(item))
3335
3336    return cart
3337
3338  }
3339
3340  const mapCheckout = checkout => {
3341
3342    const mapper = {
3343      note: 'note',
3344      attributes: 'note_attributes',
3345      billing_address: 'billing_address',
3346      currency: 'currency',
3347      customer_id: 'customer_id',
3348      discounts_amount: 'total_discount',
3349      id: 'id',
3350      line_items: 'order_item',
3351      order_number: 'order_number',
3352      shipping_address: 'shipping_address',
3353      shipping_price: 'shipping_tax',
3354      shipping_method: 'shipping_method_name',
3355      tax_price: 'total_tax',
3356    }
3357
3358    checkout = map(checkout, mapper)
3359
3360    checkout.requires_shipping = checkout.line_items.some(item => item.shipping_required)
3361
3362    checkout.line_items = checkout.line_items.map(item => mapLineItem(item))
3363
3364    return checkout
3365
3366  }
3367
3368  const mapOrder = order => {
3369
3370    const mapper = {
3371      attributes: 'note_attributes',
3372      billing_address: 'billing_address',
3373      cancelled: 'is_cancelled',
3374      cancelled_at: 'cancelled_at',
3375      created_at: 'created_at',
3376      customer_id: 'customer_id',
3377      // discount_applications: 'discount_applications',
3378      email: 'email',
3379      financial_status: 'financial_status',
3380      fulfillment_status: 'fulfillment_status',
3381      line_items: 'order_item',
3382      note: 'note',
3383      order_number: 'order_number',
3384      phone: 'phone',
3385      shipping_address: 'shipping_address',
3386      shipping_methods: 'shipping_methods',
3387      shipping_price: 'total_shipping',
3388      subtotal_price: 'subtotal_price',
3389      // tax_lines: 'tax_lines',
3390      tax_price: 'total_tax',
3391      total_discounts: 'total_discount',
3392      total_net_amount: 'total_amount_include_transaction',
3393      total_price: 'total_price',
3394      transactions: 'transaction_records',
3395      is_manual_payment: 'is_manual_payment',
3396    }
3397
3398    order.email = order.billing_address.email
3399    order.phone = order.billing_address.phone
3400    order.shipping_method = order.shipping_method_name
3401
3402    order = map(order, mapper)
3403
3404    order.line_items = order.line_items.map(item => mapLineItem(item))
3405    order.transactions = order.transactions.map(transaction => mapTransaction(transaction))
3406
3407    return order
3408
3409  }
3410
3411  const mapLineItem = line_item => {
3412
3413    const old_line_item = line_item
3414
3415    const mapper = {
3416      final_price: 'price',
3417      image: 'img_url',
3418      message: 'message',
3419      original_line_price: 'original_line_price',
3420      original_price: 'original_price',
3421      properties: 'properties',
3422      quantity: 'quantity',
3423      requires_shipping: 'shipping_required',
3424      sku: 'sku',
3425      taxable: 'taxable',
3426      title: 'product_name',
3427      product_name: 'product_name',
3428      url: 'url',
3429      product_id: 'product_id',
3430      variant_id: 'variant_id',
3431      id: ['id', 'i_id'],
3432    }
3433
3434    line_item = map(line_item, mapper)
3435
3436    line_item.product_id = line_item.product_id || (old_line_item.product && old_line_item.product.id) || null
3437    line_item.variant_id = line_item.variant_id || (old_line_item.variant && old_line_item.variant.id) || null
3438    line_item.image      = line_item.image || (old_line_item.image && old_line_item.image.url) || null
3439
3440    return line_item
3441
3442  }
3443
3444  const mapTransaction = transaction => {
3445
3446    const mapper = {
3447      amount: 'amount',
3448      created_at: 'created_at',
3449      gateway: 'gateway_type',
3450      id: 'id',
3451      status: 'status',
3452    }
3453
3454    transaction = map(transaction, mapper)
3455
3456    return transaction
3457
3458  }
3459
3460
3461</script>
3461
3462
3463</body>
3464</html>

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.