1 2<!DOCTYPE html> 3<html> 4<head> 5 <meta charset="utf-8" /> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover, maximum-scale=1.0" /> 7 <meta name="format-detection" content="telephone=no" /> 8 <meta property="og:locale" content="en_US" /> 9 <meta property="og:type" content="website" /> 10 <meta property="og:title" content="Koenen's Water Works Plumbing Co. LLC - Burlington, WI" /> 11 <meta property="og:url" content="https://koenenswaterworksplumbing.com/" /> 12 <meta property="og:image" content="https://du9m0k402rjmo.cloudfront.net/images/P_37496/192e9f94-e967-4440-8e62-a13879fad1f2.jpg" /> 13 <meta property="og:description" content="Koenen's Water Works Plumbing is a full-service residential and commercial plumbing, kitchen and bathroom new construction and remodeling company located in Burlington, WI and has been servicing southeastern Wisconsin area since 2021. Prior to the new name, it was previously a staple in the area for 30+ years as Bruesewitz Plumbing dba WaterWorks Plumbing. As a family owned and operated company, we are serious about ensuring your satisfaction. We offer 24/7 emergency services, sending our plumbers to you when you need them mostâincluding Saturdays, Sundays, nights, and holidays. 14 15We provide 24-hour emergency services, plumbing maintenance, commercial plumbing, boiler installation, repair work, faucet repair and installation, new construction, in-floor heating, remodeling, and custom countertops. We are committed to providing superior customer service and quality workmanship. Our services are designed to meet all of your plumbing, new construction and remodeling needs. From new installations and repairs to remodeling and maintenance, we are here to serve you. Call today!" /> 16 <meta name="description" content="Koenen's Water Works Plumbing is a full-service residential and commercial plumbing, kitchen and bathroom new construction and remodeling company located in Burlington, WI and has been servicing southeastern Wisconsin area since 2021. Prior to the new name, it was previously a staple in the area for 30+ years as Bruesewitz Plumbing dba WaterWorks Plumbing. As a family owned and operated company, we are serious about ensuring your satisfaction. We offer 24/7 emergency services, sending our plumbers to you when you need them mostâincluding Saturdays, Sundays, nights, and holidays. 17 18We provide 24-hour emergency services, plumbing maintenance, commercial plumbing, boiler installation, repair work, faucet repair and installation, new construction, in-floor heating, remodeling, and custom countertops. We are committed to providing superior customer service and quality workmanship. Our services are designed to meet all of your plumbing, new construction and remodeling needs. From new installations and repairs to remodeling and maintenance, we are here to serve you. Call today!" /> 19 <meta name="title" content="Koenen's Water Works Plumbing Co. LLC - Burlington WI" /> 20 <meta name="keywords" content="24/7 Emergency Services,Plumbing,Plumber,Remodeler,Repair Work" /> 21 <title>Koenen's Water Works Plumbing Co. LLC - Burlington, WI</title> 22
22<script src="/Scripts/Profile/googleAnalytics.js" type="text/javascript"></script>
vendor: 112 bytes, lines 22-25
22 23 <script type="text/javascript" src="https://www.google.com/recaptcha/api.js" async defer></script> 24 25
25<script src="https://code.jquery.com/jquery-3.5.0.min.js" integrity="sha256-xNzN2a4ltkB44Mc/Jz3pT4iU1cmeR0FkXs4pru/JxaQ=" crossorigin="anonymous"></script>
25 26 27
27<script>window.jQuery || document.write('
27<script src="/scripts/templates/jquery-3.5.0.min.js"><\/script>')</script>
27 28 29
29<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
29 30 31
31<script>if (typeof (Popper) === 'undefined') { document.write('
31<script src="/scripts/templates/popper.min.js"><\/script>') }</script>
31 32 33 <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/all.css" integrity="sha384-lKuwvrZot6UHsBSfcMvOkWwlCMgc0TaWr+30HWe3a4ltaBwTZhyTEggF5tJv8tbt" crossorigin="anonymous"> 34 35 <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous"> 36 37
37<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js" integrity="sha384-mrcBkRTg0HmTfecoh1I+48Ptm7cAe18uN+3GsS5SXXGSwzpjIhJZkxEJ5jYaZmE" crossorigin="anonymous"></script>
37 38 39
39<script>if (typeof ($.fn.modal) === 'undefined') { document.write('
39<script src="/scripts/templates/bootstrap.min.js"><\/script>') }</script>
39 40 41
41<script src="/Scripts/Templates/googleMaps.js" type="text/javascript"></script>
41 42 <link href="/Content/Templates/custom-bootstrap.css" type="text/css" rel="stylesheet" /> 43
43<script src="/Scripts/bootbox.min.js" type="text/javascript"></script>
43 44
44<script src="/Scripts/Profile/jquery.barrating.1.1.4.js" type="text/javascript"></script>
44 45
45<script src="/Scripts/Templates/cleave.min.js" type="text/javascript"></script>
45 46
46<script src="/Scripts/Templates/cleave-phone.us.js" type="text/javascript"></script>
46 47
47<script src="/Scripts/Templates/slick.min.js" type="text/javascript"></script>
47 48 <link href="/Content/Templates/slick.css" type="text/css" rel="stylesheet" /> 49 <link href="/Content/Templates/slick-theme.css" type="text/css" rel="stylesheet" /> 50
50<script src="/Scripts/Templates/googleMapsMultiLocation.js" type="text/javascript"></script>
vendor: 66 bytes, lines 50-51
50 51 <script src="https://www.google.com/recaptcha/api.js?render=
516LcokacUAAAAAH_snk3O5bpdYwjpC5XAuXNLrJLH
vendor: 40 bytes, lines 51-52
51" type="text/javascript"></script> 52
52<script src="https://player.vimeo.com/api/player.js" type="text/javascript"></script>
52 53 54 <link href="/Content/Templates/chatbot.css" type="text/css" rel="stylesheet" /> 55 56 <meta name="viewport" content="width=device-width, user-scalable=yes,initial-scale=1, maximum-scale=2" /> 57 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> 58 59 60 <style> 61 :root { 62 --text_color: 255, 255, 255, 1; 63 --text_color_rgba: rgba(var(--text_color)); 64 --customer_color: #031733; 65 --post_text_color: 0, 0, 0, 1; 66 --post_text_color_rgba: rgba(var(--post_text_color)); 67 } 68 </style> 69 <link href="/Content/Templates/template_6.css" type="text/css" rel="stylesheet" /> 70 71 <link rel="canonical" href="https://koenenswaterworksplumbing.com/"> 72 73
74<script type="application/ld+json"> 75{ 76 "@context": "https://schema.org", 77 "@graph": [ 78 { 79 "@type": "LocalBusiness", 80 "@id": "https://koenenswaterworksplumbing.com/#localbusiness", 81 "name": "Koenen's Water Works Plumbing Co. LLC", 82 "url": "https://koenenswaterworksplumbing.com/", 83 "description": "Koenen's Water Works Plumbing is a full-service residential and commercial plumbing, kitchen and bathroom new construction and remodeling company located in Burlington, WI and has been servicing southeastern Wisconsin area since 2021. Prior to the new name, it was previously a staple in the area for 30+ years as Bruesewitz Plumbing dba WaterWorks Plumbing. As a family owned and operated company, we are serious about ensuring your satisfaction. We offer 24/7 emergency services, sending our plumbers to you when you need them mostâincluding Saturdays, Sundays, nights, and holidays. We provide 24-hour emergency services, plumbing maintenance, commercial plumbing, boiler installation, repair work, faucet repair and installation, new construction, in-floor heating, remodeling, and custom countertops. We are committed to providing superior customer service and quality workmanship. Our services are designed to meet all of your plumbing, new construction and remodeling needs. From new installations and repairs to remodeling and maintenance, we are here to serve you. Call today!", 84 "image": "https://du9m0k402rjmo.cloudfront.net/images/P_37496/192e9f94-e967-4440-8e62-a13879fad1f2.jpg", 85 "logo": "https://du9m0k402rjmo.cloudfront.net/images/P_37496/192e9f94-e967-4440-8e62-a13879fad1f2.jpg", 86 "address": { 87 "@type": "PostalAddress", 88 "streetAddress": "1201 Milwaukee Ave, Suite B", 89 "addressLocality": "Burlington", 90 "addressRegion": "WI", 91 "postalCode": "53105", 92 "addressCountry": "US" 93 }, 94 "telephone": "(262) 763-7385", 95 "email": "[email protected]", 96 "geo": { 97 "@type": "GeoCoordinates", 98 "latitude": 42.6954223, 99 "longitude": -88.2632462 100 }, 101 "openingHoursSpecification": [ 102 { 103 "@type": "OpeningHoursSpecification", 104 "dayOfWeek": "Monday", 105 "opens": "07:30", 106 "closes": "16:30" 107 }, 108 { 109 "@type": "OpeningHoursSpecification", 110 "dayOfWeek": "Tuesday", 111 "opens": "07:30", 112 "closes": "16:30" 113 }, 114 { 115 "@type": "OpeningHoursSpecification", 116 "dayOfWeek": "Wednesday", 117 "opens": "07:30", 118 "closes": "16:30" 119 }, 120 { 121 "@type": "OpeningHoursSpecification", 122 "dayOfWeek": "Thursday", 123 "opens": "07:30", 124 "closes": "16:30" 125 }, 126 { 127 "@type": "OpeningHoursSpecification", 128 "dayOfWeek": "Friday", 129 "opens": "07:30", 130 "closes": "16:30" 131 }, 132 { 133 "@type": "OpeningHoursSpecification", 134 "dayOfWeek": "Saturday", 135 "opens": "08:00", 136 "closes": "12:00" 137 } 138 ], 139 "paymentAccepted": "Visa, MasterCard, American Express, Discover, Debit Cards, Personal Checks", 140 "sameAs": [ 141 "https://www.yelp.com/biz/koenens-water-works-plumbing-burlington", 142 "https://www.facebook.com/koenenwaterworksplumbing", 143 "https://www.instagram.com/koenenswaterworksplumbing/" 144 ] 145 }, 146 { 147 "@type": "WebSite", 148 "@id": "https://koenenswaterworksplumbing.com/#website", 149 "url": "https://koenenswaterworksplumbing.com/", 150 "name": "Koenen's Water Works Plumbing Co. LLC", 151 "description": "Koenen's Water Works Plumbing is a full-service residential and commercial plumbing, kitchen and bathroom new construction and remodeling company located in Burlington, WI and has been servicing southeastern Wisconsin area since 2021. Prior to the new name, it was previously a staple in the area for 30+ years as Bruesewitz Plumbing dba WaterWorks Plumbing. As a family owned and operated company, we are serious about ensuring your satisfaction. We offer 24/7 emergency services, sending our plumbers to you when you need them mostâincluding Saturdays, Sundays, nights, and holidays. We provide 24-hour emergency services, plumbing maintenance, commercial plumbing, boiler installation, repair work, faucet repair and installation, new construction, in-floor heating, remodeling, and custom countertops. We are committed to providing superior customer service and quality workmanship. Our services are designed to meet all of your plumbing, new construction and remodeling needs. From new installations and repairs to remodeling and maintenance, we are here to serve you. Call today!", 152 "potentialAction": { 153 "@type": "SearchAction", 154 "target": "https://koenenswaterworksplumbing.com/?s={search_term_string}", 155 "query-input": "required name=search_term_string" 156 } 157 }, 158 { 159 "@type": "WebPage", 160 "@id": "https://koenenswaterworksplumbing.com/#webpage", 161 "url": "https://koenenswaterworksplumbing.com/", 162 "name": "Koenen's Water Works Plumbing Co. LLC - Burlington, WI", 163 "description": "Koenen's Water Works Plumbing is a full-service residential and commercial plumbing, kitchen and bathroom new construction and remodeling company located in Burlington, WI and has been servicing southeastern Wisconsin area since 2021. Prior to the new name, it was previously a staple in the area for 30+ years as Bruesewitz Plumbing dba WaterWorks Plumbing. As a family owned and operated company, we are serious about ensuring your satisfaction. We offer 24/7 emergency services, sending our plumbers to you when you need them mostâincluding Saturdays, Sundays, nights, and holidays. We provide 24-hour emergency services, plumbing maintenance, commercial plumbing, boiler installation, repair work, faucet repair and installation, new construction, in-floor heating, remodeling, and custom countertops. We are committed to providing superior customer service and quality workmanship. Our services are designed to meet all of your plumbing, new construction and remodeling needs. From new installations and repairs to remodeling and maintenance, we are here to serve you. Call today!", 164 "isPartOf": { 165 "@id": "https://koenenswaterworksplumbing.com/#website" 166 }, 167 "about": { 168 "@id": "https://koenenswaterworksplumbing.com/#localbusiness" 169 }, 170 "primaryImageOfPage": { 171 "@type": "ImageObject",
172 "url": "https://du9m0k402rjmo.cloudfront.net/images/P_37496/192e9f94-e967-4440-8e62-a13879fad1f2.jpg" 173 }, 174 "breadcrumb": { 175 "@type": "BreadcrumbList", 176 "itemListElement": [ 177 { 178 "@type": "ListItem", 179 "position": 1, 180 "name": "Home", 181 "item": "https://koenenswaterworksplumbing.com/" 182 } 183 ] 184 } 185 }, 186 { 187 "@type": "Service", 188 "@id": "https://koenenswaterworksplumbing.com/#service", 189 "name": "Our Services", 190 "provider": { 191 "@id": "https://koenenswaterworksplumbing.com/#localbusiness" 192 }, 193 "serviceType": [ 194 "Plumbing Services â We provide full-service residential and commercial plumbing solutions, including expert repair, maintenance, and installation. Our team handles everything from leak diagnosis and drain piping replacement to certified RPZ testing and gas piping. With free estimates and 24-hour emergency service, weâre ready when you need us most.", 195 "Water Systems â Our specialists install and service water heaters, boilers, pressure tanks, and well pumps to ensure consistent water flow and temperature. We also offer water treatment solutions, including iron filtration and water softeners, to improve water quality and protect your plumbing system.", 196 "Sewer & Septic Solutions â We offer advanced drain cleaning and sewer video inspections to identify and resolve blockages. Our team is experienced in septic repairs and installs E-One grinder sewage pumps for efficient waste management in challenging environments.", 197 "Remodeling & Fixtures â From kitchen and bath remodels to custom cabinetry and countertops, we bring your vision to life. Our interactive showroom features Merillat cabinets and a wide selection of materials to help you design your ideal space with expert plumbing integration.", 198 "Seasonal & Specialty Services â We provide winterization services to protect your plumbing during freezing temperatures and offer pool chemical support and repair to keep your recreational systems safe and functional year-round." 199 ], 200 "description": "Professional services offered by Koenen's Water Works Plumbing Co. LLC" 201 } 202 ] 203} 204</script>
204</head> 205<body> 206 <div id="bootstrapCssTest" class="d-none"></div> 207
207<script> 208 $(function () { 209 210 if ($('#bootstrapCssTest').is(':visible')) { 211 $("head").prepend('<link rel="stylesheet" href="/content/templates/bootstrap.min.css">'); 212 } 213 }); 214 </script>
214 215 216 217 218 219<input type="hidden" id="areaMarkers" /> 220 221<!-- NAVBAR --> 222<div class="container-fullwidth fixed-top"> 223 224 225 226 227 228<header class="content-header custom-background-color d-flex flex-wrap align-items-center justify-content-between py-0 px-2"> 229 230 231 <div class="nav-image-mobile-left"> 232 <a href="#home-section" id="HomeNav" onclick="DisplayPage('#homePage')"> 233 <img src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/192e9f94-e967-4440-8e62-a13879fad1f2.jpg" alt="navbar logo" class="d-line-block align-top nav-logo" /> 234 </a> 235 </div> 236 <div class="nav-location pt-2"> 237 <ul class="mx-auto p-0 header-address d-flex flex-wrap justify-content-center"> 238 239 <li class="nav-business_name text-center header-item mx-1 px-1 text-font-color"> 240 Koenen's Water Works Plumbing Co. LLC 241 </li> 242 243 244 <li class="text-center header-item mx-1 px-1 text-font-color"> 245 246 1201 Milwaukee Ave Suite B 247 </li> 248 249 <li class="text-center header-item mx-1 px-1 text-font-color"> 250 Burlington, WI 53105 251 </li> 252 <li class="navbar-hours-sm text-center header-item mx-1 px-1"> 253 <a href="#" id="navbar-hours-sm" class="text-font-color" onclick="DisplayPage('#contactPage')"><i class="fas fa-clock fa-lg px-1 text-font-color"></i>Click Here for Hours</a> 254 </li> 255 256 257 <li class="nav-phone-sm text-center header-item mx-1 px-1"> 258 <a id="PhoneNav" href="tel:2627637385" class="phone-nav-mobile text-font-color"> 259 <i class="fas fa-phone fa-inverse fa-xs fa-rotate-90"></i> 260 (262) 763-7385 261 </a> 262 </li> 263 </ul> 264 </div> 265 266 267 268 <div class="navbar-hours pb-1 mx-auto"> 269 <a href="#" id="navbar-hours" class="text-font-color" onclick="DisplayPage('#contactPage')"><i class="fas fa-clock fa-lg px-1 text-font-color"></i>Click Here for Hours</a> 270 </div> 271 272 273 274 <div class="nav-phone-social pb-1 d-flex flex-wrap justify-content-center"> 275 276 <div class="nav-phone flex-column align-self-center mx-1 px-1 pb-1"> 277 <a id="PhoneNav" href="tel:2627637385" class="phone-nav-mobile text-font-color"> 278 <i class="fas fa-phone fa-inverse fa-xs fa-rotate-90"></i> 279 (262) 763-7385 280 </a> 281 </div> 282 <div class="nav-social mx-1 px-1"> 283 <div class="mx-auto text-center d-flex flex-wrap justify-content-center"> 284 <div class="m-1"> 285 <a class="text-font-color social-link-footer" href="https://www.facebook.com/koenenwaterworksplumbing" target="_blank" id="facebook-social-footer" title="Facebook"> 286 <i class="fab fa-facebook-f fa-lg text-font-color"></i> 287 </a> 288 </div> 289 <div class="m-1"> 290 <a class="text-font-color social-link-footer" href="https://www.yelp.com/biz/koenens-water-works-plumbing-burlington" target="_blank" id="yelp-social-footer" title="Yelp"> 291 <i class="fab fa-yelp fa-lg text-font-color"></i> 292 </a> 293 </div> 294 <div class="m-1"> 295 <a class="text-font-color social-link-footer" href="https://www.instagram.com/koenenswaterworksplumbing/" target="_blank" id="instagram-social-footer" title="Instagram"> 296 <i class="fab fa-instagram fa-lg text-font-color"></i> 297 </a> 298 </div> 299 </div> 300 </div> 301 </div> 302</header> 303 304 305<nav class="bg-default-color navbar navbar-light bg-light navbar-expand-xl pt-1 pb-2"> 306 307 308 <div class="nav-image bg-default-color bg-light flex-column text-center nav
308-image-desktop"> 309 <a href="#home-section" class="navbar-brand ml-3" id="HomeNav" onclick="DisplayPage('#homePage')"> 310 <img src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/192e9f94-e967-4440-8e62-a13879fad1f2.jpg" alt="navbar logo" class="d-line-block align-top nav-logo" /> 311 </a> 312 </div> 313 314 <button class="navbar-toggler nav-menu collapsed" type="button" data-toggle="collapse" data-target="#navbarToggler" aria-controls="navbarToggler" aria-expanded="false" aria-label="Toggle navigation"> 315 <span class="navbar-toggler-icon"></span> 316 <span class="my-1 mx-2 close">X</span> 317 </button> 318 319 <div class="collapse navbar-collapse flex-column mx-auto" id="navbarToggler"> 320 321 <div class="d-none d-xl-block nav-section"> 322 <div class="navbar-nav d-flex flex-wrap align-items-center"> 323 324 325<div class="col nav-item text-center header-item mx-auto text-nowrap"> <a href="#" id="HomePageNavigationLink" class="nav-link p-3" onclick="DisplayPage('#homePage')">Home</a> 326</div><div class="col nav-item text-center header-item mx-auto text-nowrap"> <a href="#" id="AboutPageNavigationLink" class="nav-link p-3" onclick="DisplayPage('#aboutPage')">About</a> 327</div><div class="col nav-item text-center header-item mx-auto text-nowrap"> <a target="_blank" href="https://koenenswaterworksplumbing.com/optimamedia/products/P_37496/299f942e-f2df-4975-91ff-4afc48b98a3e.pdf" id="DocumentPageNavigationLink" class="nav-link p-3">We are Hiring</a> 328</div><div class="col nav-item text-center header-item mx-auto text-nowrap"> <a href="#" id="ServicesPageNavigationLink" class="nav-link p-3" onclick="DisplayPage('#servicesPage')">Services</a> 329</div><div class="col nav-item text-center header-item mx-auto text-nowrap"> <a href="#" id="PhotosNavigationLink" class="nav-link p-3" onclick="DisplayPage('#imageryPage')">Gallery</a> 330</div><div class="col nav-item text-center header-item mx-auto text-nowrap"> <a href="#" id="PostsPageNavigationLink" class="nav-link p-3" onclick="DisplayPage('#postsPage')">Posts</a> 331</div><div class="col nav-item text-center header-item mx-auto text-nowrap"> <a href="#" id="testimonialsPageNavigationLink" class="nav-link p-3" onclick="DisplayPage('#testimonialsPage')">Testimonials</a> 332</div><div class="col nav-item text-center header-item mx-auto text-nowrap"> <a href="#" id="GSVPageNavigationLink" class="nav-link p-3" onclick="DisplayPage('#gsvPage')">360 Tour</a> 333</div><div class="col nav-item text-center header-item mx-auto text-nowrap"> <a href="#" id="ContactPageNavigationLink" class="nav-link p-3" onclick="DisplayPage('#contactPage')">Contact</a> 334</div> </div> 335 </div> 336 337 <div class="d-xs-block d-xl-none"> 338 <ul class="navbar-nav mx-auto mr-auto mt-2 mt-xl-0 mb-2"> 339 <li class="nav-item text-center header-item mr-1 ml-1"> 340 Koenen's Water Works Plumbing Co. LLC 341 </li> 342 343 344<li class="nav-item text-center header-item mr-1 ml-1 text-nowrap"> <a href="#" id="HomePageNavigationLink" class="nav-link p-3" onclick="DisplayPage('#homePage')">Home</a> 345</li><li class="nav-item text-center header-item mr-1 ml-1 text-nowrap"> <a href="#" id="AboutPageNavigationLink" class="nav-link p-3" onclick="DisplayPage('#aboutPage')">About</a> 346</li><li class="nav-item text-center header-item mr-1 ml-1 text-nowrap"> <a target="_blank" href="https://koenenswaterworksplumbing.com/optimamedia/products/P_37496/299f942e-f2df-4975-91ff-4afc48b98a3e.pdf" id="DocumentPageNavigationLink" class="nav-link p-3">We are Hiring</a> 347</li><li class="nav-item text-center header-item mr-1 ml-1 text-nowrap"> <a href="#" id="ServicesPageNavigationLink" class="nav-link p-3" onclick="DisplayPage('#servicesPage')">Services</a> 348</li><li class="nav-item text-center header-item mr-1 ml-1 text-nowrap"> <a href="#" id="PhotosNavigationLink" class="nav-link p-3" onclick="DisplayPage('#imageryPage')">Gallery</a> 349</li><li class="nav-item text-center header-item mr-1 ml-1 text-nowrap"> <a href="#" id="PostsPageNavigationLink" class="nav-link p-3" onclick="DisplayPage('#postsPage')">Posts</a> 350</li><li class="nav-item text-center header-item mr-1 ml-1 text-nowrap"> <a href="#" id="testimonialsPageNavigationLink" class="nav-link p-3" onclick="DisplayPage('#testimonialsPage')">Testimonials</a> 351</li><li class="nav-item text-center header-item mr-1 ml-1 text-nowrap"> <a href="#" id="GSVPageNavigationLink" class="nav-link p-3" onclick="DisplayPage('#gsvPage')">360 Tour</a> 352</li><li class="nav-item text-center header-item mr-1 ml-1 text-nowrap"> <a href="#" id="ContactPageNavigationLink" class="nav-link p-3" onclick="DisplayPage('#contactPage')">Contact</a> 353</li> </ul> 354 </div> 355 </div> 356</nav> 357 358</div> 359 360<div id="pages" class="pages-left"> 361 <!--Home Page Information--> 362 <div class="content collapse show bg-alt-color" id="homePage"> 363 364<div class="d-flex flex-wrap"> 365 <div class="w-100 mx-auto home-banner"> 366 <div class="parallax w-100"> 367 <div class="img-fluid banner-image " style="background-image: url(https://du9m0k402rjmo.
367cloudfront.net/images/P_37496/fde5518d-399a-44cc-bd74-fa1a8de66e46.jpg)"></div> 368 <div class="home-content"> 369 <div class="d-flex flex-wrap justify-content-center align-items-center px-2"></div> 370 </div> 371 </div> 372 </div> 373 374 375 <div class="d-flex align-items-center justify-content-center col-12 text-center description mx-auto slogan p-3 slogan-speakable" style="color: #4A879E; opacity: 0.7"> 376 Emergency Services Available 24/7! 377 </div> 378 <div class="slider-attributes-container"> 379 <div class="slider slider-attributes mx-auto"> 380 <div> 381 <div class="image-slider-attributes-border m-5"> 382 <div class="image-slider-attributes-border-inner"> 383 <div class="image-slider-attributes custom-background-color d-flex justify-content-center align-items-center"> 384 <span class="m-2 text-font-color">Sump Pumps</span> 385 </div> 386 </div> 387 </div> 388 </div> 389 <div> 390 <div class="image-slider-attributes-border m-5"> 391 <div class="image-slider-attributes-border-inner"> 392 <div class="image-slider-attributes custom-background-color d-flex justify-content-center align-items-center"> 393 <span class="m-2 text-font-color">Water Heaters & Boilers</span> 394 </div> 395 </div> 396 </div> 397 </div> 398 <div> 399 <div class="image-slider-attributes-border m-5"> 400 <div class="image-slider-attributes-border-inner"> 401 <div class="image-slider-attributes custom-background-color d-flex justify-content-center align-items-center"> 402 <span class="m-2 text-font-color">Iron Filtration & Water Softeners</span> 403 </div> 404 </div> 405 </div> 406 </div> 407 <div> 408 <div class="image-slider-attributes-border m-5"> 409 <div class="image-slider-attributes-border-inner"> 410 <div class="image-slider-attributes custom-background-color d-flex justify-content-center align-items-center"> 411 <span class="m-2 text-font-color">Pressure Tanks & Well Pumps</span> 412 </div> 413 </div> 414 </div> 415 </div> 416 <div> 417 <div class="image-slider-attributes-border m-5"> 418 <div class="image-slider-attributes-border-inner"> 419 <div class="image-slider-attributes custom-background-color d-flex justify-content-center align-items-center"> 420 <span class="m-2 text-font-color">E-One Grinder Sewage Pumps</span> 421 </div> 422 </div> 423 </div> 424 </div> 425 <div> 426 <div class="image-slider-attributes-border m-5"> 427 <div class="image-slider-attributes-border-inner"> 428 <div class="image-slider-attributes custom-background-color d-flex justify-content-center align-items-center"> 429 <span class="m-2 text-font-color">High-End Finishes and Fixtures</span> 430 </div> 431 </div> 432 </div> 433 </div> 434 </div> 435 </div> 436 <nav id="circle-attributes" class="navbar-attribute custom-background-color w-100"> 437 <div class="w-100 d-flex flex-row justify-content-center text-center"> 438 <div class="inner py-1"> 439 <div class="col nav-item text-center header-item mx-auto text-wrap">
440 <span class="nav-link">Sump Pumps</span> 441 </div> 442 <div class="col nav-item text-center header-item mx-auto text-wrap"> 443 <span class="nav-link">Water Heaters & Boilers</span> 444 </div> 445 <div class="col nav-item text-center header-item mx-auto text-wrap"> 446 <span class="nav-link">Iron Filtration & Water Softeners</span> 447 </div> 448 <div class="col nav-item text-center header-item mx-auto text-wrap"> 449 <span class="nav-link">Pressure Tanks & Well Pumps</span> 450 </div> 451 <div class="col nav-item text-center header-item mx-auto text-wrap"> 452 <span class="nav-link">E-One Grinder Sewage Pumps</span> 453 </div> 454 <div class="col nav-item text-center header-item mx-auto text-wrap"> 455 <span class="nav-link">High-End Finishes and Fixtures</span> 456 </div> 457 </div> 458 </div> 459 </nav> 460 <div class="w-100 w-lg-75 mx-auto text-center p-4"> 461 <div class="p-2 section-header text-center"> 462 Established in 1978 463 </div> 464 <div class="p-2 section-information text-center"> 465 Located in Burlington, WI 466 </div> 467 </div> 468 469 470 <div class="w-100 w-lg-75 mx-auto mt-4 mb-4"> 471 <div class="slider slider-single w-100"> 472 <div class="image-slider m-2"> 473 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/9822d27a-a440-4082-bcd3-d75dd86ffc18.jpg" class="img-fluid text-center mx-auto" /> 474 </div> 475 <div class="image-slider m-2"> 476 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/7b59338d-e022-4c31-ad97-6b1d9d8ee119.jpg" class="img-fluid text-center mx-auto" /> 477 </div> 478 <div class="image-slider m-2"> 479 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/fc866e35-d2f8-4200-809d-eda7b64a7432.jpg" class="img-fluid text-center mx-auto" /> 480 </div> 481 <div class="image-slider m-2"> 482 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/8c609b90-a03f-492c-bb86-958eec245e10.jpg" class="img-fluid text-center mx-auto" /> 483 </div> 484 <div class="image-slider m-2"> 485 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/33871ee3-b0ac-4d37-ae00-b0e0e3590451.jpg" class="img-fluid text-center mx-auto" /> 486 </div> 487 <div class="image-slider m-2"> 488 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/f54608e7-9e0c-4ce4-9021-80cc3b038433.jpg" class="img-fluid text-center mx-auto" /> 489 </div> 490 <div class="image-slider m-2"> 491 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/dcdcf430-6cc5-497d-b3dd-90f1031cc18d.jpg" class="img-fluid text-center mx-auto" /> 492 </div> 493 <div class="image-slider m-2"> 494 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/d30303df-a085-4560-994f-fd8574e85c54.jpg" class="img-fluid text-center mx-auto" /> 495 </div> 496 <div class="image-slider m-2"> 497 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/1f200740-571d-4846-bb2d-90e1e8d8de35.jpg" class="img-fluid text-center mx-auto" /> 498 </div> 499 <div class="image-slider m-2"> 500 <img alt="Image" src="https://du9m0k402rjmo.
500cloudfront.net/images/P_37496/406f4b59-1853-4702-9b5f-6da17e60b3e7.jpg" class="img-fluid text-center mx-auto" /> 501 </div> 502 <div class="image-slider m-2"> 503 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/9bbcdf42-cf59-438b-82bd-e0ce1ff14cfa.jpg" class="img-fluid text-center mx-auto" /> 504 </div> 505 <div class="image-slider m-2"> 506 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/362f2daf-dfeb-4236-9c80-9df5edda4f02.jpg" class="img-fluid text-center mx-auto" /> 507 </div> 508 <div class="image-slider m-2"> 509 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/1d44e50f-d2bc-415f-9a0b-95b3dc719ee7.jpg" class="img-fluid text-center mx-auto" /> 510 </div> 511 <div class="image-slider m-2"> 512 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/4d220349-9ea8-4f89-a169-4998b2fd38da.jpg" class="img-fluid text-center mx-auto" /> 513 </div> 514 <div class="image-slider m-2"> 515 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/b868af7f-ad95-49b9-99b7-cfa93fa66fe1.jpg" class="img-fluid text-center mx-auto" /> 516 </div> 517 <div class="image-slider m-2"> 518 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/70af784f-d05d-46dc-999a-23852b90c69b.jpg" class="img-fluid text-center mx-auto" /> 519 </div> 520 <div class="image-slider m-2"> 521 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/a86ae628-5fa4-49f3-b97d-941128f3bde2.jpg" class="img-fluid text-center mx-auto" /> 522 </div> 523 <div class="image-slider m-2"> 524 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/0ae8daef-8717-492b-a749-16f1779846e7.png" class="img-fluid text-center mx-auto" /> 525 </div> 526 <div class="image-slider m-2"> 527 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/d61e30e7-fe2c-4a05-b4cd-f2b08e1703ee.png" class="img-fluid text-center mx-auto" /> 528 </div> 529 </div> 530 <div class="slider slider-nav w-45 mx-auto mt-3 mb-3"> 531 <div class="image-slider-thumbnail"> 532 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/9822d27a-a440-4082-bcd3-d75dd86ffc18.jpg" class="img-fluid text-center mx-auto" /> 533 </div> 534 <div class="image-slider-thumbnail"> 535 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/7b59338d-e022-4c31-ad97-6b1d9d8ee119.jpg" class="img-fluid text-center mx-auto" /> 536 </div> 537 <div class="image-slider-thumbnail"> 538 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/fc866e35-d2f8-4200-809d-eda7b64a7432.jpg" class="img-fluid text-center mx-auto" /> 539 </div> 540 <div class="image-slider-thumbnail"> 541 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/8c609b90-a03f-492c-bb86-958eec245e10.jpg" class="img-fluid text-center mx-auto" /> 542 </div> 543 <div class="image-slider-thumbnail"> 544 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/33871ee3-b0ac-4d37-ae00-b0e0e3590451.jpg" class="img-fluid text-center mx-auto" /> 545 </div> 546 <div class="image-slider-thumbnail"> 547 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/f54608e7-9e0c-4ce4-9021-80cc3b038433.jpg" class="img-fluid text-center mx-auto" /> 548 </div> 549 <div class="image-slider-thumbnail"> 550 <img alt="Image" src="https://du9m0k402rjmo.
550cloudfront.net/images/P_37496/dcdcf430-6cc5-497d-b3dd-90f1031cc18d.jpg" class="img-fluid text-center mx-auto" /> 551 </div> 552 <div class="image-slider-thumbnail"> 553 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/d30303df-a085-4560-994f-fd8574e85c54.jpg" class="img-fluid text-center mx-auto" /> 554 </div> 555 <div class="image-slider-thumbnail"> 556 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/1f200740-571d-4846-bb2d-90e1e8d8de35.jpg" class="img-fluid text-center mx-auto" /> 557 </div> 558 <div class="image-slider-thumbnail"> 559 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/406f4b59-1853-4702-9b5f-6da17e60b3e7.jpg" class="img-fluid text-center mx-auto" /> 560 </div> 561 <div class="image-slider-thumbnail"> 562 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/9bbcdf42-cf59-438b-82bd-e0ce1ff14cfa.jpg" class="img-fluid text-center mx-auto" /> 563 </div> 564 <div class="image-slider-thumbnail"> 565 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/362f2daf-dfeb-4236-9c80-9df5edda4f02.jpg" class="img-fluid text-center mx-auto" /> 566 </div> 567 <div class="image-slider-thumbnail"> 568 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/1d44e50f-d2bc-415f-9a0b-95b3dc719ee7.jpg" class="img-fluid text-center mx-auto" /> 569 </div> 570 <div class="image-slider-thumbnail"> 571 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/4d220349-9ea8-4f89-a169-4998b2fd38da.jpg" class="img-fluid text-center mx-auto" /> 572 </div> 573 <div class="image-slider-thumbnail"> 574 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/b868af7f-ad95-49b9-99b7-cfa93fa66fe1.jpg" class="img-fluid text-center mx-auto" /> 575 </div> 576 <div class="image-slider-thumbnail"> 577 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/70af784f-d05d-46dc-999a-23852b90c69b.jpg" class="img-fluid text-center mx-auto" /> 578 </div> 579 <div class="image-slider-thumbnail"> 580 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/a86ae628-5fa4-49f3-b97d-941128f3bde2.jpg" class="img-fluid text-center mx-auto" /> 581 </div> 582 <div class="image-slider-thumbnail"> 583 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/0ae8daef-8717-492b-a749-16f1779846e7.png" class="img-fluid text-center mx-auto" /> 584 </div> 585 <div class="image-slider-thumbnail"> 586 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/d61e30e7-fe2c-4a05-b4cd-f2b08e1703ee.png" class="img-fluid text-center mx-auto" /> 587 </div> 588 </div> 589 </div> 590 <div class="w-100 p-0 mt-4 mb-4"> 591 <iframe id='gbvFrame' src="https://www.google.com/maps/embed?pb=!4v1686837467589!6m8!1m7!1sCAoSLEFGMVFpcE93M2xJQmFHRk1qQVNrY0tVQmFXZVlTc1lfZGVOSnR1RV9tWThS!2m2!1d42.69526939105222!2d-88.26339463412708!3f30.490778227980176!4f-3.414025499493107!5f0.7820865974627469" width="100%" height="450px;" style="border:0;" allowfullscreen="" loading="lazy" referrerpolicy="no-referrer-when-downgrade"></iframe> 592 </div> 593 594 <div class="w-100 mx-auto bg-image-container"> 595 <div class="bg-image " style="background-image: url(https://du9m0k402rjmo.cloudfront.net/images/P_37496/f2f8d28d-4acd-4678-962b-9c68803cb4e1.jpg)"></div> 596 <div class="w-lg-40 p-3 mt-md-5 mb-md-5"> 597 <div class="mx-auto p-3 testimonial-blurb"> 598 <div class="blurb-review-info"> 599 <p class="paragraph-content"> 600 <div class="blurb-rating m-2 mt-3"> 601 <img class="star-rating-image" src="/content/profile/images/star_yellow_5.0.png" /> 602 </div> 603 <div class="blurb-authordate m-2 mb-3">
604 <span class="blurb-author"> 605- Danielle </span> 606 <span class="blurb-date"> 6079/26/2026 </span> 608 </div> 609 <div class="blurb m-2 mt-3 mb-3"> 610 611"They helped us with a water softener and hose bib. Communication was great, the customer service was excellent, and the prices were fair. Iâd absolutely schedule with them again!" </div> 612 <div class="blurb-more m-2 mt-3"> 613 <div class="d-flex flex-wrap flex-column text-center mx-auto mt-1 mb-1 p-0"> 614 <a id="testimonialsBlurbMore" href="#testimonialsPage" class="d-flex align-items-center justify-content-center btn btn-secondary p-2 mr-auto testimonialsBlurbMore" > 615 See More <i class="fas fa-arrow-right"></i> 616 </a> 617 </div> 618 </div> 619 </p> 620</div> 621 </div> 622 </div> 623 </div> 624</div> 625 </div> 626 627 <!--About Page Information--> 628 <div class="content collapse bg-alt-color" id="aboutPage"></div> 629 630 <!--Services Page Information--> 631 <div class="content collapse bg-alt-color" id="servicesPage"></div> 632 633 <!--Testimonial Page Information--> 634 <div class="content collapse bg-alt-color" id="testimonialsPage"></div> 635 636 <!-- REVIEW MODAL --> 637 <div id="reviewFormParentContainer"></div> 638 639 <!--Contact Page Information--> 640 <div class="content collapse bg-alt-color" id="contactPage"></div> 641 642 <!--Imagery Page Information--> 643 <div class="content collapse bg-alt-color" id="imageryPage"></div> 644 645 <!--Posts Page Information--> 646 <div class="content collapse bg-alt-color" id="postsPage"> 647 648 649<div class="d-flex flex-wrap"> 650 651 652 <div class="w-100 mx-auto text-center banner"> 653 <div class="parallax w-100 d-flex flex-wrap justify-content-center align-items-center"> 654 <div class="banner-image " style="background-image: url(https://du9m0k402rjmo.cloudfront.net/images/P_37496/d2fe696c-612a-4fb1-b37e-a4373cc1b72f.jpg)"></div> 655 </div> 656 </div> 657 658 659 <div class="w-100 mx-auto"> 660 <div class="d-flex flex-row flex-wrap justify-content-center text-center"> 661 <div class="posts-partial-content w-100"> 662 663 <div class="postsInfo" id="testimonialPostsInfo"></div> 664 <div class="text-center m-3"> 665 <button type="button" id="prevPosts" class="btn btn-light btn-md" disabled><i class="fas fa-angle-left"></i> Previous</button> 666 <button type="button" id="nextPosts" class="btn btn-light btn-md">Next <i class="fas fa-angle-right"></i></button> 667 </div> 668 </div> 669 </div> 670 </div> 671</div> 672 </div> 673 674 <!--Locations Page Information--> 675 <div class="content collapse bg-alt-color" id="locationsPage"></div> 676 677 <!--360 Tour Page--> 678 <div class="content collapse bg-alt-color pt-3" id="gsvPage"></div> 679 680 <!--FAQ Page Information--> 681 <div class="content collapse bg-alt-color" id="faqPage"></div> 682 683 <!--Additional Content Page--> 684 <div class="content collapse bg-alt-color pt-3" id="contentPage"></div> 685 686</div> 687 688<!--FOOTER Information--> 689<footer id="footer-container" class="footer custom-background-color"> 690<div class="d-flex flex-wrap text-center justify-content-center p-3"> 691 <div class="footer-content mx-auto"> 692 693 <!--Payment Methods --> 694 <div id="paymentTypeDark" class="mx-auto mt-2 mb-2 text-center d-flex flex-wrap justify-content-center paymentType"> 695 <div class="m-2"> 696 <img alt="Payment Image" class="img-fluid text-center mx-auto payment-img" src="/content/Templates/images/payment/visa.png" /> 697 </div> 698 <div class="m-2"> 699 <img alt="Payment Image" class="img-fluid text-center mx-auto payment-img" src="/content/Templates/images/payment/mastercard.png" /> 700 </div> 701 <div class="m-2"> 702 <img alt="Payment Image" class="img-fluid text-center mx-auto payment-img" src="/content/Templates/images/payment/americanexpress.png" /> 703 </div> 704 <div class="m-2"> 705 <img alt="Payment Image" class="img-fluid text-center mx-auto payment-img" src="/content/Templates/images/payment/discover.png" /> 706 </div> 707 </div> 708 <div id="paymentTypeLight" class="mx-auto mt-2 mb-2 text-center d-flex flex-wrap justify-content-center paymentType"> 709 <div class="m-2"> 710 <img alt="Payment Image" class="img-fluid text-center mx-auto payment-img" src="/content/Templates/images/payment/visa_white.png" /> 711 </div> 712 <div class="m-2"> 713 <img alt="Payment Image" class="img-fluid text-center mx-auto payment-img" src="/content/Templates/images/payment/mastercard_white.png" /> 714 </div> 715 <div class="m-2"> 716 <img alt="Payment Image" class="img-fluid text-center mx-auto payment-img" src="/content/Templates/images/payment/americanexpress_white.png" /> 717 </div> 718 <div class="m-2"> 719 <img alt="Payment Image" class="img-fluid text-center mx-auto payment-img" src="/content/Templates/images/payment/discover_white.png" /> 720 </div> 721 </div> 722 723 <div id="footer-address"> 724 <div class="d-flex flex-wrap justify-content-center pt-1"> 725 <ul class="mx-auto p-0 mt-2 mt-lg-0 mb-2 business-info-footer d-flex flex-wrap justify-content-center"> 726 <li class="text-center mr-1 ml-1 pl-1 pr-1 text-font-color footer-business-name"> 727 Koenen's Water Works Plumbing Co. LLC 728 </li> 729 <li class="text-center header-item mr-1 ml-1 pl-1 pr-1 text-font-color"> 730 731 1201 Milwaukee Ave Suite B 732 </li> 733 <li class="text-center header-item mr-1 ml-1 pl-1 pr-1 text-font-color"> 734 Burlington, WI 53105 735 </li> 736 </ul> 737 </div> 738 </div> 739 <div class="d-flex flex-wrap flex-column text-center mx-auto mt-1 mb-1 p-0"> 740 <a id="phoneLink" href="tel:2627637385" class="phoneLinkInput d-flex align-items-start justify-content-center btn btn-secondary p-2 mx-auto text-font-color"> 741 (262) 763-7385 742 </a> 743 </div> 744 <div class="mt-3"> 745 <div class="mx-auto mt-2 mb-2 text-center d-flex flex-wrap justify-content-center"> 746 <div class="m-2"> 747 <a class="text-font-color social-link-footer" href="https://www.facebook.com/koenenwaterworksplumbing" target="_blank" id="facebook-social-footer" title="Facebook"> 748 <i class="fab fa-facebook-f fa-lg"></i> 749 </a> 750 </div> 751 <div class="m-2"> 752 <a class="text-font-color social-link-footer" href="https://www.yelp.com/biz/koenens-water-works-plumbing-burlington" target="_blank" id="yelp-social-footer" title="Yelp"> 753 <i class="fab fa-yelp fa-lg"></i> 754 </a> 755 </div> 756 <div class="m-2"> 757 <a class="text-font-color social-link-footer" href="https://www.instagram.com/koenenswaterworksplumbing/" target="_blank" id="instagram-social-footer" title="Instagram"> 758 <i class="fab fa-instagram fa-lg"></i> 759 </a> 760 </div> 761 </div> 762 </div> 763 <div class="text-center tos pt-4"> 764 <a class="text-font-color" href="/Home/TermsOfUse" id="tosLink" target="_blank">Terms of Use |</a> 765 <a class="text-font-color" href="/Home/PrivacyPolicy" id="ppLink" target="_blank">Privacy Policy</a> 766 </div> 767 <div class="text-center" style="font-size: 0.75rem; color: #999; padding-top: 0.5rem;"> 768 © 2026 American Marketing & Publishing, L.L.C. All rights reserved. Names, logos, and other marks displayed are the property of their respective owners. 769 </div> 770 </div> 771</div> 772</footer> 773 774 <div class="accessibility-img py-2 px-2"> 775 <div class="d-flex flex-wrap justify-content-center align-items-center text-center"> 776 <a href="/Accessibility?domain=koenenswaterworksplumbing" target="_blank" class="dark"> 777 <img src="/Content/Templates/images/accessibility_icon.png" height="60" width="42" /> 778 </a> 779 </div> 780 </div> 781 782 783 784 785<div class="chatbot-toggle-container"> 786 <button id="chatbot-toggle"> 787 <img src="/Content/Templates/images/chat_icon.png" height="60" width="60" /> 788 </button> 789</div> 790 791<!-- Chat Window --> 792<div id="chat-window"> 793 <!-- Chat Header --> 794 <div class="chat-header"> 795 <div class="chat-header-content"> 796 <h3 class="chat-header-title">Koenen's Water Works Plumbing Co. LLC Assistant</h3> 797 </div>
798 <button id="close-chat" class="chat-close-btn" aria-label="Close chat"> 799 <i class="fas fa-times"></i> 800 </button> 801 </div> 802 803 <!-- Chat Messages --> 804 <div id="chat-messages"> 805 <div class="chat-message-container"> 806 <div class="chat-message"> 807 Hi there! How can we help you today? 808 </div> 809 </div> 810 </div> 811 812 <div id="disclaimer-info"> 813 <div class="disclaimer-content"> 814 <div class="disclaimer-text"> 815 AI Responses not guaranteed; verify before reliance 816 </div> 817 </div> 818 </div> 819 820 <!-- Cost Display --> 821 <div id="cost-info"> 822 <div class="cost-info-row"> 823 <div class="cost-info-left"> 824 <i class="fas fa-dollar-sign fa-xs cost-icon"></i> 825 <span id="cost-display">Cost: $0.00000</span> 826 </div> 827 <span id="percentage-display">0.0% of $0.02</span> 828 </div> 829 <div class="cost-progress-bar"> 830 <div id="cost-progress"></div> 831 </div> 832 </div> 833 834 <!-- Chat Input --> 835 <div class="chat-input-container"> 836 <form id="chat-form"> 837 <input type="text" id="chat-input" placeholder="Type your message..." /> 838 <button type="submit" id="send-message"> 839 <i class="fas fa-paper-plane"></i> 840 </button> 841 </form> 842 <div id="character-count">0/250</div> 843 <div id="character-limit-message" style="display: none; color: #dc2626; font-size: 12px; margin-top: 4px;"> 844 Your message is too long. Please limit your question to 250 characters or less. 845 </div> 846 </div> 847</div> 848 849<!-- Contact Form Window --> 850<div id="contact-form-window"> 851 <div class="contact-form-header"> 852 <h3 class="contact-form-title">Contact Form</h3> 853 <button id="close-contact-form" class="contact-form-close-btn" aria-label="Close contact form"> 854 <i class="fas fa-times"></i> 855 </button> 856 </div> 857 858 <div class="contact-form-content"> 859 <form id="chatbot-contact-form"> 860 <input type="hidden" id="chat_captcha_alt" name="chat_captcha_alt" value="0uq+DT7YhakT55z49KBSHTQk1QA1eLuwq37R9WIJm8Ln80xBYNHNUaNcNG1Jx3Sg" /> 861 <input type="hidden" id="chat_g-Recaptcha-Response-Contact" name="chat_g-Recaptcha-Response-Contact" value="" /> 862 <input type="hidden" name="chat_aid" value="2016192a-be3a-414c-a879-4c87f8553d03" /> 863 <input type="hidden" name="chat_contactSubject" value="FrontDesk™ Contact Form" /> 864 <input type="hidden" name="chat_contactAddress" value="" /> 865 <input type="hidden" name="chat_contactZip" value="" /> 866 <input type="hidden" name="chat_contactCity" value="" /> 867 <input type="hidden" name="chat_contactState" value="" /> 868 869 <div class="ai-liability mt-1 mb-1">(Messages sent through this site are subject to third party moderation and are not encrypted or secure. We always try to respond as soon as possible, but off-hours inquiries may take us a little longer to reply.)</div> 870 871 <div class="form-group"> 872 <label for="chat_contactName" class="form-label">Name *</label> 873 <input type="text" id="chat_contactName" name="chat_contactName" class="form-input" required /> 874 </div> 875 876 <div class="form-group"> 877 <label for="chat_contactEmail" class="form-label">Email *</label> 878 <input type="email" id="chat_contactEmail" name="chat_contactEmail" class="form-input" required /> 879 </div> 880 881 <div class="form-group"> 882 <label for="chat_contactPhone" class="form-label">Phone</label> 883 <input type="tel" id="chat_contactPhone" name="chat_contactPhone" class="form-input" /> 884 </div> 885 886 <div class="form-group"> 887 <label for="chat_contactMessage" class="form-label">Message *</label> 888 <textarea id="chat_contactMessage" name="chat_contactMessage" rows="4" class="form-textarea" required></textarea> 889 </div> 890 891 <div id="classicCaptcha" class="d-flex flex-column"> 892 <div class="g-recaptcha ml-auto mb-3 captcha-responsive" data-sitekey="6LeprWcUAAAAAF533Xd5p6kCrnRs0z4ceJieYgeO"></div> 893 </div> 894 895 <!-- Sticky footer section with reCAPTCHA disclaimer and submit button --> 896 <div class="form-sticky-footer"> 897 <div class="grecaptcha-info"> 898 This site is protected by reCAPTCHA and the Google 899 <a href="https://policies.google.com/privacy">Privacy Policy</a> and 900 <a href="https://policies.google.com/terms">Terms of Service</a> apply. 901 </div> 902 <button type="submit" id="contact-submit-btn" class="form-submit-btn">Submit</button> 903 </div> 904 </form> 905 </div> 906</div> 907
908<script> 909 // Wrap entire chatbot functionality in a namespace to prevent conflicts 910 window.ChatbotModule = (function() { 911 'use strict'; 912 913 // Private variables 914 let isOpen = false; 915 let contactFormOpen = false; 916 let messages = [ 917 { role: 'assistant', content: 'Hi there! How can we help you today?' } 918 ]; 919 let isLoading = false; 920 let showContactForm = false; 921 let limitReached = false; 922 let apiCost = 0; 923 const maxCost = 0.5; 924 const maxQuestionLength = 250; 925 926 // Private element references 927 let $chatbotToggle; 928 let $chatWindow; 929 let $contactFormWindow; 930 let $closeChat; 931 let $closeContactForm; 932 let $chatMessages; 933 let $chatForm; 934 let $chatInput; 935 let $sendMessage; 936 let $characterCount; 937 let $costDisplay; 938 let $percentageDisplay; 939 let $costProgress; 940 let $contactForm; 941 942 // Initialize element references 943 function initializeElements() { 944 $chatbotToggle = $('#chatbot-toggle'); 945 $chatWindow = $('#chat-window'); 946 $contactFormWindow = $('#contact-form-window'); 947 $closeChat = $('#close-chat'); 948 $closeContactForm = $('#close-contact-form'); 949 $chatMessages = $('#chat-messages'); 950 $chatForm = $('#chat-form'); 951 $chatInput = $('#chat-input'); 952 $sendMessage = $('#send-message'); 953 $characterCount = $('#character-count'); 954 $costDisplay = $('#cost-display'); 955 $percentageDisplay = $('#percentage-display'); 956 $costProgress = $('#cost-progress'); 957 $contactForm = $('#chatbot-contact-form'); 958 } 959 960 // Initialize 961 function init() { 962 // Initialize element references 963 initializeElements(); 964 965 // Load cost from localStorage 966 const savedCost = localStorage.getItem('api_cost'); 967 if (savedCost) { 968 apiCost = parseFloat(savedCost); 969 970 // Check if cost limit is reached 971 if (apiCost >= maxCost) { 972 limitReached = true; 973 updateChatInputState(); 974 } 975 } 976 977 // Initialize character count display 978 updateCharacterCount(); 979 980 document.documentElement.style.setProperty('--adaptive-text-color', '#374151'); 981 document.documentElement.style.setProperty('--image-invert', 'none'); 982 983 setTimeout(updateTextColors, 100); 984 985 // Ensure chatbot stays on top even when modals are opened 986 $(document).on('shown.bs.modal', function (e) { 987 // Temporarily boost chatbot z-index when modals are shown 988 $('.chatbot-toggle-container').css('z-index', '2147483647'); 989 $('#chat-window').css('z-index', '2147483646'); 990 $('#contact-form-window').css('z-index', '2147483645'); 991 }); 992 993 // Set up event listeners 994 setupEventListeners(); 995 } 996 997 // Event Listeners with namespacing 998 function setupEventListeners() { 999 // Remove any existing chatbot event listeners to prevent duplicates 1000 $chatbotToggle.off('.chatbot'); 1001 $closeChat.off('.chatbot'); 1002 $closeContactForm.off('.chatbot'); 1003 $chatForm.off('.chatbot'); 1004 $chatInput.off('.chatbot'); 1005 $contactForm.off('.chatbot'); 1006 1007 // Toggle chat window 1008 $chatbotToggle.on('click.chatbot', function(e) { 1009 e.preventDefault(); 1010 e.stopPropagation(); 1011 toggleChat(); 1012 }); 1013 1014 $closeChat.on('click.chatbot', function(e) { 1015 e.preventDefault(); 1016 e.stopPropagation(); 1017 closeChat(); 1018 }); 1019 1020 $closeContactForm.on('click.chatbot', function(e) { 1021 e.preventDefault(); 1022 e.stopPropagation(); 1023 hideContactForm(); 1024 }); 1025 1026 // Send message 1027 $chatForm.on('submit.chatbot', function (e) { 1028 e.preventDefault(); 1029 e.stopPropagation(); 1030 1031 // Check if submit button is disabled 1032 if ($sendMessage.prop('disabled') || $sendMessage.hasClass('disabled')) { 1033 return false; 1034 } 1035 1036 sendMessage(); 1037 }); 1038 1039 // Character count - update on every keystroke 1040 $chatInput.on('input.chatbot', function(e) { 1041 // Only handle if this is specifically the chatbot input 1042 if ($(this).attr('id') === 'chat-input') { 1043 updateCharacterCount(); 1044 } 1045 }); 1046 1047 // Also check on keyup to catch paste events 1048 $chatInput.on('keyup.chatbot paste.chatbot', function(e) { 1049 // Only handle if this is specifically the chatbot input 1050 if ($(this).attr('id') === 'chat-input') { 1051 setTimeout(updateCharacterCount, 10); 1052 } 1053 }); 1054 1055 // Handle "Enter" key for sending messages 1056 $chatInput.on('keydown.chatbot', function (e) { 1057 // Only handle if this is specifically the chatbot input 1058 if ($(this).attr('id') !== 'chat-input') { 1059 return; 1060 } 1061 1062 if (e.key === 'Enter' && !e.shiftKey && !limitReached) { 1063 e.preventDefault(); 1064 e.stopImmediatePropagation(); 1065 1066 // Check if submit button is disabled 1067 if ($sendMessage.prop('disabled') || $sendMessage.hasClass('disabled')) { 1068 return false; 1069 } 1070 1071 sendMessage(); 1072 return; 1073 } 1074 }); 1075 1076 // Contact form submission 1077 $contactForm.on('submit.chatbot', function (e) { 1078 e.preventDefault(); 1079 e.stopPropagation(); 1080 submitContactForm(); 1081 }); 1082 } 1083 1084 // Toggle chat window 1085 function toggleChat() { 1086 if (!isOpen) { 1087 // Opening the chat 1088 isOpen = true; 1089 1090 // Hide toggle button on both mobile and desktop 1091 $('.chatbot-toggle-container').addClass('hide-toggle'); 1092 1093 // First show the window (still off-screen) 1094 $chatWindow.show(); 1095 1096 // Force a reflow to ensure the transition will work 1097 $chatWindow[0].offsetHeight; 1098 1099 // Then add the class that triggers the slide-in animation 1100 setTimeout(function () { 1101 $chatWindow.addClass('show'); 1102 scrollToBottom(); 1103 }, 10); 1104 } else { 1105 // Closing the chat 1106 isOpen = false; 1107 1108 // Show toggle button again 1109 $('.chatbot-toggle-container').removeClass('hide-toggle'); 1110 1111 // Remove the show class to trigger slide-out animation 1112 $chatWindow.removeClass('show'); 1113 1114 // Hide the window after the animation completes 1115 setTimeout(function () { 1116 $chatWindow.hide(); 1117 }, 300); // Match the CSS transition duration 1118 1119 // Also hide contact form if open 1120 if (contactFormOpen) { 1121 hideContactForm(); 1122 } 1123 } 1124 } 1125 1126 // Close chat window 1127 function closeChat() { 1128 if (isOpen) { 1129 isOpen = false; 1130 1131 // Show toggle button again 1132 $('.chatbot-toggle-container').removeClass('hide-toggle'); 1133 1134 // Trigger slide-out animation 1135 $chatWindow.removeClass('show'); 1136 1137 // Hide after animation 1138 setTimeout(function () { 1139 $chatWindow.hide(); 1140 }, 300); 1141 1142 if (contactFormOpen) { 1143 hideContactForm(); 1144 } 1145 } 1146 } 1147 1148 // Update character count and submit button state 1149 function updateCharacterCount() { 1150 const count = $chatInput.val().length; 1151 const remaining = maxQuestionLength - count; 1152 const $limitMessage = $('#character-limit-message'); 1153 1154 if (count > maxQuestionLength) { 1155 // Over limit - disable submit button and show message 1156 $characterCount.text(`${count}/${maxQuestionLength} (${Math.abs(remaining)} over limit)`).css('color', '#dc2626'); 1157 $limitMessage.text(`Your message is too long. Please limit your question to ${maxQuestionLength} characters or less. Your message is currently ${count} characters.`).show(); 1158 $chatInput.addClass('over-limit'); 1159 1160 // Disable submit button with proper styling 1161 $sendMessage.prop('disabled', true).addClass('disabled'); 1162 $sendMessage.css({ 1163 'background-color': '#9ca3af', 1164 'color': '#6b7280', 1165 'cursor': 'not-allowed', 1166 'opacity': '0.5', 1167 'pointer-events': 'none' 1168 }); 1169 1170 } else if (remaining <= 20) { 1171 // Close to limit - show warning but allow submit 1172 $characterCount.text(`${count}/${maxQuestionLength}`).css('color', '#f59e0b'); 1173 $limitMessage.hide(); 1174 $chatInput.removeClass('over-limit'); 1175 1176 // Enable submit button and reset styling 1177 $sendMessage.prop('disabled', false).removeClass('disabled'); 1178 $sendMessage.css({ 1179 'background-color': '', 1180 'color': '', 1181 'cursor': '', 1182 'opacity': '', 1183 'pointer-events': '' 1184 }); 1185 1186 } else {
1187 // Within limit - normal state 1188 $characterCount.text(`${count}/${maxQuestionLength}`).css('color', '#6b7280'); 1189 $limitMessage.hide(); 1190 $chatInput.removeClass('over-limit'); 1191 1192 // Enable submit button and reset styling 1193 $sendMessage.prop('disabled', false).removeClass('disabled'); 1194 $sendMessage.css({ 1195 'background-color': '', 1196 'color': '', 1197 'cursor': '', 1198 'opacity': '', 1199 'pointer-events': '' 1200 }); 1201 } 1202 } 1203 1204 // Send message 1205 function sendMessage() { 1206 const message = $chatInput.val().trim(); 1207 if (!message || isLoading || limitReached) return; 1208 1209 // Double check character limit including whitespace 1210 if (message.length > maxQuestionLength) { 1211 appendMessage('assistant', `Your message is too long. Please limit your question to ${maxQuestionLength} characters or less. Your message is currently ${message.length} characters.`); 1212 return; 1213 } 1214 1215 // Add user message to chat 1216 messages.push({ role: 'user', content: message }); 1217 appendMessage('user', message); 1218 1219 // Clear input 1220 $chatInput.val(''); 1221 updateCharacterCount(); 1222 1223 // Send to API 1224 fetchChatResponse(messages); 1225 } 1226 1227 // Fetch chat response from API 1228 function fetchChatResponse(messages) { 1229 isLoading = true; 1230 showLoadingIndicator(); 1231 1232 $.ajax({
1233 url: '/Home/Chat', 1234 type: 'POST', 1235 contentType: 'application/json', 1236 data: JSON.stringify({ 1237 Messages: messages, 1238 ProfileId: '37496' 1239 }), 1240 headers: { 1241 'RequestVerificationToken': $('input[name="__RequestVerificationToken"]').val() 1242 }, 1243 success: function (response) { 1244 hideLoadingIndicator(); 1245 1246 if (response.error) { 1247 appendMessage('assistant', `Error: ${response.error}`); 1248 console.error('API Error:', response.error); 1249 isLoading = false; 1250 return; 1251 } 1252 1253 // Update cost 1254 apiCost = response.Cost; 1255 localStorage.setItem('api_cost', apiCost.toString()); 1256 1257 // Check if limit reached 1258 if (response.LimitReached) { 1259 limitReached = true; 1260 showContactFormWindow(); 1261 appendMessage('assistant', 'Our AI chat has reached its capacity. Please use the contact form to get in touch directly with us.'); 1262 } else { 1263 // Check if response contains contact form trigger 1264 if (response.Message.includes('<start_contact_form>')) { 1265 const cleanResponse = response.Message.replace('<start_contact_form>', ''); 1266 appendMessage('assistant', cleanResponse); 1267 showContactFormWindow(); 1268 } else { 1269 appendMessage('assistant', response.Message); 1270 } 1271 1272 // Add response to messages array 1273 messages.push({ role: 'assistant', content: response.Message }); 1274 } 1275 1276 isLoading = false; 1277 updateChatInputState(); 1278 }, 1279 error: function (xhr, status, error) { 1280 hideLoadingIndicator(); 1281 appendMessage('assistant', 'Sorry, I encountered an error. Please try again later.'); 1282 console.error('AJAX Error:', error); 1283 isLoading = false; 1284 } 1285 }); 1286 } 1287 1288 // Append message to chat 1289 function appendMessage(role, content) { 1290 content = convertMarkdownLinksToHTML(content); 1291 const rootStyles = getComputedStyle(document.documentElement); 1292 const customerColor = rootStyles.getPropertyValue('--customer_color').trim(); 1293 const adaptivefontColor = rootStyles.getPropertyValue('--adaptive-text-color').trim(); 1294 1295 const messageClass = role === 'user' ? 'flex-end' : 'flex-start'; 1296 const bgColor = role === 'user' ? customerColor : 'white'; 1297 const textColor = role === 'user' ? adaptivefontColor : '#374151'; 1298 const borderRadius = role === 'user' ? 'border-bottom-right-radius: 0;' : 'border-bottom-left-radius: 0;'; 1299 const border = role === 'user' ? '' : 'border: 1px solid #e5e7eb;'; 1300 1301 const messageHtml = ` 1302 <div style="display: flex; justify-content: ${messageClass}; margin-bottom: 16px;"> 1303 <div style="max-width: 75%; padding: 12px; border-radius: 8px; background-color: ${bgColor}; ${border} ${borderRadius} color: ${textColor}; word-wrap: break-word; overflow-wrap: break-word;"> 1304 ${content} 1305 </div> 1306 </div> 1307 `; 1308 1309 $chatMessages.append(messageHtml); 1310 scrollToBottom(); 1311 } 1312 1313 // Show loading indicator 1314 function showLoadingIndicator() { 1315 const loadingHtml = ` 1316 <div id="loading-indicator" style="display: flex; justify-content: flex-start; margin-bottom: 16px;"> 1317 <div style="max-width: 75%; padding: 12px; border-radius: 8px; background-color: white; border: 1px solid #e5e7eb; color: #374151; display: flex; gap: 4px;"> 1318 <div class="loading-dot" style="width: 8px; height: 8px; background-color: #9ca3af; border-radius: 50%;"></div> 1319 <div class="loading-dot" style="width: 8px; height: 8px; background-color: #9ca3af; border-radius: 50%;"></div> 1320 <div class="loading-dot" style="width: 8px; height: 8px; background-color: #9ca3af; border-radius: 50%;"></div> 1321 </div> 1322 </div> 1323 `; 1324 1325 $chatMessages.append(loadingHtml); 1326 animateLoadingDots(); 1327 scrollToBottom(); 1328 1329 // Disable input while loading 1330 $chatInput.prop('disabled', true); 1331 $sendMessage.prop('disabled', true); 1332 } 1333 1334 // Animate loading dots 1335 function animateLoadingDots() { 1336 if (!$("#loading-indicator").length) return; 1337 1338 $(".loading-dot").each(function (index) { 1339 var $dot = $(this); 1340 setTimeout(function () { 1341 $dot.animate({ opacity: 0.3 }, 300) 1342 .animate({ opacity: 1 }, 300); 1343 }, index * 200); 1344 }); 1345 1346 setTimeout(function () { 1347 animateLoadingDots(); 1348 }, 900); 1349 } 1350 1351 // Hide loading indicator 1352 function hideLoadingIndicator() { 1353 $('#loading-indicator').remove(); 1354 1355 // Enable input after loading (unless limit reached) 1356 if (!limitReached) { 1357 $chatInput.prop('disabled', false); 1358 updateCharacterCount(); // This will set the correct submit button state 1359 } 1360 } 1361 1362 // Scroll to bottom of chat 1363 function scrollToBottom() { 1364 $chatMessages.scrollTop($chatMessages[0].scrollHeight); 1365 } 1366 1367 // Update cost display 1368 function updateCostDisplay() { 1369 $("#cost-info").show(); 1370 $costDisplay.text(`Cost: $${apiCost.toFixed(5)}`); 1371 1372 const percentage = (apiCost / maxCost) * 100; 1373 $percentageDisplay.text(`${percentage.toFixed(1)}% of $${maxCost.toFixed(2)}`); 1374 1375 $costProgress.css('width', `${percentage}%`); 1376
1377 // Change progress bar color if near limit 1378 if (percentage > 80) { 1379 $costProgress.css("background-color", "#dc2626"); 1380 } else { 1381 $costProgress.css("background-color", "#4f46e5"); 1382 } 1383 1384 // Update chat input state 1385 updateChatInputState(); 1386 } 1387 1388 // Update chat input state based on limit 1389 function updateChatInputState() { 1390 if (limitReached) { 1391 $chatInput.prop('disabled', true); 1392 $sendMessage.prop('disabled', true); 1393 $chatInput.attr('placeholder', 'Chat Unavailable.'); 1394 } else { 1395 $chatInput.prop('disabled', false); 1396 updateCharacterCount(); // This will set the correct submit button state 1397 $chatInput.attr('placeholder', 'Type your message...'); 1398 } 1399 } 1400 1401 // Show contact form 1402 function showContactFormWindow() { 1403 if (!contactFormOpen) { 1404 contactFormOpen = true; 1405 1406 // Hide toggle button when contact form opens 1407 $('.chatbot-toggle-container').addClass('hide-toggle'); 1408 1409 if (isMobile()) { 1410 // On mobile, slide out chat and slide in contact form 1411 $chatWindow.removeClass('show'); 1412 setTimeout(function () { 1413 $chatWindow.hide(); 1414 $contactFormWindow.show(); 1415 // Force reflow 1416 $contactFormWindow[0].offsetHeight; 1417 // Add show class for slide animation 1418 setTimeout(function () { 1419 $contactFormWindow.addClass('show'); 1420 $('.contact-form-content').scrollTop(0); 1421 }, 10); 1422 }, 300); 1423 } else { 1424 // Desktop - slide chat to left and slide in contact form 1425 $chatWindow.animate({ right: '390px' }, 300); 1426 $contactFormWindow.show(); 1427 setTimeout(function () { 1428 $contactFormWindow.animate({ right: '20px' }, 300); 1429 }, 50); 1430 } 1431 } 1432 } 1433 1434 // Hide contact form - slides out and chat returns to original position 1435 function hideContactForm() { 1436 if (contactFormOpen) { 1437 contactFormOpen = false; 1438 1439 if (isMobile()) { 1440 // Slide out contact form 1441 $contactFormWindow.removeClass('show'); 1442 1443 setTimeout(function () { 1444 $contactFormWindow.hide(); 1445 // Show chat window again if it was open 1446 if (isOpen) { 1447 $chatWindow.show(); 1448 // Force reflow 1449 $chatWindow[0].offsetHeight; 1450 setTimeout(function () { 1451 $chatWindow.addClass('show'); 1452 }, 10); 1453 } else { 1454 // If chat is not open, show toggle button 1455 $('.chatbot-toggle-container').removeClass('hide-toggle'); 1456 } 1457 }, 300); 1458 } else { 1459 // Desktop - animate back 1460 $contactFormWindow.animate({ right: '-370px' }, 300, function () { 1461 $contactFormWindow.hide(); 1462 }); 1463 $chatWindow.animate({ right: '20px' }, 300); 1464 1465 // Only show toggle if both windows are closed 1466 if (!isOpen) { 1467 $('.chatbot-toggle-container').removeClass('hide-toggle'); 1468 } 1469 } 1470 } 1471 } 1472
1473 // Submit contact form 1474 function submitContactForm() { 1475 const name = $('#chat_contactName').val(); 1476 const email = $('#chat_contactEmail').val(); 1477 const phone = $('#chat_contactPhone').val(); 1478 const message = $('#chat_contactMessage').val(); 1479 1480 // Basic validation 1481 if (!name || !email || !message) { 1482 alert('Please fill out all required fields.'); 1483 return; 1484 } 1485 1486 // Email validation 1487 const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; 1488 if (!emailRegex.test(email)) { 1489 alert('Please enter a valid email address.'); 1490 return; 1491 } 1492 1493 // Message length validation 1494 if (message.length < 10) { 1495 alert('Your message must be at least 10 characters long.'); 1496 return; 1497 } 1498 1499 // Disable form during submission 1500 $('#contact-submit-btn').prop('disabled', true).text('Sending...'); 1501 1502 var form = $("#chatbot-contact-form"); 1503 1504 // Execute reCAPTCHA before submitting 1505 grecaptcha.ready(function() { 1506 grecaptcha.execute('6LcokacUAAAAAH_snk3O5bpdYwjpC5XAuXNLrJLH', {action: 'contact_us'}).then(function(token) { 1507 // Set the reCAPTCHA token 1508 $("#chat_g-Recaptcha-Response-Contact").val(token); 1509 1510 // Submit the form with reCAPTCHA token 1511 $.ajax({
1512 url: "/Home/ChatContactPost", 1513 type: 'POST', 1514 data: form.serialize(), 1515 success: function (response) { 1516 if (typeof response === 'string' && response.indexOf('{"message":') != -1) { 1517 var jsonData = JSON.parse(response); 1518 if (jsonData.success) { 1519 appendMessage('assistant', 'Thanks for providing your information! We will get back to you soon.'); 1520 hideContactForm(); 1521 1522 // Reset the form 1523 $('#chat_contactName').val(''); 1524 $('#chat_contactEmail').val(''); 1525 $('#chat_contactPhone').val(''); 1526 $('#chat_contactMessage').val(''); 1527 } else { 1528 alert(jsonData.message || 'There was an error processing your request.'); 1529 } 1530 } else if (response.success) { 1531 appendMessage('assistant', 'Thanks for providing your information! We will get back to you soon.'); 1532 hideContactForm(); 1533 1534 // Reset the form 1535 $('#chat_contactName').val(''); 1536 $('#chat_contactEmail').val(''); 1537 $('#chat_contactPhone').val(''); 1538 $('#chat_contactMessage').val(''); 1539 1540 } else { 1541 alert(response.message || 'There was an error processing your request.'); 1542 } 1543 1544 $('#contact-submit-btn').prop('disabled', false).text('Submit'); 1545 }, 1546 error: function (xhr, status, error) { 1547 alert('Failed to submit your information. Please try again.'); 1548 console.error('AJAX Error:', error); 1549 $('#contact-submit-btn').prop('disabled', false).text('Submit'); 1550 } 1551 }); 1552 }); 1553 }); 1554 } 1555 1556 function convertMarkdownLinksToHTML(text) { 1557 return text.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (match, linkText, url) => { 1558 // Add target="_blank" for http/https links 1559 if (url.startsWith('http://') || url.startsWith('https://')) { 1560 return `<a href="${url}" target="_blank" rel="noopener noreferrer">${linkText}</a>`; 1561 } 1562 // Keep tel: and mailto: links as-is 1563 return `<a href="${url}">${linkText}</a>`; 1564 }); 1565 } 1566 1567 function getLuminance(hex) { 1568 // Remove # if present 1569 hex = hex.replace('#', ''); 1570 1571 // Convert hex to RGB 1572 const r = parseInt(hex.substr(0, 2), 16) / 255; 1573 const g = parseInt(hex.substr(2, 2), 16) / 255; 1574 const b = parseInt(hex.substr(4, 2), 16) / 255; 1575 1576 // Calculate relative luminance 1577 const rLum = r <= 0.03928 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4); 1578 const gLum = g <= 0.03928 ? g / 12.92 : Math.pow((g + 0.055) / 1.055, 2.4); 1579 const bLum = b <= 0.03928 ? b / 12.92 : Math.pow((b + 0.055) / 1.055, 2.4); 1580 1581 return 0.2126 * rLum + 0.7152 * gLum + 0.0722 * bLum; 1582 } 1583 1584 function isLightColor(hex) { 1585 const luminance = getLuminance(hex); 1586 return luminance > 0.5; // Threshold for light vs dark 1587 } 1588 1589 function updateTextColors() { 1590 const rootStyles = getComputedStyle(document.documentElement); 1591 let customerColor = rootStyles.getPropertyValue('--customer_color').trim(); 1592 1593 // Check if customer color is not set or is empty 1594 if (!customerColor || customerColor === '') { 1595 const defaultColor = '#f3f3f3'; 1596 1597 // Set the default customer color 1598 document.documentElement.style.setProperty('--customer_color', defaultColor); 1599 customerColor = defaultColor; 1600 } 1601 1602 const isLight = isLightColor(customerColor); 1603 const textColor = isLight ? '#000000b3' : '#ffffff'; 1604 1605 const $chatbotToggle = $('#chatbot-toggle'); 1606 if (isLight) { 1607 $chatbotToggle.removeClass('dark-background').addClass('light-background'); 1608 } else { 1609 $chatbotToggle.removeClass('light-background').addClass('dark-background'); 1610 } 1611 1612 // Update the CSS custom property 1613 document.documentElement.style.setProperty('--adaptive-text-color', textColor); 1614 } 1615 1616 function isMobile() { 1617 return window.innerWidth <= 768; 1618 } 1619 1620 // Public interface 1621 return { 1622 init: init 1623 }; 1624 })(); 1625 1626 // Initialize the chatbot module when document is ready 1627 $(document).ready(function () { 1628 if (window.ChatbotModule) {
1629 window.ChatbotModule.init(); 1630 } 1631 }); 1632</script>
1632 1633<!-- Modal --> 1634<div class="modal" id="carouselImageryPhotoModal"> 1635 <div class="modal-dialog modal-dialog-centered modal-lg"> 1636 <div class="modal-content"> 1637 <div class="modal-header"><button type="button" class="close" data-dismiss="modal">×</button></div> 1638 <div class="modal-body"> 1639 <div class="w-100 w-lg-75 mx-auto mt-4 mb-4"> 1640 <div class="slider slider-imagery w-100"> 1641 <div class="image-slider m-2"> 1642 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/9822d27a-a440-4082-bcd3-d75dd86ffc18.jpg" class="img-fluid text-center mx-auto" /> 1643 </div> 1644 <div class="image-slider m-2"> 1645 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/7b59338d-e022-4c31-ad97-6b1d9d8ee119.jpg" class="img-fluid text-center mx-auto" /> 1646 </div> 1647 <div class="image-slider m-2"> 1648 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/fc866e35-d2f8-4200-809d-eda7b64a7432.jpg" class="img-fluid text-center mx-auto" /> 1649 </div> 1650 <div class="image-slider m-2"> 1651 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/8c609b90-a03f-492c-bb86-958eec245e10.jpg" class="img-fluid text-center mx-auto" /> 1652 </div> 1653 <div class="image-slider m-2"> 1654 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/33871ee3-b0ac-4d37-ae00-b0e0e3590451.jpg" class="img-fluid text-center mx-auto" /> 1655 </div> 1656 <div class="image-slider m-2"> 1657 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/f54608e7-9e0c-4ce4-9021-80cc3b038433.jpg" class="img-fluid text-center mx-auto" /> 1658 </div> 1659 <div class="image-slider m-2"> 1660 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/dcdcf430-6cc5-497d-b3dd-90f1031cc18d.jpg" class="img-fluid text-center mx-auto" /> 1661 </div> 1662 <div class="image-slider m-2"> 1663 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/d30303df-a085-4560-994f-fd8574e85c54.jpg" class="img-fluid text-center mx-auto" /> 1664 </div> 1665 <div class="image-slider m-2"> 1666 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/1f200740-571d-4846-bb2d-90e1e8d8de35.jpg" class="img-fluid text-center mx-auto" /> 1667 </div> 1668 <div class="image-slider m-2"> 1669 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/406f4b59-1853-4702-9b5f-6da17e60b3e7.jpg" class="img-fluid text-center mx-auto" /> 1670 </div> 1671 <div class="image-slider m-2"> 1672 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/9bbcdf42-cf59-438b-82bd-e0ce1ff14cfa.jpg" class="img-fluid text-center mx-auto" /> 1673 </div> 1674 <div class="image-slider m-2"> 1675 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/362f2daf-dfeb-4236-9c80-9df5edda4f02.jpg" class="img-fluid text-center mx-auto" /> 1676 </div> 1677 <div class="image-slider m-2"> 1678 <img alt="Image" src="https://du9m0k402rjmo.
1678cloudfront.net/images/P_37496/1d44e50f-d2bc-415f-9a0b-95b3dc719ee7.jpg" class="img-fluid text-center mx-auto" /> 1679 </div> 1680 <div class="image-slider m-2"> 1681 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/4d220349-9ea8-4f89-a169-4998b2fd38da.jpg" class="img-fluid text-center mx-auto" /> 1682 </div> 1683 <div class="image-slider m-2"> 1684 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/b868af7f-ad95-49b9-99b7-cfa93fa66fe1.jpg" class="img-fluid text-center mx-auto" /> 1685 </div> 1686 <div class="image-slider m-2"> 1687 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/70af784f-d05d-46dc-999a-23852b90c69b.jpg" class="img-fluid text-center mx-auto" /> 1688 </div> 1689 <div class="image-slider m-2"> 1690 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/a86ae628-5fa4-49f3-b97d-941128f3bde2.jpg" class="img-fluid text-center mx-auto" /> 1691 </div> 1692 <div class="image-slider m-2"> 1693 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/0ae8daef-8717-492b-a749-16f1779846e7.png" class="img-fluid text-center mx-auto" /> 1694 </div> 1695 <div class="image-slider m-2"> 1696 <img alt="Image" src="https://du9m0k402rjmo.cloudfront.net/images/P_37496/d61e30e7-fe2c-4a05-b4cd-f2b08e1703ee.png" class="img-fluid text-center mx-auto" /> 1697 </div> 1698 </div> 1699 </div> 1700 </div> 1701 </div> 1702 </div> 1703</div> 1704 1705<!-- Modal --> 1706<div class="modal" id="carouselImageryVideoModal"> 1707 <div class="modal-dialog modal-dialog-centered modal-xl"> 1708 <div class="modal-content"> 1709 <div class="modal-header"><button type="button" class="close" data-dismiss="modal">×</button></div> 1710 <div class="modal-body"> 1711 </div> 1712 </div> 1713 </div> 1714</div> 1715 1716<div id="loadingImg" class="loader" style="display:none !important"> 1717 <i class="fas fa-circle"></i> 1718 <i class="fas fa-circle"></i> 1719 <i class="fas fa-circle"></i> 1720</div> 1721
1722<script type="text/javascript"> 1723 var isMobile = false; 1724 var isTablet = false; 1725 var pageSize = 5; 1726 var pageIndex = 0; 1727 var notReputation = false; 1728 var hasbanner = true; 1729 var keepPostUp = false; 1730 var listOfSites = ""; 1731 var numOfReviews = 131; 1732 var numOfFilteredReviews = 131; 1733 var testimonialPageBackgroundColor = '#031733'; 1734 var numOfPosts = 20; 1735 var postsPageIndex = 0; 1736 var geocode = null; 1737 var isSubmittingReview = false; //global flag to track submission 1738 1739 $(document).ready(function () { 1740 1741 if ($(window).width() < 576) { 1742 $("#gallerysection").addClass("pr-3"); 1743 $("#gallerysection").addClass("pl-3"); 1744 } 1745 else { 1746 $("#gallerysection").removeClass("pr-3"); 1747 $("#gallerysection").removeClass("pl-3"); 1748 } 1749 1750 if($("#contact_us_phone").length > 0){ 1751 var cleave = new Cleave('#contact_us_phone', { 1752 phone: true, 1753 phoneRegionCode: 'US' 1754 }); 1755 } 1756 1757 // Load the review modal async on page load 1758 $.get('/Home/GetReviewModalContent', { id: 37496, template: "Template_6"}, function (data) { 1759 if (data != "") { 1760 $("#reviewFormParentContainer").append(data); 1761 $('#starRating').barrating({ 1762 theme: 'bootstrap-stars', 1763 deselectable: true, 1764 onSelect: function (value, text, event) { 1765 $('.br-widget').removeClass('error'); 1766 $('.alert').alert('close'); 1767 } 1768 }); 1769 1770 } 1771 }); 1772 1773 checkMobile(); 1774 checkTablet(); 1775 bgSlider(); 1776 initializeCarousel(); 1777 checkHashRoute(); 1778 1779 PauseVideoPlayer(); 1780 1781 if(hasbanner){ 1782 GetPostsBanner(); 1783 } 1784 1785 $(window).on('hashchange', function(){ 1786 checkHashRoute(); 1787 }); 1788 1789 document.addEventListener("visibilitychange", function () { 1790 if (document["hidden"]) { 1791 PauseVideoPlayer(); 1792 } 1793 }); 1794 1795 var navMain = $("#navbarToggler"); 1796 navMain.on("click", "a", null, function () { 1797 navMain.collapse('hide'); 1798 }); 1799 1800 $(window).scroll(function () { 1801 var scroll = $(window).scrollTop(); 1802 if (('True' == 'False') || ('True' == 'True' && window.outerWidth > 767.98)) { /*false=center/true=left*/ 1803 if (scroll > 150){ 1804 $(".content").addClass("page-section-adjust"); 1805 $(".nav-logo").addClass("nav-logo-adjust"); 1806 $(".nav-location").addClass("nav-item-adjust"); 1807 } 1808 else if(scroll <= 150){ 1809 $(".content").removeClass("page-section-adjust"); 1810 $(".nav-logo").removeClass("nav-logo-adjust"); 1811 $(".nav-location").removeClass("nav-item-adjust"); 1812 } 1813 } 1814 }); 1815 1816 $("#carouselImageryVideoModal").on('shown.bs.modal', function (e) { 1817 $("video").each(function () { this.pause() }); //stop html5 video from playing 1818 }); 1819 1820 $("#carouselImageryVideoModal").on('hidden.bs.modal', function (e) { 1821 $("video").each(function () { this.pause() }); //stop html5 video from playing 1822 $('.slider-video').slick('unslick'); //destroy slider to prevent video from playing after closing 1823 }); 1824 1825 $(document).on("click", "#btnContactPost", function (e) { 1826 $("#btnContactPost").prop('disabled', true); 1827 $("#btnContactPost").css('font-weight', 'normal'); 1828 contactUsPost(e); 1829 }); 1830 1831 1832 var analyticsCategory = "Desktop"; 1833 if (isMobile == true) { 1834 analyticsCategory = "Mobile"; 1835 } 1836 1837 if (testimonialPageBackgroundColor != null && testimonialPageBackgroundColor != '' && testimonialPageBackgroundColor != "#F5F5F5") { 1838 //set footer background color 1839 $('.custom-background-color').css('background-color', testimonialPageBackgroun
1839dColor); 1840 //set footer text color appropriately 1841 setFooterColor(testimonialPageBackgroundColor); 1842 } 1843 else { 1844 //set footer background color to white 1845 var white = "#FFFFFF"; 1846 $('.custom-background-color').css('background-color', white); 1847 //set footer text color appropriately 1848 setFooterColor(white); 1849 } 1850 1851 $("#HomePageNavigationLink").click(function(e){ 1852 $('html, body').animate({ scrollTop: 0 }, 'fast'); 1853 }); 1854 1855 $(".business-name").click(function(e){ 1856 $('html, body').animate({ scrollTop: 0 }, 'fast'); 1857 }); 1858 1859 $(".testimonialsBlurbMore").click(function(e){ 1860 $('html, body').animate({ scrollTop: 0 }, 'fast'); 1861 }); 1862 1863 $('#starRating').barrating({ 1864 theme: 'bootstrap-stars', 1865 deselectable: true, 1866 onSelect: function (value, text, event) { 1867 $('.br-widget').removeClass('error'); 1868 $('.alert').alert('close'); 1869 } 1870 }); 1871 1872 if(numOfPosts > 0){ 1873 GetPostsData(0); 1874 } 1875 1876 $(document).on('click', "#nextPosts", function (e) { 1877 ScrollForPosts(e); 1878 GetPostsData(1); 1879 }); 1880 1881 $(document).on('click', "#prevPosts", function (e) { 1882 ScrollForPosts(e); 1883 GetPostsData(-1); 1884 }); 1885 1886 $(document).on('click', "#postReview", function (e) { 1887 e.preventDefault(); 1888 e.stopPropagation(); 1889 1890 if (isSubmittingReview) { 1891 console.log('Review submission already in progress - blocking duplicate submission'); 1892 return false; 1893 } 1894 1895 var $button = $(this); 1896 var $form = $("#postReviewForm"); 1897 var $modal = $("#reviewFormSection"); 1898 1899 isSubmittingReview = true; 1900 console.log('Starting review submission'); 1901 1902 setProcessingState($button, $form, true); 1903 1904 var alertType = "success"; 1905 1906 if(validateReview("#postReview")) { 1907 console.log('Review validation passed'); 1908 ShowLoading(); 1909 1910 grecaptcha.ready(function() { 1911 grecaptcha.execute('6LcokacUAAAAAH_snk3O5bpdYwjpC5XAuXNLrJLH', {action: 'testimonial_review'}).then(function(token) { 1912 $("#g-Recaptcha-Response-Review").attr("value", token); 1913 1914 var rating = null; 1915 var selectElement = document.getElementById('starRating'); 1916 var selectRating = selectElement ? selectElement.value : null; 1917 var selectedOption = $('#starRating option:selected').val(); 1918 var barRating = null; 1919 var reviewerAlias = $('#review_alias').val() || ''; 1920 var reviewHeading = $('#review_heading').val() || ''; 1921 var antiForgeryToken = $('input[name="__RequestVerificationToken"]').val(); 1922 var recaptchaToken = $('#g-Recaptcha-Response-Review').val(); 1923 var timeToPost = $('#phoneNumber_alternative').val(); 1924 1925 var reviewText = $('#review').val() || ''; 1926 var profileId = 37496; 1927 1928 console.log('Trying to get rating value...'); 1929 1930 var selectRating = $('#starRating')[0] ? $('#starRating')[0].value : null; 1931 console.log('Select element direct value:', selectRating); 1932 1933 var jqueryRating = $('#starRating').val(); 1934 console.log('jQuery val() result:', jqueryRating, typeof jqueryRating); 1935 1936 if (typeof $('#starRating').barrating === 'function') { 1937 try { 1938 var barResult = $('#starRating').barrating('show'); 1939 1940 if (barResult && typeof barResult === 'string') { 1941 barRating = barResult; 1942 } else if (barResult && typeof barResult === 'number') { 1943 barRating = barResult.toString(); 1944 } 1945 } catch (e) { 1946 console.log('Error getting barrating value:', e); 1947 } 1948 } 1949 1950 var selectedOption = $('#starRating option:selected').val(); 1951 console.log('Selected option value:', selectedOption); 1952 1953 var jqueryResult = $('#starRating').val(); 1954 var jqueryRating = null; 1955 1956 if (jqueryResult && typeof jqueryResult === 'string') { 1957 jqueryRating = jqueryResult; 1958 } else if (jqueryResult && typeof jqueryResult === 'number') { 1959 jqueryRating = jqueryResult.toString(); 1960 } 1961 1962 if (barRating && barRating !== "" && barRating !== "0") { 1963 rating = barRating; 1964 } else if (selectRating && selectRating !== "" && selectRating !== "0") { 1965 rating = selectRating; 1966 } else if (selectedOption && selectedOption !== "" && selectedOption !== "0") { 1967 rating = selectedOption; 1968 } else if (jqueryRating && jqueryRating !== "" && jqueryRating !== "0") { 1969 rating = jqueryRating; 1970 } 1971 1972 if (rating && typeof rating !== 'string') { 1973 console.log('WARNING: Rating is not a string, converting:', rating, typeof rating);
1974 rating = String(rating); 1975 } 1976 1977 if (rating && typeof rating === 'object') { 1978 console.error('CRITICAL ERROR: Rating is still an object!', rating); 1979 rating = null; 1980 } 1981 1982 console.log('Validation check - rating found:', rating, typeof rating); 1983 console.log('Final rating value:', rating, typeof rating); 1984 1985 console.log('Form values before sending:'); 1986 console.log('- Review text:', reviewText); 1987 console.log('- Rating:', rating); 1988 console.log('- Profile ID:', profileId); 1989 console.log('- Reviewer alias:', reviewerAlias); 1990 console.log('- Review heading:', reviewHeading); 1991 console.log('- Anti-forgery token:', antiForgeryToken ? 'Present' : 'Missing'); 1992 1993 // Build form data 1994 var formDataArray = [ 1995 { name: 'profile_id', value: profileId }, 1996 { name: 'review', value: reviewText }, 1997 { name: 'review_rating', value: rating }, 1998 { name: 'reviewer_alias', value: reviewerAlias }, 1999 { name: 'review_heading', value: reviewHeading }, 2000 { name: '__RequestVerificationToken', value: antiForgeryToken }, 2001 { name: 'g-Recaptcha-Response-Review', value: recaptchaToken }, 2002 { name: 'phoneNumber_alternative', value: timeToPost }, 2003 { name: '_t', value: new Date().getTime() } 2004 ]; 2005 2006 var formData = formDataArray 2007 .filter(item => item.value !== undefined && item.value !== null && item.value !== '') 2008 .map(item => encodeURIComponent(item.name) + '=' + encodeURIComponent(item.value)) 2009 .join('&'); 2010 2011 console.log('Manual form data built:', formData); 2012 2013 $.ajax({
2014 url: "/Home/ReviewPost", 2015 type: "POST", 2016 data: formData, 2017 contentType: "application/x-www-form-urlencoded; charset=UTF-8", 2018 dataType: "json", 2019 success: function(data) { 2020 console.log('Review submission response:', data); 2021 2022 if (!data.message || data.message.trim() === '') { 2023 data.message = data.success ? 2024 'Thank you for your review! It has been submitted successfully.' : 2025 'There was an issue submitting your review. Please check all fields and try again.'; 2026 } 2027 2028 alertType = data.success ? "success" : "warning"; 2029 2030 if (!data.success) { 2031 recaptchaReviewIncomplete(); 2032 showClassicCaptcha("review"); 2033 } 2034 2035 $form.find('.alert').remove(); 2036 2037 var alertHtml = '<div class="alert alert-' + alertType + ' alert-dismissible" role="alert">' + 2038 '<button type="button" class="close" data-dismiss="alert" aria-label="Close">' + 2039 '<span aria-hidden="true">×</span></button>' + 2040 data.message + '</div>'; 2041 2042 $form.prepend(alertHtml); 2043 2044 $modal.find('.modal-body').scrollTop(0); 2045 2046 if(alertType === "success") { 2047 // Auto-hide modal after showing success message 2048 setTimeout(function () { 2049 $modal.modal('hide'); 2050 ClearReviewFields(); 2051 }, 3000); 2052 } 2053 2054 // Fade out alert after delay 2055 setTimeout(function() { 2056 $form.find('.alert').fadeOut(500, function() { 2057 $(this).remove(); 2058 }); 2059 }, 6000); 2060 }, 2061 error: function(xhr, status, error) { 2062 console.error('AJAX Error:', status, error); 2063 console.error('Response Text:', xhr.responseText); 2064 2065 $form.find('.alert').remove(); 2066 var errorHtml = '<div class="alert alert-danger alert-dismissible" role="alert">' + 2067 '<button type="button" class="close" data-dismiss="alert" aria-label="Close">' + 2068 '<span aria-hidden="true">×</span></button>' + 2069 'An error occurred while submitting your review. Please try again.</div>'; 2070 $form.prepend(errorHtml); 2071 2072 $modal.find('.modal-body').scrollTop(0); 2073 }, 2074 complete: function() { 2075 // Reset states 2076 console.log('Resetting processing state'); 2077 setProcessingState($button, $form, false); 2078 HideLoading(); 2079 isSubmittingReview = false; 2080 console.log('Review submission completed'); 2081 } 2082 }); 2083 2084 }).catch(function(error) { 2085 console.error('reCAPTCHA Error:', error); 2086 2087 $form.find('.alert').remove(); 2088 var captchaErrorHtml = '<div class="alert alert-danger alert-dismissible" role="alert">
2088' + 2089 '<button type="button" class="close" data-dismiss="alert" aria-label="Close">' + 2090 '<span aria-hidden="true">×</span></button>' + 2091 'Security verification failed. Please refresh the page and try again.</div>'; 2092 $form.prepend(captchaErrorHtml); 2093 2094 $modal.find('.modal-body').scrollTop(0); 2095 setProcessingState($button, $form, false); 2096 HideLoading(); 2097 isSubmittingReview = false; 2098 }); 2099 }); 2100 } else { 2101 console.log('Review validation failed'); 2102 2103 var missingFields = []; 2104 if (!$('#review').val() || $('#review').val().trim() === '') { 2105 missingFields.push('review text'); 2106 } 2107 2108 var rating = null; 2109 var selectRating = $('#starRating')[0] ? $('#starRating')[0].value : null; 2110 var jqueryRating = $('#starRating').val(); 2111 var selectedOption = $('#starRating option:selected').val(); 2112 var barRating = null; 2113 2114 if (typeof $('#starRating').barrating === 'function') { 2115 try { 2116 barRating = $('#starRating').barrating('show'); 2117 } catch (e) { 2118 // Ignore error 2119 } 2120 } 2121 2122 if (barRating && barRating !== "" && barRating !== "0") { 2123 rating = barRating; 2124 } else if (selectRating && selectRating !== "" && selectRating !== "0") { 2125 rating = selectRating; 2126 } else if (selectedOption && selectedOption !== "" && selectedOption !== "0") { 2127 rating = selectedOption; 2128 } else if (typeof jqueryRating === 'string' && jqueryRating !== "" && jqueryRating !== "0") { 2129 rating = jqueryRating; 2130 } 2131 2132 console.log('Validation check - rating found:', rating); 2133 2134 if (!rating || rating === "" || rating === "0") { 2135 missingFields.push('rating'); 2136 } 2137 2138 var validationMessage = 'Please fill out the following required fields: ' + missingFields.join(' and ') + '.'; 2139 console.log('Validation message:', validationMessage); 2140 2141 $form.find('.alert').remove(); 2142 var validationHtml = '<div class="alert alert-warning alert-dismissible" role="alert">' + 2143 '<button type="button" class="close" data-dismiss="alert" aria-label="Close">' + 2144 '<span aria-hidden="true">×</span></button>' + 2145 validationMessage + '</div>'; 2146 $form.prepend(validationHtml); 2147 2148 $modal.find('.modal-body').scrollTop(0); 2149 setProcessingState($button, $form, false); 2150 isSubmittingReview = false; 2151 2152 return false; 2153 } 2154 }); 2155 2156 $('#reviewFormSection').on('hidden.bs.modal', function () { 2157 console.log('Modal hidden - resetting submission state'); 2158 isSubmittingReview = false; 2159 setProcessingState($("#postReview"), $("#postReviewForm"), false); 2160 $(this).find('.alert').remove(); 2161 }); 2162 2163 $('#reviewFormSection').on('show.bs.modal', function () { 2164 console.log('Modal shown - ensuring clean state'); 2165 isSubmittingReview = false; 2166 setProcessingState($("#postReview"), $("#postReviewForm"), false); 2167 2168 $("#postReview").prop('disabled', false); 2169 $("#postReview").css('font-weight', 'bold'); 2170 2171 setTimeout(function () { 2172 console.log('=== STAR RATING DEBUG ==='); 2173 console.log('Star rating element:', $('#starRating')[0]); 2174 console.log('Star rating jQuery object:', $('#starRating')); 2175 console.log('Star rating direct value:', $('#starRating')[0] ? $('#starRating')[0].value : 'N/A'); 2176 console.log('Star rating jQuery val():', $('#starRating').val()); 2177 console.log('Star rating selected option:', $('#starRating option:selected').val()); 2178 console.log('Barrating plugin available:', typeof $('#starRating').barrating === 'function'); 2179 if (typeof $('#starRating').barrating === 'function') { 2180 try { 2181 console.log('Barrating current value:', $('#starRating').barrating('show')); 2182 } catch (e) { 2183 console.log('Error getting barrating value:', e); 2184 } 2185 } 2186 console.log('=== END STAR RATING DEBUG ==='); 2187 }, 100); 2188 }); 2189 2190 // Prevent modal from closing during submission 2191 $('#reviewFormSection').on('hide.bs.modal', function (e) { 2192 if (isSubmittingReview) { 2193 console.log('Preventing modal close during submission'); 2194 e.preventDefault(); 2195 return false; 2196 } 2197 }); 2198 2199 $('a').on('click', function () { 2200 if (this.id !== "undefined" && this.id !== "") { 2201 gtag('event', 'Link Click', { 2202 'event_category': analyticsCategory, 2203 'event_label': this.id 2204 }); 2205 } 2206 }); 2207 2208 $('#PhoneNav').on('click', function () { 2209 gtag('event', 'Link Click', { 2210 'event_category': analyticsCategory, 2211 'event_label': "CustomerBusinessPhoneLinkTemplate6" 2212 }); 2213 }); 2214 $('.phoneLinkInput').on('click', function () { 2215 gtag('event', 'Link Click', { 2216 'event_category': analyticsCategory, 2217 'event_label': "CustomerBusinessPhoneLinkTemplate6-1" 2218 }); 2219 }); 2220 $('#contactPhoneLink').on('click', function () { 2221 gtag('event', 'Link Click', { 2222 'event_category': analyticsCategory, 2223 'event_label': "CustomerBusinessPhoneLinkTemplate6-2"
2224 }); 2225 }); 2226 $('#contactPrimaryPhoneLink').on('click', function () { 2227 gtag('event', 'Link Click', { 2228 'event_category': analyticsCategory, 2229 'event_label': "CustomerBusinessPhoneLinkTemplate6-3" 2230 }); 2231 }); 2232 $('#contactSecondaryPhoneLink').on('click', function () { 2233 gtag('event', 'Link Click', { 2234 'event_category': analyticsCategory, 2235 'event_label': "CustomerBusinessPhoneLinkTemplate6-4" 2236 }); 2237 }); 2238 $('#contactMobilePhoneLink').on('click', function () { 2239 gtag('event', 'Link Click', { 2240 'event_category': analyticsCategory, 2241 'event_label': "CustomerBusinessPhoneLinkTemplate6-5" 2242 }); 2243 }); 2244 $('#contactFaxPhoneLink').on('click', function () { 2245 gtag('event', 'Link Click', { 2246 'event_category': analyticsCategory, 2247 'event_label': "CustomerBusinessPhoneLinkTemplate6-6" 2248 }); 2249 }); 2250 $('#contactTollfreePhoneLink').on('click', function () { 2251 gtag('event', 'Link Click', { 2252 'event_category': analyticsCategory, 2253 'event_label': "CustomerBusinessPhoneLinkTemplate6-7" 2254 }); 2255 }); 2256 $('#contactPhoneC1').on('click', function () { 2257 gtag('event', 'Link Click', { 2258 'event_category': analyticsCategory, 2259 'event_label': "CustomerContactPhoneLinkTemplate6-8" 2260 }); 2261 }); 2262 $('#contactPhoneC2').on('click', function () { 2263 gtag('event', 'Link Click', { 2264 'event_category': analyticsCategory, 2265 'event_label': "CustomerContactPhoneLinkTemplate6-9" 2266 }); 2267 }); 2268 $('#contactPhoneC3').on('click', function () { 2269 gtag('event', 'Link Click', { 2270 'event_category': analyticsCategory, 2271 'event_label': "CustomerContactPhoneLinkTemplate6-10" 2272 }); 2273 }); 2274 $('#contactPhoneC4').on('click', function () { 2275 gtag('event', 'Link Click', { 2276 'event_category': analyticsCategory, 2277 'event_label': "CustomerContactPhoneLinkTemplate6-11" 2278 }); 2279 }); 2280 $('#contactPhoneC5').on('click', function () { 2281 gtag('event', 'Link Click', { 2282 'event_category': analyticsCategory, 2283 'event_label': "CustomerContactPhoneLinkTemplate6-12" 2284 }); 2285 }); 2286 $('#contactEmail').on('click', function () { 2287 gtag('event', 'Link Click', { 2288 'event_category': analyticsCategory, 2289 'event_label': "CustomerBusinessEmailLinkTemplate6" 2290 }); 2291 }); 2292 $('#writeReviewBt').on('click', function () { 2293 gtag('event', 'Button Click', { 2294 'event_category': analyticsCategory, 2295 'event_label': "WriteReviewButtonTemplate6" 2296 }); 2297 }); 2298 $(document).on('click', '#postReview', function () { 2299 gtag('event', 'Button Click', { 2300 'event_category': analyticsCategory, 2301 'event_label': "PostReviewButtonTemplate6" 2302 }); 2303 }); 2304 $('#nextReview').on('click', function () { 2305 gtag('event', 'Button Click', { 2306 'event_category': analyticsCategory, 2307 'event_label': "ShowNextReviewsButtonTemplate6" 2308 }); 2309 }); 2310 $('#prevReview').on('click', function () { 2311 gtag('event', 'Button Click', { 2312 'event_category': analyticsCategory, 2313 'event_label': "ShowPreviousReviewsButtonTemplate6" 2314 }); 2315 }); 2316 $('#google-social').on('click', function () { 2317 gtag('event', 'Link Click', { 2318 'event_category': analyticsCategory, 2319 'event_label': "CustomerGoogleSocialLinkTemplate6-1" 2320 }); 2321 }); 2322 $('#facebook-social').on('click', function () { 2323 gtag('event', 'Link Click', { 2324 'event_category': analyticsCategory, 2325 'event_label': "CustomerFacebookSocialLinkTemplate6-1" 2326 }); 2327 }); 2328 $('#yelp-social').on('click', function () { 2329 gtag('event', 'Link Click', { 2330 'event_category': analyticsCategory, 2331 'event_label': "CustomerYelpSocialLinkTemplate6-1" 2332 }); 2333 }); 2334 $('#twitter-social').on('click', function () { 2335 gtag('event', 'Link Click', { 2336 'event_category': analyticsCategory, 2337 'event_label': "CustomerTwitterSocialLinkTemplate6-1" 2338 }); 2339 }); 2340 $('#linkedin-social').on('click', function () { 2341 gtag('event', 'Link Click', { 2342 'event_category': analyticsCategory, 2343 'event_label': "CustomerLinkedinSocialLinkTemplate6-1" 2344 }); 2345 }); 2346 $('#instagram-social').on('click', function () { 2347 gtag('event', 'Link Click', { 2348 'event_category': analyticsCategory,
2349 'event_label': "CustomerInstagramSocialLinkTemplate6-1" 2350 }); 2351 }); 2352 $('#google-social-footer').on('click', function () { 2353 gtag('event', 'Link Click', { 2354 'event_category': analyticsCategory, 2355 'event_label': "CustomerGoogleSocialLinkTemplate6-2" 2356 }); 2357 }); 2358 $('#facebook-social-footer').on('click', function () { 2359 gtag('event', 'Link Click', { 2360 'event_category': analyticsCategory, 2361 'event_label': "CustomerFacebookSocialLinkTemplate6-2" 2362 }); 2363 }); 2364 $('#yelp-social-footer').on('click', function () { 2365 gtag('event', 'Link Click', { 2366 'event_category': analyticsCategory, 2367 'event_label': "CustomerYelpSocialLinkTemplate6-2" 2368 }); 2369 }); 2370 $('#twitter-social-footer').on('click', function () { 2371 gtag('event', 'Link Click', { 2372 'event_category': analyticsCategory, 2373 'event_label': "CustomerTwitterSocialLinkTemplate6-2" 2374 }); 2375 }); 2376 $('#linkedin-social-footer').on('click', function () { 2377 gtag('event', 'Link Click', { 2378 'event_category': analyticsCategory, 2379 'event_label': "CustomerLinkedinSocialLinkTemplate6-2" 2380 }); 2381 }); 2382 $('#instagram-social-footer').on('click', function () { 2383 gtag('event', 'Link Click', { 2384 'event_category': analyticsCategory, 2385 'event_label': "CustomerInstagramSocialLinkTemplate6-2" 2386 }); 2387 }); 2388 $('#contactEmailFooter').on('click', function () { 2389 gtag('event', 'Link Click', { 2390 'event_category': analyticsCategory, 2391 'event_label': "CustomerBusinessEmailLinkTemplate6-2" 2392 }); 2393 }); 2394 $('#btnContactPost').on('click', function () { 2395 gtag('event', 'Link Click', { 2396 'event_category': analyticsCategory, 2397 'event_label': "CustomerContactLeadPostTemplate6" 2398 }); 2399 }); 2400 $("#external-review-link").on('click', function () { 2401 gtag('event', 'Link Click', { 2402 'event_category': analyticsCategory, 2403 'event_label': "CustomerExternalReviewLinkTemplate6" 2404 }); 2405 }); 2406 $('#video').on('click', function () { 2407 gtag('event', 'Video Click', { 2408 'event_category': analyticsCategory, 2409 'event_label': "CustomerVideoTemplate6" 2410 }); 2411 }); 2412 $('#website-social').on('click', function () { 2413 gtag('event', 'Link Click', { 2414 'event_category': analyticsCategory, 2415 'event_label': "CustomerWebsiteSocialLinkTemplate6-1" 2416 }); 2417 }); 2418 $('#website-social-footer').on('click', function () { 2419 gtag('event', 'Link Click', { 2420 'event_category': analyticsCategory, 2421 'event_label': "CustomerWebsiteSocialLinkTemplate6-2" 2422 }); 2423 }); 2424 $('#photos-image-element').on('click', function () { 2425 gtag('event', 'Link Click', { 2426 'event_category': analyticsCategory, 2427 'event_label': "CustomerWebsiteImageryPhotoTemplate6" 2428 }); 2429 }); 2430 $('#HomePageNavigationLink').on('click', function () { 2431 gtag('event', 'Link Click', { 2432 'event_category': analyticsCategory, 2433 'event_label': "CustomerHomePageNavLinkTemplate6" 2434 }); 2435 }); 2436 $('#ContactPageNavigationLink').on('click', function () { 2437 gtag('event', 'Link Click', { 2438 'event_category': analyticsCategory, 2439 'event_label': "CustomerContactPageNavLinkTemplate6" 2440 }); 2441 }); 2442 $('#PhotosNavigationLink').on('click', function () { 2443 gtag('event', 'Link Click', { 2444 'event_category': analyticsCategory, 2445 'event_label': "CustomerPhotosPageNavLinkTemplate6" 2446 }); 2447 }); 2448 $('#testimoinalsPageNavigationLink').on('click', function () { 2449 gtag('event', 'Link Click', { 2450 'event_category': analyticsCategory, 2451 'event_label': "CustomerTestimonialsPageNavLinkTemplate6" 2452 }); 2453 }); 2454 $('#ServicesPageNavigationLink').on('click', function () { 2455 gtag('event', 'Link Click', { 2456 'event_category': analyticsCategory, 2457 'event_label': "CustomerServicesPageNavLinkTemplate6" 2458 }); 2459 }); 2460 $('#AboutPageNavigationLink').on('click', function () { 2461 gtag('event', 'Link Click', { 2462 'event_category': analyticsCategory, 2463 'event_label': "CustomerAboutPageNavLinkTemplate6" 2464 }); 2465 }); 2466 $('#GSVPageNavigationLink').on('click', function () { 2467 gtag('event', 'Link Click', { 2468 'event_category': analyticsCategory, 2469 'event_label': "CustomerGSVTourPageNavLinkTemplate3" 2470 }); 2471 }); 2472 //unable to directly track cross domain iFrame clicks. Track only first click on the iFrame itself 2473 var monitor = setInterval(function () { 2474 var elem = document.activeElement; 2475 if (elem && elem.tagName == "IFRAME" && elem.id == "googleMapEmbed") { 2476 gtag('event', 'iFrame Click', { 2477 'event_category': analyticsCategory, 2478 'event_label': "GoogleDirectionsTemplate6" 2479 }); 2480 clearInterval(monitor); 2481 } 2482 }, 1000); 2483 });
2484 2485 var servicesRendered = false; 2486 var aboutRendered = false; 2487 var testimonialsRendered = false; 2488 var contactRendered = false; 2489 var photosRendered = false; 2490 var locationsRendered = false; 2491 var gsvRendered = false; 2492 var faqRendered = false; 2493 var contentRendered = false; 2494 2495 function DisplayPage(page) { 2496 2497 PauseVideoPlayer(); 2498 2499 if (!$(page).hasClass("show")) { 2500 $("#pages div.collapse.show").collapse("hide"); 2501 } 2502 $(page).collapse("show"); 2503 2504 if(page == "#homePage") 2505 { 2506 var carousel = $(".slick-slider"); 2507 if(carousel != null) 2508 { 2509 carousel.slick('refresh'); 2510 } 2511 } 2512 2513 if (page == "#testimonialsPage") { 2514 // Load Testimonials via Ajax if not already loaded 2515 if (!testimonialsRendered) { 2516 ShowLoading(); 2517 $.get('/Home/GetTestimonialsContent', {id: 37496, template: "Template_6"}, function (data) { 2518 if (data != "") 2519 { 2520 $("#testimonialsPage").append(data); 2521 } 2522 }).always(function() { 2523 HideLoading(); 2524 testimonialsRendered = true; 2525 GetReviewData(0); 2526 }); 2527 } 2528 2529 $("html, body").animate({ scrollTop: 0 }, "fast"); 2530 } 2531 2532 if (page == "#aboutPage") { 2533 // Load About via Ajax if not already loaded 2534 if (!aboutRendered) { 2535 ShowLoading(); 2536 $.get('/Home/GetAboutContent', { id: 37496, template: "Template_6"}, function (data) { 2537 if (data != "") 2538 { 2539 $("#aboutPage").append(data); 2540 $.getScript("https://maps.googleapis.com/maps/api/js?key=AIzaSyB2UoPWVWPR8WrIFK_zqJ5nTN1NvGm9dqY&callback=initMap"); 2541 } 2542 }).always(function() { 2543 HideLoading(); 2544 aboutRendered = true; 2545 }); 2546 } 2547 } 2548 2549 if (page == "#servicesPage") { 2550 // Load Services via Ajax if not already loaded 2551 if (!servicesRendered) { 2552 ShowLoading(); 2553 $.get('/Home/GetServicesContent', { id: 37496, template: "Template_6"}, function (data) { 2554 if (data != "") 2555 { 2556 $("#servicesPage").append(data); 2557 } 2558 }).always(function() { 2559 HideLoading(); 2560 servicesRendered = true; 2561 }); 2562 } 2563 } 2564 2565 if (page == "#imageryPage") { 2566 // Load photos via Ajax if not already loaded 2567 if (!photosRendered) { 2568 ShowLoading(); 2569 $.get('/Home/GetPhotosContent', { id: 37496, template: "Template_6"}, function (data) { 2570 if (data != "") 2571 { 2572 $("#imageryPage").append(data); 2573 } 2574 }).always(function() { 2575 HideLoading(); 2576 photosRendered = true; 2577 }); 2578 } 2579 } 2580 2581 if (page == "#contactPage") { 2582 // Load Contact via Ajax if not already loaded 2583 if (!contactRendered) { 2584 ShowLoading(); 2585 $.get('/Home/GetContactContent', { id: 37496, template: "Template_6"}, function (data) { 2586 if (data != "") 2587 { 2588 $("#contactPage").append(data); 2589 } 2590 }).always(function() { 2591 HideLoading(); 2592 contactRendered = true; 2593 }); 2594 } 2595 } 2596 2597 if (page == "#locationsPage") { 2598 // Load Locations via Ajax if not already loaded 2599 if (!locationsRendered) { 2600 ShowLoading(); 2601 2602 $.get('/Home/GetLocationsContent', { id: 37496, template: "Template_6" }, function (data) { 2603 if (data != "") 2604 { 2605 $("#locationsPage").append(data); 2606 } 2607 }).always(function() { 2608 HideLoading(); 2609 locationsRendered = true; 2610 }); 2611 } 2612 } 2613 2614 if (page == "#gsvPage") { 2615 // Load GSV via Ajax if not already loaded 2616 if (!gsvRendered) { 2617 ShowLoading(); 2618 $.get('/Home/Get360TourContent', { id: 37496, template: "Template_6"}, function (data) { 2619 if (data != "") 2620 { 2621 $("#gsvPage").append(data); 2622 } 2623 }).always(function() { 2624 HideLoading(); 2625 gsvRendered = true; 2626 }); 2627 } 2628 } 2629 2630 if (page == "#faqPage") { 2631 // Load Faqs via Ajax if not already loaded 2632 if (!faqRendered) { 2633 ShowLoading(); 2634 2635 $.get('/Home/GetFAQContent', { id: 37496, template: "Template_6" }, function (data) { 2636 if (data != "") { 2637 $("#faqPage").append(data); 2638 } 2639 }).always(function () { 2640 HideLoading(); 2641 faqRendered = true; 2642 }); 2643 } 2644 } 2645 2646 if (page == "#contentPage") { 2647 if (!contentRendered) { 2648 ShowLoading(); 2649 2650 $.get('/Home/GetAdditionalContentContent', { id: 37496, template: "Template_6" }, function (data) { 2651 if (data != "") { 2652 $("#contentPage").append(data); 2653 } 2654 }).always(function () { 2655 HideLoading(); 2656 contentRendered = true; 2657 }); 2658 } 2659 } 2660 } 2661 2662 function nextReview() { 2663 ScrollForReviews(); 2664 GetReviewData(1); 2665 } 2666 2667 function prevReview() { 2668 ScrollForReviews(); 2669 GetReviewData(-1); 2670 } 2671 2672 function GetReviewData(i) 2673 { 2674 if(i != 0){ 2675 ShowLoading(); 2676 } 2677 pageIndex = pageIndex + i; 2678 $.get('/Home/GetEnhancedTestimonialReviewInfo', {id: 37496, pageIndex: pageIndex, pageSize: pageSize, notReputation: notReputation, file: '_TemplateReviewContent'}, function (data) { 2679 if (data != "") 2680 { 2681 $(".reviewInfo").html(data); 2682 } 2683 }).always(function() { 2684 HideLoading(); 2685 }); 2686 SetPaginationButtons(); 2687 } 2688 2689 function GetPostsData(i) 2690 { 2691 if(i != 0){ 2692 ShowLoading(); 2693 } 2694 postsPageIndex = postsPageIndex + i; 2695 $.get('/Home/GetTestimonialPostsInfo', {id: 37496, program_id: 17, profileDomain: 'https://koenenswaterworksplumbing.com/', subdomain: 'koenenswaterworksplumbing', testimonialSSL : 'False', domainSSL : 'True', pageIndex: postsPageIndex, pageSize: pageSize, file: '_TestimonialPostsContent'}, function (data) { 2696 if (data != "") 2697 { 2698 $(".postsInfo").html(data); 2699 } 2700 }).always(function() { 2701 HideLoading(); 2702 }); 2703 SetPostsPaginationButtons(); 2704 } 2705 2706 function GetPostsBanner() 2707 { 2708 ShowLoading(); 2709 var bannerObj = {"id":475650,"urgency_item_type_id":15,"urgency_status_id":4,"delay_reason":null,"delay_notification_sent":null,"created":"2026-09-01T09:14:48","created_by":"bbcb7930-ba94-11ec-939c-005056b02f53","created_note":"AMPLibrary.Optima2.Urgency.UrgencyItem.AddUrgencyItem()","modified":"2026-09-01T17:03:45","modified_by":"Personiv User17","modified_note":"AMPLibrary.Optima2.Urgency.UrgencyItem.UpdateUrgencyItem()","deleted":null,"deleted_by":null,"deleted_note":null,"profile_review_id":null,"review_response":null,"profile_review_response_image_id":null,"google_post_title":"ð½ð§ Upgrade Your Flush, Save Your Cash! ð§ð½","google_post_start":"2026-09-01T09:14:00","google_post_end":"2027-08-31T00:00:00","google_post_body":"ð½ Did you know your toilet could be wasting thousands of gallons of water each year without you even realizing it? \r\n\r\nOlder or inefficient toilets can quietly drive up your water bill and waste valuable water every day. If your toilet is constantly running, requires multiple flushes, or is simply outdated, it may be time for an upgrade. \r\n\r\nð§ A water-saving toilet can help: â Lower utility bills \r\n\r\nâ Reduce water waste \r\n\r\nâ Improve efficiency \r\n\r\nâ Deliver reliable performance with every flush \r\n\r\nAt Koenen's Water Works Plumbing, we can help you choose and install the right toilet for your home and budget. \r\n\r\nð Ready to save water and money? Give us a call today! \r\n\r\nð Proudly serving Southeast Wisconsin \r\n\r\n#KoenensWaterWorks #BurlingtonWI #WaterSavingToilets #PlumbingTips #HomeEfficiency #SaveWater #LowerUtilityBills #LocalPlumber","google_post_network_path":"\\\\w19-amp-imagery\\optima_media\\googlepost\\P_37496\\36f42927-1f88-4d14-8520-7aef4d8e0b34.jpeg","google_post_web_path":"https://du9m0k402rjmo.
2709cloudfront.net/googlepost/P_37496\\36f42927-1f88-4d14-8520-7aef4d8e0b34.jpeg","google_post_filename":"36f42927-1f88-4d14-8520-7aef4d8e0b34.jpeg","google_post_option":"Call Now","google_post_link":"???? Upgrade Your Flush, Save Your Cash! ????","completed_notification_sent":null,"completed_feedback":null,"post_display_date":"2026-09-01T00:00:00","post_to_google":true,"post_to_testimonial":true,"attention_grabber":"WATER\r\nWISE","deleted_reason":null,"urgency_google_post_option_id":6,"post_feature":true,"post_feature_expiration":"2027-08-31T00:00:00","crm_post_id":132675,"ignore_end_dates":false,"hide_start_date":true,"hide_expiration_date":true,"google_post_submitted":false,"keep_feature_post_up":false,"api_status":null,"api_message":null,"api_posted":null}; 2710 $.ajax({ 2711 method: "POST", 2712 url: "/Home/GetPostBanner", 2713 data:JSON.stringify( 2714 { 2715 banner: bannerObj, 2716 testimonialPageColor: (true) ? 'transparent' :'#F5F5F5', 2717 postsColor: '#F5F5F5' 2718 }), 2719 contentType: 'application/json', 2720 success: function (data) { 2721 if(isMobile || isTablet){ 2722 setTimeout(function(){ 2723 $(".home-content").prepend(data); 2724 }, 5000); 2725 } 2726 else{ 2727 $(".home-content").prepend(data); 2728 } 2729 2730 //remove banner after 30 seconds regardless of mobile/tablet/desktop 2731 if (!keepPostUp) { 2732 setTimeout(function () { 2733 $("#posts-banner-alert").remove(); 2734 }, 30000); 2735 } 2736 } 2737 }).always(function() { 2738 HideLoading(); 2739 }); 2740 } 2741 2742 function SetPaginationButtons() 2743 { 2744 //look ahead by one 2745 if(((pageIndex + 1) * pageSize) >= numOfReviews){ 2746 $("#nextReview").hide(); 2747 } 2748 else{ 2749 $("#nextReview").show(); 2750 $("#nextReview").prop('disabled', false); 2751 } 2752 2753 if(pageIndex <= 0) { 2754 pageIndex = 0; 2755 $("#prevReview").hide(); 2756 } 2757 else if (pageIndex > 0){ 2758 $("#prevReview").show(); 2759 $("#prevReview").prop('disabled', false); 2760 } 2761 } 2762 2763 function SetPostsPaginationButtons() 2764 { 2765 //look ahead by one 2766 if(((postsPageIndex + 1) * pageSize) >= numOfPosts){ 2767 $("#nextPosts").hide(); 2768 } 2769 else{ 2770 $("#nextPosts").show(); 2771 $("#nextPosts").prop('disabled', false); 2772 } 2773 2774 if(postsPageIndex <= 0) { 2775 postsPageIndex = 0; 2776 $("#prevPosts").hide(); 2777 } 2778 else if (postsPageIndex > 0){ 2779 $("#prevPosts").show(); 2780 $("#prevPosts").prop('disabled', false); 2781 } 2782 } 2783 2784 function ShowLoading() 2785 { 2786 $("#loadingImg").show(); 2787 } 2788 2789 function HideLoading() 2790 { 2791 $("#loadingImg").hide(); 2792 } 2793 2794 function checkMobile() { 2795 var windowsize = $(window).width(); 2796 switch (true) { 2797 case /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent): 2798 isMobile = true; 2799 break; 2800 case windowsize < 800: 2801 isMobile = true; 2802 break; 2803 default: 2804 isMobile = false; 2805 } 2806 } 2807 2808 function checkTablet() { 2809 var windowsize = $(window).width(); 2810 switch (true) { 2811 case (windowsize >= 800) && (windowsize < 1200): 2812 isTablet = true; 2813 break; 2814 default: 2815 isTablet = false; 2816 } 2817 } 2818 2819 function DisplayPhoto(imageUrl){ 2820 bootbox.alert({ 2821 message:'<img class="img-fluid d-block mx-auto" src="' + imageUrl + '" />', 2822 size: "large", 2823 backdrop: true, 2824 buttons: { 2825 ok: { 2826 className: 'btn-outline-dark', 2827 label: 'Close' 2828 } 2829 } 2830 }); 2831 } 2832
2833 function DisplayPhotoSlider(index){ 2834 if(!$(".slider-imagery").hasClass("slick-initialized")) 2835 { 2836 $('.slider-imagery').slick({ 2837 slidesToShow: 1, 2838 slidesToScroll: 1, 2839 arrows: true, 2840 fade: false, 2841 adaptiveHeight: false, 2842 infinite: true, 2843 useTransform: true, 2844 speed: 400, 2845 cssEase: 'cubic-bezier(0.77, 0, 0.18, 1)', 2846 autoplay: true, 2847 }); 2848 } 2849 2850 $(".slider-imagery").slick('slickGoTo', index); 2851 2852 $("#carouselImageryPhotoModal").modal('show'); 2853 } 2854 2855 function DisplayVideoSlider(index) { 2856 2857 if(!$(".slider-video").hasClass("slick-initialized")) 2858 { 2859 $('.slider-video').slick({ 2860 slidesToShow: 1, 2861 slidesToScroll: 1, 2862 arrows: true, 2863 fade: false, 2864 adaptiveHeight: false, 2865 infinite: true, 2866 useTransform: true, 2867 speed: 400, 2868 cssEase: 'cubic-bezier(0.77, 0, 0.18, 1)', 2869 }); 2870 } 2871 2872 PauseVideoPlayer(); 2873 2874 //arrow onclick tracker 2875 var el = document.querySelectorAll(".slick-arrow"); 2876 for (var i = 0; i < el.length; i++) { 2877 el[i].onclick = function () { 2878 PauseVideoPlayer(); 2879 }; 2880 } 2881 2882 2883 $(".slider-video").slick('slickGoTo', index); 2884 2885 $("#carouselImageryVideoModal").modal('show'); 2886 } 2887 2888 function PauseVideoPlayer() { 2889 2890 var videos = document.querySelectorAll('video'); 2891 var iframes = document.querySelectorAll('iframe'); 2892 2893 //mp4 2894 Array.prototype.forEach.call(videos, video => { 2895 video.pause(); 2896 }); 2897 2898 //youtube 2899 Array.prototype.forEach.call(iframes, iframe => { 2900 iframe.contentWindow.postMessage(JSON.stringify({ 2901 event: 'command', 2902 func: 'pauseVideo' 2903 }), '*'); 2904 }); 2905 2906 //wistia + vimeo 2907 Array.prototype.forEach.call(iframes, iframe => { 2908 iframe.contentWindow.postMessage(JSON.stringify({ 2909 "method": "pause", 2910 "value": "true" 2911 }), '*'); 2912 }); 2913 } 2914 2915 function setFooterColor(hexColor) 2916 { 2917 //set footer text color based on background color 2918 var r = parseInt(hexColor.substr(1,2),16); 2919 var g = parseInt(hexColor.substr(3,2),16); 2920 var b = parseInt(hexColor.substr(5,2),16); 2921 var rgb = ((r*299)+(g*587)+(b*114))/1000; 2922 2923 var textColor = (rgb >= 128) ? 'black' : 'white'; 2924 //text needs to be black 2925 if(textColor == 'black') 2926 { 2927 //set payment method icons 2928 if ($('.paymentType').hasClass('light')) { 2929 $('.paymentType').removeClass('light'); 2930 $('.paymentType').remove('#paymentTypeLight'); 2931 } 2932 if (!$('.paymentType').hasClass('dark')) { 2933 $('.paymentType').addClass('dark'); 2934 $('.paymentType').remove('#paymentTypeLight'); 2935 $('.paymentType').add('#paymentTypeDark'); 2936 } 2937 } 2938 //text needs to be white 2939 else if(textColor == 'white') 2940 { 2941 //mobile menu hamburger 2942 if ($('.navbar-toggler').hasClass('dark')) { 2943 $('.navbar-toggler').css('background-color', 'transparent'); 2944 } 2945 if (!$('.navbar-toggler').hasClass('light')) { 2946 $('.navbar-toggler').css('background-color', 'white'); 2947 } 2948 2949 //set payment method icons 2950 if ($('.paymentType').hasClass('dark')) { 2951 $('.paymentType').removeClass('dark'); 2952 $('.paymentType').remove('#paymentTypeDark'); 2953 } 2954 if (!$('.paymentType').hasClass('light')) { 2955 $('.paymentType').addClass('light'); 2956 $('.paymentType').remove('#paymentTypeDark'); 2957 $('.paymentType').add('#paymentTypeLight'); 2958 } 2959 } 2960 } 2961 2962 function checkHashRoute() 2963 { 2964 if ((location.hash != null) && (location.hash != "") && (location.hash == '#homePage' || location.hash == '#aboutPage' || location.hash == '#servicesPage' || location.hash == '#testimonialsPage' || location.hash == '#contactPage' || location.hash == '#locationsPage' || location.hash == '#faqPage' || location.hash == '#gsvPage' || location.hash == '#contentPage') ) { 2965 DisplayPage(location.hash); 2966 } 2967 } 2968 2969 function contactUsPost(event) { 2970 var _contactForm = $("#ContactPostForm"); 2971 2972 // Clear previous validation states 2973 $('.validation-error-message').remove(); 2974 _contactForm.find('.validation-error').removeClass('validation-error'); 2975 $("#contactResponseMessage").empty(); 2976 2977 if (_contactForm[0].checkValidity()) { 2978 contactUsSubmit(event); 2979 } else { 2980 var firstInvalidField = null; 2981 2982 _contactForm.find('input[required], textarea[required], select[required]').each(function () { 2983 var $field = $(this); 2984 2985 if (!this.checkValidity()) { 2986 var fieldId = $field.attr('id') || $field.attr('name'); 2987 var fieldLabel = getFieldLabel(fieldId); 2988 2989 $field.addClass('validation-error'); 2990 2991 var errorMessage = getCustomErrorMessage($field, fieldLabel); 2992 $field.after(`<div class="validation-error-message">${errorMessage}</div>`); 2993 2994 if (!firstInvalidField) { 2995 firstInvalidField = $field; 2996 } 2997 } 2998 }); 2999 3000 // Focus first invalid field 3001 if (firstInvalidField) { 3002 firstInvalidField.focus(); 3003 } 3004 3005 // Re-enable submit button 3006 $("#btnContactPost").prop('disabled', false); 3007 $("#btnContactPost").css('font-weight', 'bold'); 3008 } 3009 } 3010 3011 function getFieldLabel(fieldId) { 3012 var labels = { 3013 'contact_us_phone': 'Phone Number', 3014 'contact_us_address': 'Address', 3015 'contact_us_city': 'City', 3016 'contact_us_state': 'State', 3017 'contact_us_zip': 'ZIP Code', 3018 'contact_us_subject': 'Subject', 3019 'contact_us_name': 'Name', 3020 'contact_us_email': 'Email', 3021 'contact_us_message': 'Message' 3022 }; 3023 return labels[fieldId] || 'This field'; 3024 } 3025 3026 function getCustomErrorMessage($field, fieldLabel) { 3027 if ($field.prop('required') && !$field.val().trim()) { 3028 return `${fieldLabel} required`; 3029 } 3030 3031 if ($field.attr('type') === 'email' && $field.val()) { 3032 return `Please enter a valid email address.`; 3033 } 3034 3035 return `Please enter a valid ${fieldLabel.toLowerCase()}.`; 3036 } 3037 3038 function contactUsSubmit(event) { 3039 event.preventDefault(); 3040 3041 var form = $("#ContactPostForm"); 3042 grecaptcha.ready(function() { 3043 grecaptcha.execute('6LcokacUAAAAAH_snk3O5bpdYwjpC5XAuXNLrJLH', {action: 'contact_us'}).then(function(token) { 3044 $("#g-Recaptcha-Response-Contact").attr("value", token); //add token for server side validation 3045 $.ajax({
3046 type: "POST", 3047 url: "/Home/ContactPost", 3048 data: form.serialize(), 3049 success: function(data){ 3050 if (data.indexOf('{"message":') != -1) { 3051 var jsonData = JSON.parse(data); 3052 if (!jsonData.success) { 3053 $("#contactResponseMessage").html('<div class="alert alert-warning alert-dissmisable" role="alert"><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>' + jsonData.message + '</div>'); 3054 recaptchaContactUsInComplete(); 3055 showClassicCaptcha("contact"); 3056 } 3057 else{ 3058 $("#contactResponseMessage").html('<div class="alert alert-success alert-dissmisable" role="alert"><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>' + jsonData.message + '</div>'); 3059 recaptchaContactUsComplete(); 3060 } 3061 } 3062 } 3063 }); 3064 }); 3065 }); 3066 } 3067 3068 function bgSlider() { 3069 var index = 0; 3070 var opacity = 'False'; 3071 3072 $imageEls = $('.parallax .parallax-image'); // Get the images to be cycled. 3073 3074 setInterval(function () { 3075 // Get the next index. If at end, restart to the beginning. 3076 index = index + 1 < $imageEls.length ? index + 1 : 0; 3077 3078 // Show the next 3079 if (opacity == 'True') { 3080 $imageEls.eq(index).addClass('opacity'); 3081 } 3082 else { 3083 $imageEls.eq(index).addClass('show'); 3084 } 3085 3086 // Hide the previous 3087 if (opacity == 'True') { 3088 $imageEls.eq(index - 1).removeClass('opacity'); 3089 } 3090 else { 3091 $imageEls.eq(index - 1).removeClass('show'); 3092 } 3093 }, 5000); 3094 } 3095 3096 function initializeCarousel(){ 3097 //https://codepen.io/dolce/pen/QarQde 3098 $('.slider-single').slick({ 3099 slidesToShow: 1, 3100 slidesToScroll: 1, 3101 arrows: true, 3102 fade: false, 3103 adaptiveHeight: false, 3104 infinite: true, 3105 useTransform: true, 3106 speed: 400, 3107 cssEase: 'cubic-bezier(0.77, 0, 0.18, 1)', 3108 autoplay: true, 3109 }); 3110 3111 $('.slider-nav') 3112 .on('init', function(event, slick) { 3113 $('.slider-nav .slick-slide.slick-current').addClass('is-active'); 3114 }) 3115 .slick({ 3116 slidesToShow: 5, 3117 slidesToScroll: 5, 3118 dots: false, 3119 focusOnSelect: false, 3120 infinite: true, 3121 }); 3122 3123 $('.slider-attributes') 3124 .on('init', function(event, slick) { 3125 $('.slider-attributes .slick-slide.slick-current').addClass('is-active'); 3126 }) 3127 .slick({ 3128 slidesToShow: 3, 3129 slidesToScroll: 3, 3130 dots: false, 3131 focusOnSelect: false, 3132 infinite: true 3133 }); 3134 3135 $('.slider-single').on('afterChange', function(event, slick, currentSlide) { 3136 $('.slider-nav').slick('slickGoTo', currentSlide); 3137 var currrentNavSlideElem = '.slider-nav .slick-slide[data-slick-index="' + currentSlide + '"]'; 3138 $('.slider-nav .slick-slide.is-active').removeClass('is-active'); 3139 $(currrentNavSlideElem).addClass('is-active'); 3140 3141 if (currentSlide > 6) { 3142 var m = parseInt(currentSlide / 6); 3143 var d = 6 * m; 3144 var currentAttributeSlide = currentSlide - d; 3145 } 3146 else if (currentSlide >= 3 && currentSlide <= 6) 3147 { 3148 var m = parseInt(currentSlide / 3); 3149 var d = 3 * m; 3150 var currentAttributeSlide = currentSlide - d; 3151 } 3152 else { 3153 currentAttributeSlide = currentSlide; 3154 } 3155 3156 if (6 > 3) { 3157 $('.slider-attributes').slick('slickGoTo', currentAttributeSlide); 3158 var currrentNavAttributeSlideElem = '.slider-attributes .slick-slide[data-slick-index="' + currentAttributeSlide + '"]'; 3159 $('.slider-attributes .slick-slide.is-active').removeClass('is-active'); 3160 $(currrentNavAttributeSlideElem).addClass('is-active'); 3161 } 3162 }); 3163 3164 $('.slider-nav').on('click', '.slick-slide', function(event) { 3165 event.preventDefault(); 3166 var goToSingleSlide = $(this).data('slick-index'); 3167 $('.slider-single').slick('slickGoTo', goToSingleSlide); 3168 }); 3169 3170 $('.slider-attributes').on('click', '.slick-slide', function(event) { 3171 event.preventDefault(); 3172 var goToSingleSlide = $(this).data('slick-index'); 3173 $('.slider-single').slick('slickGoTo', goToSingleSlide); 3174 }); 3175 } 3176 3177 function ScrollForReviews(){ 3178 // target element 3179 var $id = $(".review-partial-content"); 3180 if ($id.length === 0) { 3181 return; 3182 } 3183 3184 // prevent standard hash navigation (avoid blinking in IE) 3185 //e.preventDefault(); 3186 3187 // top position relative to the document 3188 var pos = $id.offset().top - $('.navbar').height(); 3189 3190 // animated top scrolling 3191 // .stop() keeps from scrolling to top then to element 3192 $('body, html').stop().animate({ scrollTop: pos }, 500); 3193 } 3194 3195 function ScrollForPosts(e){ 3196 // target element 3197 var $id = $(".posts-partial-content"); 3198 if ($id.length === 0) { 3199 return; 3200 } 3201 3202 // prevent standard hash navigation (avoid blinking in IE) 3203 e.preventDefault(); 3204 3205 // top position relative to the document 3206 var pos = $id.offset().top - $('.navbar').height(); 3207 3208 // animated top scrolling 3209 // .stop() keeps from scrolling to top then to element 3210 $('body, html').stop().animate({ scrollTop: pos }, 500); 3211 } 3212 3213 function recaptchaContactUsInComplete(){ 3214 $("#btnContactPost").prop('disabled', false); 3215 $("#btnContactPost").css('font-weight', 'bold'); 3216 } 3217 3218 function recaptchaContactUsComplete() { 3219 $("#btnContactPost").prop('disabled', false); 3220 $("#btnContactPost").css('font-weight', 'normal'); 3221 $("#ContactPostForm").trigger("reset"); 3222 } 3223 3224 function recaptchaReviewIncomplete(){ 3225 $("#postReview").prop('disabled', false); 3226 $("#postReview").css('font-weight', 'bold'); 3227 } 3228 3229 function recaptchaReviewComplete(){ 3230 $("#postReview").css('font-weight', 'normal'); 3231 $("#postReviewForm").trigger("reset"); 3232 $("#postReview").prop('disabled', false); 3233 } 3234 3235 function showClassicCaptcha(type) { 3236 if(type === "review"){ 3237 $("#classicCaptchaReview").show(); 3238 } 3239 else{ 3240 $("#classicCaptcha").show(); 3241 } 3242 } 3243 3244 function ClearReviewFields() { 3245 $('#starRating').barrating('clear'); 3246 $("#review").val(""); 3247 $("#review_alias").val(""); 3248 $("#review_heading").val(""); 3249 $("#reviewCaptcha").val(""); 3250 } 3251 3252 function resetReviewButton($button) { 3253 var $buttonText = $button.find('.button-text'); 3254 var $spinner = $button.find('.spinner'); 3255 3256 $button.prop('disabled', false); 3257 3258 if ($buttonText.length && $spinner.length) { 3259 $buttonText.show(); 3260 $spinner.hide(); 3261 } else { 3262 var originalText = $button.data('original-text'); 3263 if (originalText) { 3264 $button.html(originalText); 3265 } 3266 } 3267 } 3268 3269 function setProcessingState($button, $form, isProcessing) { 3270 var $buttonText = $button.find('.button-text'); 3271 var $spinner = $button.find('.spinner'); 3272 3273 if (isProcessing) { 3274 $button.prop('disabled', true); 3275 $form.addClass('review-form-processing'); 3276 $form.find('input, textarea, select').not('#profile_id, #g-Recaptcha-Response-Review, [type="hidden"]').prop('disabled', true); 3277 3278 if ($buttonText.length && $spinner.length) { 3279 $buttonText.hide(); 3280 $spinner.show(); 3281 } else { 3282 $button.data('original-text', $button.html()); 3283 $button.html('<i class="fas fa-spinner fa-spin"></i> Processing...'); 3284 } 3285 } else { 3286 $button.prop('disabled', false); 3287 $form.removeClass('review-form-processing'); 3288 $form.find('input, textarea, select').prop('disabled', false); 3289 3290 if ($buttonText.length && $spinner.length) { 3291 $buttonText.show(); 3292 $spinner.hide(); 3293 } else { 3294 var originalText = $button.data('original-text'); 3295 if (originalText) { 3296 $button.html(originalText); 3297 } 3298 } 3299 } 3300 } 3301 3302 function ClearReviewFields() { 3303 console.log('Clearing review fields'); 3304 $('#starRating').barrating('clear'); 3305 $("#review").val(""); 3306 $("#review_alias").val(""); 3307 $("#review_heading").val(""); 3308 $("#reviewCaptcha").val(""); 3309 3310 $("#postReviewForm input, #postReviewForm textarea").removeClass('error'); 3311 $("#postReviewForm .br-widget").removeClass('error'); 3312 } 3313 3314 function validateReview(btn) { 3315 var $form = $("#postReviewForm"); 3316 var isValid = true; 3317 3318 console.log('Starting validation...'); 3319 3320 $form.find('input, textarea').removeClass('error'); 3321 $form.find('.br-widget').removeClass('error'); 3322 3323 var reviewText = $('#review').val(); 3324 console.log('Review text length:', reviewText ? reviewText.trim().length : 0); 3325 3326 if (!reviewText || reviewText.trim().length === 0) { 3327 console.log('Review text validation failed - empty or whitespace only'); 3328 $('#review').addClass('error'); 3329 $('#review').focus(); 3330 isValid = false; 3331 } else { 3332 console.log('Review text validation passed'); 3333 } 3334 3335 var rating = null; 3336 var selectRating = $('#starRating')[0] ? $('#starRating')[0].value : null; 3337 var jqueryRating = $('#starRating').val(); 3338 var selectedOption = $('#starRating option:selected').val(); 3339 var barRating = null; 3340 3341 if (typeof $('#starRating').barrating === 'function') { 3342 try { 3343 var barResult = $('#starRating').barrating('show'); 3344 if (barResult && typeof barResult === 'string') { 3345 barRating = barResult; 3346 } else if (barResult && typeof barResult === 'number') { 3347 barRating = barResult.toString(); 3348 } 3349 } catch (e) { 3350 console.log('Error getting barrating value:', e); 3351 } 3352 } 3353 3354 if (jqueryRating && typeof jqueryRating === 'string') { 3355 } else if (jqueryRating && typeof jqueryRating === 'number') { 3356 jqueryRating = jqueryRating.toString(); 3357 } else { 3358 jqueryRating = null; 3359 } 3360 3361 if (barRating && barRating !== "" && barRating !== "0") { 3362 rating = barRating; 3363 } else if (selectRating && selectRating !== "" && selectRating !== "0") { 3364 rating = selectRating; 3365 } else if (selectedOption && selectedOption !== "" && selectedOption !== "0") { 3366 rating = selectedOption; 3367 } else if (jqueryRating && jqueryRating !== "" && jqueryRating !== "0") { 3368 rating = jqueryRating; 3369 } 3370 3371 if (rating && typeof rating !== 'string') { 3372 console.log('WARNING: Rating is not a string, converting:', rating, typeof rating);
3373 rating = String(rating); 3374 } 3375 3376 if (rating && typeof rating === 'object') { 3377 console.error('CRITICAL ERROR: Rating is still an object!', rating); 3378 rating = null; 3379 } 3380 3381 console.log('Validation - Final rating value:', rating, typeof rating); 3382 3383 if (!rating || rating === "" || rating === "0") { 3384 console.log('Rating validation failed'); 3385 $('.br-widget').addClass('error'); 3386 isValid = false; 3387 } else { 3388 console.log('Rating validation passed with value:', rating); 3389 } 3390 3391 console.log('Validation result:', isValid); 3392 return isValid; 3393 } 3394 3395 function validateReviewLength() { 3396 var text = $('#review').val(); 3397 var success = true; 3398 3399 if (text.trim().length == 0) { 3400 $('#review').addClass('error'); 3401 success = false; 3402 } 3403 return success; 3404 } 3405 3406 function validateRating() { 3407 var rating = null; 3408 3409 // Use the same rating detection logic 3410 var selectRating = $('#starRating')[0] ? $('#starRating')[0].value : null; 3411 var jqueryRating = $('#starRating').val(); 3412 var selectedOption = $('#starRating option:selected').val(); 3413 var barRating = null; 3414 3415 if (typeof $('#starRating').barrating === 'function') { 3416 try { 3417 barRating = $('#starRating').barrating('show'); 3418 } catch (e) { 3419 console.log('Error getting barrating value in validateRating:', e); 3420 } 3421 } 3422 3423 // Determine which rating to use 3424 if (barRating && barRating !== "" && barRating !== "0") { 3425 rating = barRating; 3426 } else if (selectRating && selectRating !== "" && selectRating !== "0") { 3427 rating = selectRating; 3428 } else if (selectedOption && selectedOption !== "" && selectedOption !== "0") { 3429 rating = selectedOption; 3430 } else if (typeof jqueryRating === 'string' && jqueryRating !== "" && jqueryRating !== "0") { 3431 rating = jqueryRating; 3432 } 3433 3434 var success = true; 3435 if (!rating || rating === "" || rating === "0") { 3436 $('.br-widget').addClass('error'); 3437 success = false; 3438 } 3439 return success; 3440 } 3441</script>
3441 3442</body> 3443</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.