1<!DOCTYPE html> <html lang="en"> <head><meta name="description" content=""> <meta charset="utf-8"> <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="msvalidate.01" content="52D8CD5F9EA2B1031F2D2472023A5D34"> <title>MyPortal | Collections</title> <link rel="preconnect" href="https://www.google.com"> <link rel="preconnect" href="https://www.gstatic.com" crossorigin> <link rel="dns-prefetch" href="https://cdn1.brivityidx.com">
1<script> 2 var head = document.getElementsByTagName('head')[0] 3 var insertBefore = head.insertBefore; 4 head.insertBefore = function (newElement, referenceElement) { 5 // intercept style elements for IEs 6 if (newElement.tagName.toLowerCase() === 'style' 7 && newElement.styleSheet 8 && newElement.styleSheet.cssText 9 && newElement.styleSheet.cssText.replace('\r\n', '').indexOf('.gm-style') === 0) { 10 return; 11 } 12 // intercept style elements for other browsers 13 if (newElement.tagName.toLowerCase() === 'style' 14 && newElement.innerHTML 15 && newElement.innerHTML.replace('\r\n', '').indexOf('.gm-style') === 0) { 16 return; 17 } 18 insertBefore.call(head, newElement, referenceElement); 19 }; 20 </script>
20 <link rel="shortcut icon" href="https://cdn1.brivityidx.com/assets/images/uploads/7586/icon-01.png" type="image/x-icon"> <link href="https://cdn1.brivityidx.com/assets/css/build-site.min.css?ck=" rel="stylesheet"> <link href="https://cdn1.brivityidx.com/assets/css/build-chatbot-v1.min.css?ck=" rel="stylesheet" media="print" onload="this.media='all'"><noscript><link href="https://cdn1.brivityidx.com/assets/css/build-chatbot-v1.min.css?ck=" rel="stylesheet"></noscript> <link rel="canonical" href="https://www.realestateagency.com/myportal/collections">
20<script> 21 function deferScriptOnLoad(url, sleep = 0) { 22 window.addEventListener('load', function () { 23 deferScript(url, sleep); 24 }); 25 } 26 function deferScript(url, sleep = 0) { 27 if (sleep > 0) { 28 setTimeout(() => { 29 deferScript(url); 30 }, sleep); 31 return; 32 } 33 let s = document.createElement('script'); 34 s.type = 'text/javascript'; 35 s.async = true; 36 s.src = url; 37 let x = document.getElementsByTagName('head')[0]; 38 x.appendChild(s); 39 } 40 41 /* PLACE_COMPONENTS_LOADER_START */ 42 window.sitebuilderPlaceComponents = (function () { 43 var DEFAULT_URL = 'https://mobile-component-services-library-dev.brivity.com/web-components.min.js?ck=1'; 44 var BUNDLE_URLS = { default: DEFAULT_URL }; 45 var loadPromises = {}; 46 var LOAD_TIMEOUT_MS = 10000; 47 48 function urlForTag(tagName) { 49 return BUNDLE_URLS[tagName] || BUNDLE_URLS.default; 50 } 51 52 function ensureLoaded(tagName) { 53 var url = urlForTag(tagName); 54 if (loadPromises[url]) { 55 return loadPromises[url]; 56 } 57 loadPromises[url] = new Promise(function (resolve, reject) { 58 var settled = false; 59 var timer = setTimeout(function () { 60 if (settled) return; 61 settled = true; 62 reject(new Error('web-components load timeout')); 63 }, LOAD_TIMEOUT_MS); 64 var s = document.createElement('script'); 65 s.type = 'text/javascript'; 66 s.async = true; 67 s.src = url; 68 s.onerror = function () { 69 if (settled) return; 70 settled = true; 71 clearTimeout(timer); 72 reject(new Error('web-components script onerror')); 73 }; 74 document.getElementsByTagName('head')[0].appendChild(s); 75 if (window.customElements && customElements.whenDefined) { 76 customElements.whenDefined(tagName).then(function () { 77 if (settled) return; 78 settled = true; 79 clearTimeout(timer); 80 resolve(); 81 }); 82 } 83 }); 84 return loadPromises[url]; 85 } 86 87 var EAGER_SELECTOR = 'place-propertycard, place-searchpagefilter, place-bedbathfiltermodal, ' + 88 'place-listingstatusmodal, place-propertytypemodal, place-savesearchmodal, ' + 89 'place-basicmodal, place-details, place-agentbio, place-agentmessaging, ' + 90 'place-contactyouragent, place-menu, place-collectionpopup, ' + 91 'place-copycollectionmodal, place-removecollectionpopup, place-vs-accumulate'; 92 93 function warmIfEagerTagsPresent() { 94 if (document.querySelector(EAGER_SELECTOR)) { 95 ensureLoaded('place-propertycard').catch(function () {}); 96 } 97 } 98 if (document.readyState === 'loading') { 99 document.addEventListener('DOMContentLoaded', warmIfEagerTagsPresent); 100 } else { 101 warmIfEagerTagsPresent(); 102 } 103 104 var INTERACTION_SELECTOR = 'place-getyourhomecta, place-generictoast, ' + EAGER_SELECTOR + 105 ', [data-needs-place-components]'; 106 function onInteract(e) { 107 var t = e.target; 108 if (t && t.closest && t.closest(INTERACTION_SELECTOR)) { 109 ensureLoaded('place-generictoast').catch(function () {}); 110 } 111 } 112 document.addEventListener('pointerdown', onInteract, true); 113 document.addEventListener('focusin', onInteract, true); 114 115 function idleWarm() { 116 ensureLoaded('place-generictoast').catch(function () {}); 117 } 118 if ('requestIdleCallback' in window) { 119 requestIdleCallback(idleWarm, { timeout: 5000 }); 120 } else { 121 setTimeout(idleWarm, 3000); 122 } 123 124 return { ensureLoaded: ensureLoaded }; 125 })(); 126 /* PLACE_COMPONENTS_LOADER_END */ 127 128 const googleApiKey = 'AIzaSyAjpuNg6WGCMV5rzoJcIP2QmMTVto6hYmc' 129 130 /* Lazy loader for Google Maps API + turf.js. 131 * The TURF_INLINE / MAPS_API_INLINE placeholders below are emitted by 132 * Sitemodel.php only on pages whose blocks actually consume Maps/turf. 133 * On other pages those tags are stripped, and consumers call 134 * sitebuilderMapsApi.ensureLoaded() to inject them on demand. 135 * 136 * Safari fix vs. the prior reverted attempt (commit 0cef3135e): uses 137 * Google's official &callback= parameter, not setTimeout, to detect 138 * Maps readiness. 139 */ 140 window.sitebuilderMapsApi = (function () { 141 var TURF_URL = 'https://cdn.jsdelivr.net/npm/@turf/[email protected]/turf.min.js';
142 var MAPS_URL = 'https://maps.googleapis.com/maps/api/js?libraries=geocoding,places,marker,drawing&key=' + 143 googleApiKey + '&map_ids=85c127b7bf0255d9&callback=__sitebuilderMapsReady'; 144 var LOAD_TIMEOUT_MS = 15000; 145 var loadPromise = null; 146 147 function injectScript(url) { 148 var s = document.createElement('script'); 149 s.type = 'text/javascript'; 150 s.async = true; 151 s.src = url; 152 document.getElementsByTagName('head')[0].appendChild(s); 153 return s; 154 } 155 156 function loadTurf() { 157 return new Promise(function (resolve, reject) { 158 if (window.turf) { resolve(); return; } 159 var s = injectScript(TURF_URL); 160 s.onload = function () { resolve(); }; 161 s.onerror = function () { reject(new Error('turf load failed')); }; 162 }); 163 } 164 165 function loadMaps() { 166 return new Promise(function (resolve, reject) { 167 if (window.google && window.google.maps) { resolve(); return; } 168 window.__sitebuilderMapsReady = function () { resolve(); }; 169 var s = injectScript(MAPS_URL); 170 s.onerror = function () { reject(new Error('maps load failed')); }; 171 }); 172 } 173 174 function ensureLoaded() { 175 if (loadPromise) return loadPromise; 176 if (window.google && window.google.maps && window.turf) { 177 loadPromise = Promise.resolve(); 178 return loadPromise; 179 } 180 loadPromise = new Promise(function (resolve, reject) { 181 var settled = false; 182 var timer = setTimeout(function () { 183 if (settled) return; 184 settled = true; 185 reject(new Error('maps/turf load timeout')); 186 }, LOAD_TIMEOUT_MS); 187 Promise.all([loadTurf(), loadMaps()]).then(function () { 188 if (settled) return; 189 settled = true; 190 clearTimeout(timer); 191 resolve(); 192 }, function (err) { 193 if (settled) return; 194 settled = true; 195 clearTimeout(timer); 196 reject(err); 197 }); 198 }); 199 return loadPromise; 200 } 201 202 return { ensureLoaded: ensureLoaded }; 203 })(); 204 </script>
204 <link href="https://cdn1.brivityidx.com/assets/css/style-headers.min.css" rel="stylesheet"><link href="https://cdn1.brivityidx.com/assets/css/style-premium.min.css" rel="stylesheet"><link href="https://cdn1.brivityidx.com/assets/css/library-dd.css" rel="stylesheet"><link href="https://cdn1.brivityidx.com/assets/css/style-footers.css" rel="stylesheet"><link href="https://cdn1.brivityidx.com/idx-sites/9/6/9/9695/site_custom.css?v=1790846336" rel="stylesheet">
204<script type="text/javascript" src="https://cdn1.brivityidx.com/idx-sites/9/6/9/9695/global_js_variables.js?v=1790846336"></script>
204
204<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=!0;j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f)})(window,document,'script','dataLayer','GTM-K2WGMDL')</script>
204
204<script>$(document).ready(function(){$("ul.seo-anchor-links li:nth-of-type(4) a").attr("href","/search")})</script>
204
204<script>function loadScript(a){var b=document.getElementsByTagName("head")[0],c=document.createElement("script");c.type="text/javascript",c.src="https://tracker.metricool.com/resources/be.js",c.onreadystatechange=a,c.onload=a,b.appendChild(c)}loadScript(function(){beTracker.t({hash:"f0ad558c6f6b8ff0fb0bc185cc4ca696"})})</script>
vendor: 64 bytes, line 204
204 <script async src="https://www.googletagmanager.com/gtag/js?id=
204G-SE4W6NGRBJ
vendor: 12 bytes, line 204
204"></script>
204<script> 205
vendor: 134 bytes, lines 205-209
205window.dataLayer = window.dataLayer || []; 206 function gtag(){dataLayer.push(arguments);} 207 gtag('js', new Date()); 208 209 gtag('config', '
209G-SE4W6NGRBJ
vendor: 4 bytes, line 209
209');
210</script>
210
210<script>
vendor: 395 bytes, lines 210-216
210 211!function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod? 212n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n; 213n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0; 214t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window, 215document,'script','https://connect.facebook.net/en_US/fbevents.js'); 216fbq('init', "
216829902774477445
vendor: 30 bytes, lines 216-217
216"); 217fbq('track', 'PageView');
218var propDetailsPixelOnReady = function(){ 219 let propDetFpst = new FbRealEstatePixelTracker({"eventType": "ViewContent", "content_ids": [""]}); 220 propDetFpst.fireEvent(); 221}; 222if (document.readyState === "complete" || (document.readyState !== "loading" && !document.documentElement.doScroll)) { 223 propDetailsPixelOnReady(); 224} else { 225 document.addEventListener("DOMContentLoaded", propDetailsPixelOnReady); 226} 227 228console.log('facebook pixel PageView tracking...'); 229</script>
229 <noscript><img height="1" width="1" style="display:none" src="https://www.facebook.com/tr?id=829902774477445&ev=PageView&noscript=1"></noscript>
229<script>
vendor: 327 bytes, lines 229-233
229(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': 230new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], 231j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= 232'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); 233})(window,document,'script','dataLayer','
233GTM-NQFTPBXT
vendor: 3 bytes, line 233
233');
233</script>
233 <meta property="og:url" content="https://www.realestateagency.com/myportal/collections"> </head> <body>
vendor: 68 bytes, line 233
233 <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=
233GTM-NQFTPBXT
vendor: 83 bytes, line 233
233" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
233<script> 234 window.fbAsyncInit = function() { 235 FB.init({ 236 appId : '1', 237 cookie : true, 238 xfbml : true, 239 version : 'v17.0' 240 }); 241 FB.AppEvents.logPageView(); 242 }; 243 244 setTimeout(() => {(function(d, s, id){ 245 var js, fjs = d.getElementsByTagName(s)[0]; 246 if (d.getElementById(id)) {return;} 247 js = d.createElement(s); js.id = id; 248 js.defer = true; 249 js.xfbml = false; 250 js.src = "//connect.facebook.net/en_US/sdk.js"; 251 fjs.parentNode.insertBefore(js, fjs); 252 }(document, 'script', 'facebook-jssdk'))}, 5000); 253 </script>
253<meta property="fb:app_id" content="1"><meta name="google-signin-client_id" content="1"><meta name="apple-signin-flag" content="1"><meta name="main_sitebuilder_domain" content="https://sitebuilder.brivity.com"> <div id="site-registration-bar" class="collapse"> <input type="hidden" id="huser_id" value=""> <div class="row" style="width: 100%; margin: 0;"> <div class="col-md-12" style="display: none;" id="logged-in"> <div class="topBar flex aiCenter jcBetween"> <div class="topBarLeft flex aiCenter"> <span><topbar_show_agent_name/></span> </div> <div class="topBarRight flex aiCenter"> <a class="topLink flex aiCenter thin favoritesTop" href="/myportal/collections"> <svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg"> <g clip-path="url(#clip0_16761_179132)"> <path d="M14.2659 3.57333C13.9254 3.23267 13.5211 2.96243 13.0761 2.77806C12.6312 2.59368 12.1542 2.49878 11.6726 2.49878C11.1909 2.49878 10.714 2.59368 10.269 2.77806C9.82401 2.96243 9.41973 3.23267 9.07922 3.57333L8.37256 4.28L7.66589 3.57333C6.97809 2.88554 6.04524 2.49914 5.07256 2.49914C4.09987 2.49914 3.16702 2.88554 2.47922 3.57333C1.79143 4.26113 1.40503 5.19398 1.40503 6.16667C1.40503 7.13936 1.79143 8.07221 2.47922 8.76L3.18589 9.46667L8.37256 14.6533L13.5592 9.46667L14.2659 8.76C14.6066 8.4195 14.8768 8.01521 15.0612 7.57024C15.2455 7.12526 15.3404 6.64832 15.3404 6.16667C15.3404 5.68501 15.2455 5.20807 15.0612 4.7631C14.8768 4.31812 14.6066 3.91384 14.2659 3.57333V3.57333Z" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </g> <defs> <clipPath id="clip0_16761_179132"> <rect width="16" height="16" fill="white" transform="translate(0.372559 0.5)"/> </clipPath> </defs> </svg> <span class="ml6 topLabel">Collections </span> </a> <a class="topLink flex aiCenter thin saveSearchTop" href="/myportal/searches"> <svg width="16" height="16" viewBox="0 4 20 17" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M19 21L12 16L5 21V5C5 4.46957 5.21071 3.96086 5.58579 3.58579C5.96086 3.21071 6.46957 3 7 3H17C17.5304 3 18.0391 3.21071 18.4142 3.58579C18.7893 3.96086 19 4.46957 19 5V21Z" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> </svg> <span class="ml6 topLabel">Saved Searches </span> </a> <a class="topLink flex aiCenter thin market-report-top" style="display:none" href="/myportal/reports"> <svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M7.70589 13.1667C10.6514 13.1667 13.0392 10.7789 13.0392 7.83333C13.0392 4.88781 10.6514 2.5 7.70589 2.5C4.76037 2.5 2.37256 4.88781 2.37256 7.83333C2.37256 10.7789 4.76037 13.1667 7.70589 13.1667Z" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M14.3725 14.5L11.4725 11.6" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> <span class="ml6 topLabel">My Reports </span> </a> <a class="aiCenter flex topBarProfile thin" href="/myportal/profile"> <span class="profileName"></span> </a> <a style="padding-right: 0px" class="aiCenter flex thin" id="topBarLogout" href="javascript:void()"> <svg width="23" height="23" viewBox="0 0 23 23" fill="none" xmlns="http://www.w3.org/2000/svg"> <g clip-path="url(#clip0_16761_179186)"> <path d="M16.4003 16.214C19.0038 13.6106 19.0038 9.38945 16.4003 6.78595C13.7968 4.18246 9.57572 4.18246 6.97222 6.78595C4.36873 9.38945 4.36873 13.6105 6.97222 16.214C9.57572 18.8175 13.7968 18.8175 16.4003 16.214Z" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M9.80066 9.61438L13.5719 13.3856" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M9.80066 13.3856L13.5719 9.61438" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </g> <defs> <clipPath id="clip0_16761_179186"> <rect width="16" height="16" fill="white" transform="translate(0.372559 11.5) rotate(-45)"/> </clipPath> </defs> </svg> <span class="ml6">Log Out</span> </a> </div> </div> </div> <div id="not-logged-in"> <topbar_agent_info_not_logged_in/> <ul class="list-unstyled list-inline no-margin"> <li class="topBarSignin"><a href="#" onclick="showGoogleOneTap(true);"><svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-plus-circle mr10"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="16"></line>
253<line x1="8" y1="12" x2="16" y2="12"></line></svg> Sign In</a></li> </ul> </div> </div> </div> <input type="hidden" id="huser_email" value=""> <input type="hidden" id="huser_first_name" value=""> <input type="hidden" id="huser_last_name" value=""> <input type="hidden" id="huser_phone" value=""> <input type="hidden" id="huser_uuid" value=""> <div id="page" class="page"> <header id="premium-navigation" data-selector="#premium-navigation" style=""><div class="main-nav"> <div class="container"> <div class="navbar-header"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse" data-selector="a.btn, button.btn, button" style="outline: none; cursor: inherit;"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="/"> <img class="img-responsive site_custom_logo_dynamic" src="https://cdn1.brivityidx.com/assets/images/uploads/7586/logo-011.png" alt="Realvolution" data-selector="img" style=""></a> </div> <div class="collapse navbar-collapse"> <div> <ul class="nav navbar-nav navbar-right adv-nav"><li class="nav-item" data-selector="li" style=""><a id="top-nav-marketing-plan" class="nav-link-color" data-toggle="modal" data-target="#sell-modal">Get Marketing Plan</a></li></ul></div> <div class="basic-nav render-menu"><ul class="nav navbar-nav navbar-right"><li class="nav-item"><a class="sec-nav-link-color" href="/index">Home</a></li><li class="nav-item"><a class="sec-nav-link-color" href="/search">Search Listings</a></li><li class="nav-item"><a class="sec-nav-link-color" href="/home_value">See home value</a></li><li class="nav-item"><a class="sec-nav-link-color" href="/why_list_with_us">Why List with Us?</a></li><li class="nav-item"><a class="sec-nav-link-color" href="/careers">Careers</a></li><li class="nav-item"><a class="sec-nav-link-color" href="/who_we_are">Who We Are</a></li><li class="nav-item"><a class="sec-nav-link-color" href="/instant_offer">Instant Offer</a></li></ul></div> </div> </div> </div> </header><div class="modal fade magic-modal" id="sell-modal" tabindex="-1" role="dialog" aria-labelledby="sell-modal"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-body"> <button type="button" class="close" data-dismiss="modal" aria-label="Close" data-selector="a.btn, button.btn, button" style="outline: none; cursor: inherit;"><span aria-hidden="true">Ã</span></button> <h4 class="prmry-color" data-selector="h1, h2, h3, h4, h5, h6" style="outline: none; cursor: inherit;">Request property marketing plan</h4> <form class="form-contact" id="form-contact1"> <input type="hidden" name="lead_type" value="seller"><input type="hidden" name="tags" value="Marketing_Plan_Requested"><p data-selector="p" style="outline: none; cursor: inherit;">Youâre one step away from getting a free marketing plan that shows how weâll sell your home for the most amount of money in the least amount of time - hassle free.</p> <div class="row"> <div class="col-sm-6"> <div class="form-group"> <input name="contact1_fname" id="contact1_fname" placeholder="First Name" class="form-control" required="" type="text"></div> </div> <div class="col-sm-6"> <div class="form-group"> <input name="contact1_lname" id="contact1_lname" placeholder="Last Name" class="form-control" required="" type="text"></div> </div> <div class="col-sm-6"> <div class="form-group"> <input name="contact1_email" id="contact1_email" placeholder="Email Address" class="form-control" required="" type="email"></div> </div> <div class="col-sm-6"> <div class="form-group"> <input name="contact1_phone" id="contact1_phone" placeholder="Phone Number" class="form-control" required="" type="tel"></div> </div> <div class="col-sm-12"> <div class="form-group"> <input name="contact1_address" id="contact1_address" placeholder="Address" class="form-control" required="" type="text"></div> </div> <div class="col-sm-6"> <div class="form-group"> <input name="contact1_city" id="contact1_city" placeholder="City" class="form-control" required="" type="text"></div> </div> <div class="col-sm-6"> <div class="form-group"> <input name="contact1_state" id="contact1_state" placeholder="State" class="form-control" required="" type="text"></div> </div> <div class="col-sm-6"> <div class="form-group"> <input name="contact1_zip" id="contact1_zip" placeholder="ZIP"
253class="form-control" required="" type="text"></div> </div> <div class="col-sm-12"> <div class="form-group"> <select name="contact1_whenareyouselling" id="contact1_whenareyouselling" class="form-control" placeholder="When are you planning to sell?"><option value="" disabled selected>When are you planning to sell?</option><option value="1">Now</option><option value="2">0-6 months</option><option value="3">6+ months</option></select></div> </div> </div> <button data-dismiss="modal" class="btn btn-primary" type="submit" id="cf-submit" name="submit" data-selector="a.btn, button.btn, button" style="outline: none; cursor: inherit;">Send</button> <div id="honeypot-div"> <input name="age_required" id="age_required" value="" type="text" style="display: none;"></div></form> </div> </div> </div> </div> <style> 254 255 .center-modal { 256 display:flex; 257 justify-content: center; 258 align-items:center; 259 position:fixed; 260 background-color:rgba(0,0,0,0.4); 261 left:0; 262 top:0; 263 right:0; 264 bottom:0; 265 z-index: 300; 266 } 267 268 .page-width-parent{ 269 max-width: 1280px; 270 margin: 0 auto; 271 } 272 273 274 .property-list-map-view { 275 display:flex; 276 flex-wrap:wrap; 277 gap:16px; 278 } 279 .property-list-map-view-parent { 280 background-color: #F9F9F9; 281 padding:16px; 282 height:710px; 283 overflow:scroll; 284 } 285 286 .property-list-list-view { 287 display:flex; 288 flex-wrap:wrap; 289 gap:24px 290 } 291 292 .property-container { 293 294 gap:24px; 295 } 296 297 .property-map-container { 298 flex:1; 299 height:710px; 300 } 301 302 .property-pagination { 303 margin-top: 26px; 304 } 305 306 .collection-saved-listings { 307 margin-bottom: 26px; 308 font-size:16px; 309 color:black; 310 } 311 312 .collection-description { 313 padding: 20px 0 18px 8px; 314 } 315 316 .my-feed-parent { 317 margin-top:32px; 318 padding-top:32px; 319 border-top: solid 1px #C4C4C4; 320 } 321 322 .collection-description-text { 323 font-size:16px; 324 margin:0; 325 color:black; 326 } 327 328 #collections { 329 display:flex; 330 flex-wrap:wrap; 331 gap:40px 24px; 332 } 333 334 #collection-pagination{ 335 margin-top: 55px 336 } 337 338 #add-listing-btn{ 339 margin-bottom: 20px 340 } 341 342 @media only screen and (min-width: 1280px) { 343 .collection-page { 344 padding:48px 48px 48px 120px; 345 } 346 .my-feed-parent { 347 width:90vw; 348 max-width: 100%; 349 overflow: hidden; 350 } 351 .property-list-map-view-parent { 352 width:500px; 353 } 354 .property-container { 355 display:flex; 356 } 357 } 358 359 @media only screen and (max-width:1280px) { 360 .collection-page { 361 padding:60px 16px 16px 16px; 362 } 363 .my-feed-parent { 364 width: unset; 365 } 366 .property-container { 367 display:flex; 368 flex-direction: column-reverse; 369 } 370 .property-list-map-view { 371 flex-wrap:nowrap; 372 overflow:scroll; 373 height:280px; 374 } 375 .property-list-map-view-parent { 376 height:unset; 377 padding:0px; 378 background-color: #FFFFFF 379 } 380 .property-map-container { 381 flex:none; 382 height:446px; 383 } 384 } 385 386 @media only screen and (max-width:768px) { 387 #collections { 388 justify-content: center; 389 } 390 .property-map-container { 391 width: calc(100% + 32px); 392 margin-left: -16px; 393 } 394 .property-list-map-view { 395 height:250px; 396 } 397 } 398 399</style>
399<script> 400 window.addEventListener("load", () => { 401 const key = localStorage.getItem('authorization'); 402 403 if( !key) { 404 $("#sign-up-modal").modal('show'); 405 406 $("#sign-up-modal").on("hidden.bs.modal", function () { 407 location.reload(); 408 }); 409 } 410 else{ 411 412 let myPortalPage = document.getElementById('myportal-page'); 413 myPortalPage.style.display = "block"; 414 415 window.location.hash = "" 416 417 function isGuid(value) { 418 var regex = /[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}/i; 419 var match = regex.exec(value); 420 return match != null; 421 } 422 423 let lastUrlItem = window.location.href.substring(window.location.href.lastIndexOf('/') + 1) 424 let showCollectionByUUID = false 425 426 if (isGuid(lastUrlItem)) { 427 showCollectionByUUID = true 428 } 429 430 431 class logger extends Collections.BaseLogger { 432 log(e) { 433 console.log(e); 434 } 435 } 436 437 438 class Pubsub { 439 static events = {}; 440 constructor() { 441 //this.events = {}; 442 } 443 444 static subscription (eventName, func) { 445 return { 446 subscribe: () => { 447 if (this.events[eventName]) { 448 this.events[eventName].push(func); 449 } else { 450 this.events[eventName] = [func]; 451 } 452 }, 453 unsubscribe: () => { 454 if(this.events[eventName]){ 455 this.events[eventName] = this.events[eventName].filter((subscriber) => subscriber !== func); 456 } 457 } 458 } 459 } 460 461 static publish(eventName, ...args) { 462 const funcs = this.events[eventName]; 463 if (Array.isArray(funcs)) { 464 funcs.forEach((func) => { 465 func.apply(null, args); 466 }); 467 } 468 } 469 } 470 471 class CollectionCard { 472 constructor(collection, count){ 473 474 this.element = document.createElement(`place-collectioncard`); 475 this.collection = collection 476 let _this = this; 477 let menuOpen = false; 478 var images = []; 479 480 for (let i = 0; i < collection?.propertiesImages?.length; i++) { 481 images.push(collection.propertiesImages[i].mainPhoto); 482 } 483 484 this.element.setAttribute("appearance", "regular"); 485 this.element.setAttribute("image", images); 486 this.element.setAttribute("num_properties", collection?.totalListings ?? 0) 487 this.element.setAttribute("title", collection.collectionName); 488 this.element.setAttribute("description", collection.collectionDescription ? collection.collectionDescription : collection.description ? collection.description : ""); 489 this.element.setAttribute("creator", ""); 490 this.element.setAttribute("disable_dropdown", "false"); 491 this.element.setAttribute("style", "height: 254px"); 492 this.element.setAttribute('z_index', count); 493 this.element.setAttribute("show_menu", "false"); 494 this.element.setAttribute("id", collection.collectionUUID); 495 this.element.setAttribute("container_styles", "w-[300px]"); 496 497 const collectionUUID = collection.collectionUUID; 498 499 this.element.addEventListener(`on_menu_item_pressed`, (e) => { 500 let menuItem = e.detail 501 Pubsub.publish('collection_card_menu_item_pressed', {collection,menuItem}); 502 }); 503 504 this.element.addEventListener('on_search_pressed', (e) => { 505 if (e.target.tagName != "svg" && e.target.tagName != "path") { 506 window.open('../../search.php', '_blank'); 507 e.stopPropagation(); 508 } 509 }); 510 511 this.element.addEventListener(`click`, (e) => { 512 if (e.target.tagName != "svg" && e.target.tagName != "path" && !menuOpen) { 513 Pubsub.publish('collection_card_pressed', {collection:_this.collection,e}); 514 e.stopPropagation(); 515 } 516 }); 517 518 this.element.addEventListener(`on_menu_open`, (e) => { 519 if (this.element.getAttribute("title") === "Favorites") { 520 this.element.setAttribute("disable_menu", "true"); 521 } 522 523 menuOpen = e.detail; 524 this.element.setAttribute("show_menu", menuOpen); 525 }); 526 } 527 } 528 529 class CollectionSection { 530 531 532 collectionSection = document.getElementById('collection-section') 533 collections = document.getElementById('collections') 534 535 addCollectionCard = (collection, count) => { 536 const collectionCard = new CollectionCard(collection, count); 537 538 539 540 541 this.collections.append(collectionCard.element); 542 543 } 544 545 show = () => { 546 this.collectionSection.style.display = 'block' 547 } 548 549 hide = () => { 550 this.collectionSection.style.display = 'none' 551 } 552 } 553 554 class PropertyCard { 555 constructor(collectionUUID,property){ 556 557 let _this = this; 558 this.element = document.createElement(`place-propertycard`); 559 let menuOpen = false;
560 this.property = property; 561 562 this.element.setAttribute("id", property.blossorId) 563 this.element.setAttribute("display_menu", "true"); 564 this.element.setAttribute("show_menu", "false"); 565 this.element.setAttribute("items", '[{"icon":"share-2","text":"Share Property"},{"icon":"layers","text":"Copy to Collection"},{"icon":"trash","text":"Remove from Collection"}]'); 566 567 this.element.setAttribute('appearance','small') 568 this.element.setAttribute('layout_width', '300') 569 this.element.setAttribute('display_tag', 'true') 570 this.element.setAttribute('display_favorite', 'true') 571 this.element.setAttribute('mls',`{ 572 "status":"${property.statusText}", 573 "favorite":"true", 574 "image":[{"uri":"${property?.photos[0]?.url}"}], 575 "price":"${property?.price}", 576 "address":"${property?.address?.street}", 577 "state":"${property?.address?.state}", 578 "city":"${property?.address?.city}", 579 "postalCode":"${property?.address?.zip}", 580 "beds":"${property?.bedrooms}", 581 "baths":"${property?.totalBaths}", 582 "sqft":"${property?.sqFeet}" 583 }`) 584 this.element.setAttribute('on_hover', 'true') 585 586 this.element.addEventListener('mouseenter', (e) => { 587 Pubsub.publish('property_card_mouseenter', property); 588 }) 589 590 this.element.addEventListener('mouseleave', (e) => { 591 Pubsub.publish('property_card_mouseleave', property); 592 }) 593 594 this.element.addEventListener(`on_menu_item_pressed`, (e) => { 595 let menuItem = e.detail 596 let propertyCollectionUUID = property.propertyCollectionUUID 597 let url = this.getPropertyUrl(this.property); 598 property.searchUrl = url; 599 Pubsub.publish('property_card_menu_item_pressed', {property,collectionUUID,propertyCollectionUUID,menuItem, url}); 600 }); 601 602 this.element.addEventListener(`on_menu_open`, (e) => { 603 menuOpen = e.detail; 604 this.element.setAttribute("show_menu", menuOpen); 605 }); 606 607 this.element.addEventListener('click', (e) => { 608 if (e.target.tagName != "svg" && e.target.tagName != "path" && !menuOpen) { 609 let state = _this.property.address.state; 610 let city = _this.slugify(_this.property.address.city); 611 let zip = _this.property.address.zip 612 let address = _this.slugify(_this.property.address.street); 613 let blossorId = _this.property.blossorId; 614 let url = this.getPropertyUrl(property); 615 window.open(`../../${url}`, '_blank'); 616 } 617 }); 618 619 this.element.addEventListener('on_favorite_press', (e) => { 620 let propertyCollectionUUID = property.propertyCollectionUUID; 621 Pubsub.publish('delete_property_modal_pressed', {collectionUUID, propertyCollectionUUID}); 622 }); 623 624 } 625 626 getPropertyUrl = (property) => { 627 let state = property.address.state; 628 let city = this.slugify(property.address.city); 629 let zip = property.address.zip 630 let address = this.slugify(property.address.street); 631 let blossorId = property.blossorId; 632 return `homes-for-sale/${state}/${city}/${zip}/${address}/bid-${blossorId}`; 633 } 634 635 slugify(text) { 636 // replace non letter or digits by - 637 text = text.replace(/[^\pL\d]+~u/g, '_'); 638 // transliterate 639 text = text.normalize('NFKD').replace(/[\u0300-\u036F]/g,'') 640 // remove unwanted characters 641 text = text.replace(/[^_\w]+/g, '_'); 642 // trim 643 text = text.trim(); 644 // remove duplicate - 645 text = text.replace(/_+/g, '-'); 646 // lowercase 647 text = text.toLowerCase(); 648 if (!text) { 649 return 'n-a'; 650 } 651 return text 652 } 653 } 654 655 let dateNow = new Date(); 656 dateNow.setDate(dateNow.getDate()-7); 657 dateNow.setHours(dateNow.getHours()); 658 dateNow.setMinutes(dateNow.getMinutes()); 659 dateNow.setSeconds(dateNow.getSeconds()); 660 const sevenDaysAgo = dateNow.getTime(); 661 662 class PropertySection { 663 propertySection = document.getElementById('property-section') 664 listIcon = document.getElementById('property-list-icon') 665 mapIcon = document.getElementById('property-map-icon') 666 propertyHeader = document.getElementById('property-header') 667 propertyList = document.getElementById("property-list") 668 propertyListParent = document.getElementById("property-list-parent") 669 propertyMap = document.getElementById('property-map') 670 selectedView = 'map' 671 672 collectionProperties = [] 673 674 properties = [] 675 676 677 constructor() { 678 this.listIcon.addEventListener('click', () => { 679 this.setView('list') 680 }) 681 682 this.mapIcon.addEventListener('click', () => { 683 this.setView('map') 684 }) 685 } 686 687 show = (collectionUUID, collectionProperties) => { 688 this.propertySection.style.display = 'block' 689 this.collectionProperties = collectionProperties 690 this.collectionUUID = collectionUUID 691 692 this.propertyList.innerHTML = '' 693 count = 100; 694 695 this.collectionProperties?.data?.properties?.forEach((property) => { 696 count-- 697 this.addPropertyCard(property,collectionUUID, count) 698 }); 699 } 700 701 hide = () => { 702 this.propertySection.style.display = 'none' 703 } 704 705 setPropertyCardWidth = () => { 706 let width; 707 let imageHeight; 708 let windowWidth = window.innerWidth 709 if(this.selectedView == 'map') { 710 if(windowWidth > 1279) { 711 width = `220`; 712 imageHeight = `154`; 713 } else if(windowWidth > 768) { 714 width = `325`; 715 imageHeight = `184`; 716 } else{ 717 width = `244`; 718 imageHeight = `154`; 719 } 720 } 721 else { 722 if(windowWidth > 1440 ){ 723 width = `300`; 724 imageHeight = `184`; 725 } 726 else if(windowWidth > 1279) { 727 width = `260`; 728 imageHeight = `152`; 729 } else if(windowWidth > 768) { 730 width = `218`; 731 imageHeight = `152`; 732 } else{ 733 width = `288`; 734 imageHeight = `184`; 735 } 736 } 737 738 let propertyCards = document.querySelectorAll('place-propertycard') 739 propertyCards.forEach((propertyCard) => { 740 propertyCard.setAttribute('layout_width', width) 741 propertyCard.setAttribute('image_height', imageHeight) 742 }) 743 } 744
745 setView = (view) => { 746 this.selectedView = view 747 if (view == 'list') { 748 this.listIcon.setAttribute('stroke', 'black') 749 this.mapIcon.setAttribute('stroke', 'gray') 750 751 this.propertyMap.style.display = 'none' 752 this.propertyList.classList.add('property-list-list-view') 753 this.propertyList.classList.remove('property-list-map-view') 754 this.propertyListParent.classList.remove('property-list-map-view-parent') 755 756 Pubsub.publish('property_section_show_list_view', this.collectionProperties?.data?.properties); 757 } else { 758 this.listIcon.setAttribute('stroke', 'gray') 759 this.mapIcon.setAttribute('stroke', 'black') 760 761 this.propertyMap.style.display = 'block' 762 this.propertyList.classList.remove('property-list-list-view') 763 this.propertyList.classList.add('property-list-map-view') 764 this.propertyListParent.classList.add('property-list-map-view-parent') 765 766 Pubsub.publish('property_section_show_map_view', this.collectionProperties?.data?.properties); 767 } 768 769 this.setPropertyCardWidth(); 770 } 771 772 scrollIntoView = (id) => { 773 let propertyCard = document.getElementById(id); 774 propertyCard.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'start' }) 775 } 776 777 addPropertyCard = (property, collectionUUID, count) => { 778 779 var propertyCardWrapperElement = document.createElement(`div`) 780 propertyCardWrapperElement.setAttribute('style', `z-index:${count}`) 781 propertyCardWrapperElement.setAttribute('class', 'property-card-wrapper') 782 propertyCardWrapperElement.setAttribute("id", property.propertyCollectionUUID); 783 784 const propertyCard = new PropertyCard(collectionUUID,property); 785 var propertyCardElement = propertyCard.element; 786 787 propertyCardWrapperElement.append(propertyCardElement) 788 789 this.propertyList.append(propertyCardWrapperElement) 790 791 } 792 793 } 794 795 796 class PageSubHeader{ 797 constructor() { 798 799 this.element = document.querySelector('place-pagesubheader') 800 801 this.element.addEventListener('button_on_press', (e) => { 802 Pubsub.publish('create_new_collection_pressed', e) 803 }) 804 805 this.element.addEventListener('top_header_on_press', (e) => { 806 Pubsub.publish('top_header_back_pressed', e) 807 }) 808 809 this.element.addEventListener('on_menu_item_pressed', (e) => { 810 Pubsub.publish('top_header_menu_item_pressed', e.detail) 811 }) 812 813 this.element.addEventListener('secondary_button_on_press', (e) => { 814 window.open('../../search.php', '_blank') 815 }) 816 } 817 818 setTitle(title) { 819 this.element.setAttribute('title', title) 820 } 821 822 setTopHeaderTitle(title){ 823 this.element.setAttribute('top_header_title', title) 824 } 825 826 showTopHeader(){ 827 this.element.setAttribute('show_top_header', true) 828 } 829 830 hideTopHeader(){ 831 this.element.setAttribute('show_top_header', false) 832 } 833 834 showPrimaryButton() { 835 this.element.setAttribute('show_button', true) 836 } 837 838 hidePrimaryButton() { 839 this.element.setAttribute('show_button', false) 840 } 841 842 showSecondaryButton(){ 843 this.element.setAttribute('show_secondary_button', true) 844 } 845 846 hideSecondaryButton(){ 847 this.element.setAttribute('show_secondary_button', false) 848 } 849 850 showMenuButton() { 851 this.element.setAttribute('show_menu_button', true) 852 } 853 854 hideMenuButton() { 855 this.element.setAttribute('show_menu_button', false) 856 } 857 } 858 859 class CollectionModal { 860 861 constructor() { 862 863 let _this = this; 864 this.element = document.querySelector('place-collectionpopup'); 865 this.collectionUUID = 0; 866 867 this.element.addEventListener("on_close_press", (e) => { 868 _this.hide(); 869 }); 870 871 this.element.addEventListener("on_save_press", (e) => { 872 this.showError(false); 873 e.detail.collectionUUID = this.collectionUUID 874 e.detail.type = this.isEditingCollection ? 'edit' : 'save' 875 Pubsub.publish('on_new_collection_saved', e.detail); 876 }); 877 878 } 879 880 setName(name) { 881 this.element.setAttribute('name_value', name) 882 } 883 884 setDescription(description) { 885 this.element.setAttribute('description_value', description ? description : "") 886 } 887 888 showError(error) { 889 this.element.setAttribute('show_error', error) 890 } 891 892 show(collectionUUID, isEditingCollection) { 893 this.isEditingCollection = isEditingCollection; 894 if(collectionUUID){ 895 this.collectionUUID = collectionUUID; 896 } 897 this.element.setAttribute('style', 'display:flex') 898 } 899 900 hide() { 901 this.element.setAttribute('style', 'display:none'); 902 903 this.showError(false) 904 905 // terrible hack.. only way i could get it to respond to prop changes 906 // to clear the input fields after closing the modal 907 this.setName('none') 908 this.setDescription('none') 909 setTimeout(() => { 910 this.setName('') 911 this.setDescription('') 912 }, 100); 913 } 914 } 915 916 class CollectionCreatedModal { 917 constructor() { 918 919 920 this.collection = "" 921 this.element = document.getElementById('collection-created-modal'); 922 let _this = this; 923 924 this.element.addEventListener("on_primary_press", (e) => { 925 this.hide(); 926 window.location.href = '../../search.php' 927 }); 928 929 this.element.addEventListener("on_tertiary_press", (e) => { 930 _this.hide(); 931 Pubsub.publish('collection_created_modal_view_collection_pressed', _this.collection); 932 }); 933 934 this.element.addEventListener("on_close_press", (e) => { 935 _this.hide(); 936 }); 937 938 this.element.setAttribute("stacked_buttons", true) 939 this.element.setAttribute("primary_button_text", "Search Listings") 940 this.element.setAttribute("tertiary_button_text", "View Collection") 941 } 942 943 show(collection) { 944 if(collection){ 945 this.collection = collection; 946 } 947 this.element.setAttribute('style', 'display:flex') 948 } 949 950 hide() { 951 this.element.setAttribute('style', 'display:none'); 952 } 953 } 954 955 class EditCollectionModal { 956 constructor() { 957 958 959 this.collection = "" 960 this.element = document.getElementById('edit-collection-modal'); 961 let _this = this; 962 963 this.element.addEventListener("on_primary_press", (e) => { 964 _this.hide(); 965 966 }); 967 968 969 970 this.element.addEventListener("on_close_press", (e) => { 971 _this.hide(); 972 }); 973 } 974 975 show() { 976 977 this.element.setAttribute('style', 'display:flex') 978 } 979 980 hide() { 981 this.element.setAttribute('style', 'display:none'); 982 } 983 } 984 985 class DeleteCollectionModal { 986 constructor() { 987 988 989 this.collection = "" 990 this.element = document.getElementById('delete-collection-modal'); 991 let _this = this; 992 993 this.element.addEventListener("on_primary_press", (e) => { 994 _this.hide(); 995 Pubsub.publish('delete_collection_modal_delete_pressed', _this.collection); 996 }); 997 998 this.element.addEventListener("on_tertiary_press", (e) => { 999 this.hide(); 1000 }); 1001 1002 this.element.addEventListener("on_close_press", (e) => { 1003 _this.hide(); 1004 }); 1005 } 1006 1007 show(collection) { 1008 if(collection){ 1009 this.collection = collection; 1010 } 1011 this.element.setAttribute('style', 'display:flex') 1012 } 1013 1014 hide() { 1015 this.element.setAttribute('style', 'display:none'); 1016 } 1017 } 1018 1019 class ShareSavedPropertyModal { 1020 constructor() { 1021 let _this = this; 1022 this.savedProperty = {} 1023 this.element = document.getElementById('share-saved-property-modal'); 1024 1025 this.element.addEventListener("on_primary_press", (e) => { 1026 1027 1028 1029 navigator.clipboard.writeText(this.link) 1030 _this.hide(); 1031 Pubsub.publish('share_saved_property_modal_share_pressed'); 1032 1033 }); 1034 1035 this.element.addEventListener("on_close_press", (e) => { 1036 _this.hide(); 1037 }); 1038 } 1039 1040 show = (savedProperty) => { 1041 1042 1043 this.savedProperty = savedProperty; 1044 1045 this.link = document.location.origin + "/" + this.savedProperty.searchUrl 1046 this.element.setAttribute('share_link_text', this.link) 1047 this.element.setAttribute('style', 'display:flex') 1048 } 1049 1050 hide = () => { 1051 this.element.setAttribute('style', 'display:none'); 1052 } 1053 } 1054 1055 class DeletePropertyModal { 1056 constructor() { 1057 1058 1059 this.collectionUUID = "" 1060 this.propertyCollectionUUID = "" 1061 this.element = document.getElementById('delete-property-modal'); 1062 let _this = this; 1063 1064 this.element.addEventListener("on_primary_press", (e) => { 1065 _this.hide(); 1066 Pubsub.publish('delete_property_modal_delete_pressed', {"collectionUUID":_this.collectionUUID, "propertyCollectionUUID":_this.propertyCollectionUUID}); 1067 }); 1068 1069 this.element.addEventListener("on_tertiary_press", (e) => { 1070 this.hide(); 1071 }); 1072 1073 this.element.addEventListener("on_close_press", (e) => { 1074 _this.hide(); 1075 }); 1076 } 1077 1078 show(collectionUUID, propertyCollectionUUID) { 1079 if(collectionUUID){ 1080 this.collectionUUID = collectionUUID; 1081 } 1082 if(propertyCollectionUUID){ 1083 this.propertyCollectionUUID = propertyCollectionUUID; 1084 } 1085 this.element.setAttribute('style', 'display:flex') 1086 } 1087 1088 hide() { 1089 this.element.setAttribute('style', 'display:none'); 1090 } 1091 } 1092 1093 class CopyPropertyToCollectionModal { 1094 constructor(){ 1095 1096 this.element = document.querySelector('place-copycollectionmodal'); 1097 this.collections = []; 1098 this.property = {} 1099 this.isVisible = false;
1100 1101 1102 1103 this.element.addEventListener('close_button', (e) => { 1104 this.hide(); 1105 }); 1106 1107 this.element.addEventListener('cancel_button', (e) => { 1108 this.hide(); 1109 }); 1110 1111 this.element.addEventListener('on_save', (e) => { 1112 Pubsub.publish('copy_property_to_collection_modal_save_pressed', {'collectionUUID':e.detail, 'property':this.property}); 1113 }); 1114 1115 this.element.addEventListener('set_selected_collection', (e) => { 1116 console.log('set_selected_collection', e) 1117 }); 1118 1119 this.element.addEventListener('on_link_press', (e) => { 1120 Pubsub.publish('show_new_collection_modal'); 1121 }); 1122 1123 } 1124 1125 getCollectionData(){ 1126 return JSON.parse(this.element.getAttribute("collections")); 1127 } 1128 1129 setCollectionData(collections){ 1130 this.element.setAttribute('collections', JSON.stringify(collections)) 1131 } 1132 1133 getCollectionList(collections, currentCollectionName) { 1134 let collectionList = []; 1135 collections.forEach(collection => { 1136 if (currentCollectionName && (collection.collectionName == currentCollectionName)) return; 1137 collectionList.push({ 1138 collection_title: collection.collectionName, 1139 id: collection.collectionUUID, 1140 propertiesImages: collection?.propertiesImages?.length > 0 ? collection?.propertiesImages : [], 1141 }) 1142 }); 1143 this.setCollectionData(collectionList); 1144 1145 } 1146 1147 setIsAddingToCollection(isAddingToCollection){ 1148 this.element.setAttribute('is_add_to_collection', isAddingToCollection); 1149 } 1150 1151 show(property) { 1152 1153 if(property){ 1154 this.property = property; 1155 } 1156 1157 this.isVisible = true; 1158 1159 let mls = { 1160 status: property?.status || property?.standardStatus || "", 1161 image: this.getPropertyImageUrl(property), 1162 price: property?.price || "0", 1163 address: ( typeof property?.address === "string") ? property?.address : (property?.address?.street || property?.streetAddress || ""), 1164 state: property?.state || property?.address?.state || "", 1165 city: property?.city || property?.address?.city || "", 1166 postal_code: property?.postal_code || property?.address?.zip || "", 1167 beds: property?.beds || property?.bedrooms || 0, 1168 baths: property?.baths || property?.fullBaths || property?.bathsTotalDecimal || 0, 1169 sqft: property?.sqft || property?.squareFeet || property?.sqFeet || 0, 1170 creator: property?.creator || "", 1171 } 1172 1173 this.element.setAttribute('mls', JSON.stringify(mls)) 1174 this.element.setAttribute('image_url',mls?.image || "") 1175 this.element.setAttribute('style', 'display:flex') 1176 } 1177 1178 getPropertyImageUrl(property){ 1179 // property?.image[0]?.uri || property?.photos[0]?.url || "", 1180 1181 if(property.image && property.image.length > 0){ 1182 return property.image[0].uri 1183 } else if (property.photos && property.photos.length > 0){ 1184 return property.photos[0].url 1185 } else { 1186 return "" 1187 } 1188 } 1189 1190 hide() { 1191 this.isVisible = false;
1192 this.element.setAttribute('style', 'display:none'); 1193 } 1194 } 1195 1196 class CollectionPaging { 1197 constructor(collectionsPerPage){ 1198 1199 1200 this.element = document.getElementById('collection-pagination'); 1201 this.collectionsPerPage = collectionsPerPage; 1202 1203 this.element.addEventListener('page_changed', (e) => { 1204 Pubsub.publish('collection_page_changed', e.detail); 1205 }); 1206 } 1207 1208 setPageCount(pageCount){ 1209 this.element.setAttribute('page_count', pageCount); 1210 } 1211 1212 show() { 1213 this.element.setAttribute('style', 'display:flex') 1214 } 1215 1216 hide() { 1217 this.element.setAttribute('style', 'display:none') 1218 } 1219 } 1220 1221 class PropertyPaging { 1222 constructor(propertiesPerPage){ 1223 1224 1225 this.element = document.getElementById('property-pagination'); 1226 this.propertiesPerPage = propertiesPerPage; 1227 1228 this.element.addEventListener('page_changed', (e) => { 1229 Pubsub.publish('property_page_changed', e.detail); 1230 }); 1231 } 1232 1233 setPageCount(pageCount){ 1234 this.element.setAttribute('page_count', pageCount); 1235 } 1236 1237 setCurrentPage(currentPage){ 1238 this.element.setAttribute('current_page', currentPage); 1239 } 1240 1241 show() { 1242 this.element.setAttribute('style', 'display:flex') 1243 } 1244 1245 hide() { 1246 this.element.setAttribute('style', 'display:none') 1247 } 1248 } 1249 1250 class NewCollectionBlock { 1251 constructor(){ 1252 1253 this.element = document.getElementById('new-collection-block'); 1254 1255 this.element.addEventListener('on_main_press', (e) => { 1256 Pubsub.publish('new_collection_block_create_collection_pressed', e.detail); 1257 }); 1258 } 1259 show(collectionUUID, propertyCollectionUUID) { 1260 this.element.setAttribute('style', 'display:flex') 1261 } 1262 1263 hide() { 1264 this.element.setAttribute('style', 'display:none'); 1265 } 1266 } 1267 1268 class AddListingsBlock { 1269 constructor() { 1270 1271 this.element = document.getElementById('add-listings-block'); 1272 1273 this.element.addEventListener('on_main_press', (e) => { 1274 window.open('../../search.php', '_blank') 1275 }); 1276 1277 this.element.addEventListener("on_tertiary_press", (e) => { 1278 1279 }); 1280 } 1281 1282 show() { 1283 this.element.setAttribute('style', 'display:flex') 1284 } 1285 1286 hide() { 1287 this.element.setAttribute('style', 'display:none'); 1288 } 1289 } 1290 1291 class MyFeed { 1292 constructor(blueroofMiddlewareApi, collectionsService) { 1293 this.blueroofMiddlewareApi = blueroofMiddlewareApi; 1294 this.collectionsService = collectionsService; 1295 this.element = document.querySelector('place-myfeedblock'); 1296 1297 this.element.addEventListener('on_menu_open', (e) => { 1298 this.element.setAttribute('show_menu', e.detail.e); 1299 this.element.setAttribute('show_menu_index', e.detail.index); 1300 }); 1301 1302 this.element.addEventListener('on_view_all_pressed', (e) => { 1303 window.open('../../search.php', '_blank'); 1304 }); 1305 1306 this.element.addEventListener('on_add_collection', (e) => { 1307 1308 let property = e.detail; 1309 Pubsub.publish('my_feed_add_collection_pressed', {property}); 1310 1311 }); 1312 1313 this.element.addEventListener('on_share_pressed', (e) => { 1314 1315 let property = e.detail 1316 1317 let url = this.getPropertyUrl(property); 1318 property.searchUrl = url; 1319 1320 Pubsub.publish('my_feed_share_pressed', {property}); 1321 }); 1322 1323 this.element.addEventListener('on_favorite_pressed', (e) => { 1324 let property = e.detail.property; 1325 let isAddingFavorite = e.detail.isAddingFavorite; 1326 1327 if(isAddingFavorite){ 1328 Pubsub.publish('my_feed_on_favorite_pressed', {property}); 1329 } 1330 else{ 1331 Pubsub.publish('my_feed_on_unfavorite_pressed', {property}); 1332 } 1333 }); 1334 1335 this.element.addEventListener('on_property_pressed', (e) => { 1336 let property = e.detail 1337 1338 let url = this.getPropertyUrl(property); 1339 property.searchUrl = url; 1340 window.open('../../' + url, '_blank'); 1341 }); 1342 1343 1344 this.blueroofMiddlewareApi.getMyFeed().then((data) => { 1345 1346 let myFeedBlossorIds = data.map(property => property.blossorId); 1347 1348 1349 this.collectionsService.checkIfInCollection(myFeedBlossorIds).then((propertiesInCollections) => { 1350 1351 let feed = [] 1352 data.forEach((item) => { 1353 feed.push({ 1354 image: [ 1355 { 1356 title: "", 1357 id: 0, 1358 uri: item?.photos[0].url, 1359 }, 1360 ], 1361 price: item?.price, 1362 favorite: propertiesInCollections?.data[item?.blossorId] != null || false, 1363 address: item?.streetAddress, 1364 city: item?.city, 1365 state: item?.state, 1366 postal_code: item?.postalCode, 1367 beds: item?.bedrooms, 1368 status: item?.standardStatus, 1369 baths: item?.bathsTotalDecimal, 1370 sqft: item?.squareFeet, 1371 creator: "", 1372 mls_price_history: item?.history[item.history.length-1]?.price, 1373 blossorId: item?.blossorId, 1374 open_house : item?.openhouses?.length > 0 ? true : false, 1375 open_house_date : item?.openhouses[0]?.startDate, 1376 open_house_end_time : item?.openhouses[0]?.endDate, 1377 property_created_at : item?.listDate, 1378 lastStatusChangeDate : item?.lastStatusChangeDate, 1379 }) 1380 }) 1381 1382 if(feed && feed?.length > 0){ 1383 this.show(); 1384 this.element.setAttribute('mls_data', JSON.stringify(feed)); 1385 } 1386 }); 1387 }); 1388 1389 } 1390 1391 getPropertyUrl = (property) => { 1392 let state = property.state; 1393 let city = this.slugify(property.city); 1394 let zip = property.postal_code 1395 let address = this.slugify(property.address); 1396 let blossorId = property.blossorId; 1397 return `homes-for-sale/${state}/${city}/${zip}/${address}/bid-${blossorId}`; 1398 } 1399 1400 slugify(text) { 1401 // replace non letter or digits by - 1402 text = text.replace(/[^\pL\d]+~u/g, '_'); 1403 // transliterate 1404 text = text.normalize('NFKD').replace(/[\u0300-\u036F]/g,'') 1405 // remove unwanted characters 1406 text = text.replace(/[^_\w]+/g, '_'); 1407 // trim 1408 text = text.trim(); 1409 // remove duplicate - 1410 text = text.replace(/_+/g, '-'); 1411 // lowercase 1412 text = text.toLowerCase(); 1413 if (!text) { 1414 return 'n-a'; 1415 } 1416 return text 1417 } 1418 1419 getMlsData = () => { 1420 return JSON.parse(this.element.getAttribute('mls_data')); 1421 } 1422 1423 setMlsData = (data) => { 1424 this.element.setAttribute('mls_data', JSON.stringify(data)); 1425 } 1426 1427 show() { 1428 this.element.setAttribute('style', 'display:flex') 1429 } 1430 1431 hide() { 1432 this.element.setAttribute('style', 'display:none') 1433 } 1434 } 1435 1436 class BlueroofMiddlewareApi { 1437 constructor() { 1438 this.baseUrl = "https://brivity-home-middleware.production.brivity.com"; 1439 this.apiKey = localStorage.getItem('authorization'); 1440 } 1441 1442 getMyFeed = async () => { 1443 const response = await fetch(`${this.baseUrl}/listings/voltron`, { 1444 method: 'POST', 1445 headers: { 1446 'Content-Type': 'application/json', 1447 'Authorization': `${this.apiKey}` 1448 }, 1449 body: JSON.stringify([]) 1450 }); 1451 1452 const data = await response.json(); 1453 return data; 1454 } 1455 1456 getLeadBasicInfo = async () => { 1457 const response = await fetch(`${this.baseUrl}/blueroofleads/basicinfo`, { 1458 method: 'GET', 1459 headers: { 1460 'Content-Type': 'application/json', 1461 'Authorization': `${this.apiKey}` 1462 }, 1463 1464 }); 1465 1466 const data = await response.json(); 1467 return data; 1468 } 1469 1470 getAgentProfile = async (brivityUserId) => { 1471 const response = await fetch(`${this.baseUrl}/blueroofagents/profile`, { 1472 method: 'POST', 1473 headers: { 1474 'Content-Type': 'application/json', 1475 'Authorization': `${this.apiKey}` 1476 }, 1477 body: `{"brivityUserId": ${brivityUserId}}` 1478 1479 }); 1480 1481 const data = await response.json(); 1482 return data; 1483 } 1484 1485 } 1486 1487 class Map { 1488 constructor(){ 1489 this.element = document.querySelector('place-map'); 1490 this.properties = []; 1491 1492 this.element.addEventListener('on_marker_clicked', (e) => { 1493 Pubsub.publish('map_marker_clicked', e.detail.id) 1494 }); 1495 } 1496 1497 setMarkers = (properties) => { 1498 let markers = []; 1499 let color = 'black' 1500 1501 let dateNow = new Date(); 1502 dateNow.setDate(dateNow.getDate()-7); 1503 dateNow.setHours(dateNow.getHours()); 1504 dateNow.setMinutes(dateNow.getMinutes()); 1505 dateNow.setSeconds(dateNow.getSeconds()); 1506 const sevenDaysAgo = dateNow.getTime(); 1507 1508 this.properties = properties; 1509 properties?.forEach(property => { 1510 1511 if(property.statusText == 'Active'){ 1512 color = '#1FA6E8' 1513 }else if(property.statusText == 'Pending'){ 1514 color = '#FFC82C' 1515 }else if(property.statusText == 'Sold'){ 1516 color = '#FF7343' 1517 } 1518 1519 let listDate = new Date(property.listDate); 1520 1521 1522 if(listDate.getTime() > sevenDaysAgo){ 1523 color = '#24D0BC' 1524 } 1525 1526 markers.push({ 1527 id: `${property.blossorId}`, 1528 location: property.location, 1529 price: property.price, 1530 color : color 1531 }) 1532 }); 1533 1534 this.element.setAttribute('markers', JSON.stringify(markers)); 1535 } 1536 1537 setSelectedMarker = (property) => { 1538 let markerIndex = this.properties.findIndex((p) => p.blossorId == property.blossorId) 1539 if(markerIndex > -1){ 1540 this.element.setAttribute('selected_property_index', markerIndex); 1541 } 1542 } 1543 1544 clearSelectedMarker = () => { 1545 this.element.setAttribute('selected_property_index', -1); 1546 } 1547 1548 } 1549 1550 class SavedListings { 1551 constructor(){ 1552 this.element = document.getElementById('collection-saved-listings'); 1553 } 1554 1555 setCount(count) { 1556 this.element.innerText = `Saved Listings (${count})`; 1557 } 1558 1559 hide() { 1560 this.element.style.display = `none`; 1561 } 1562 show() { 1563 this.element.style.display = `block`; 1564 } 1565 } 1566 1567 class AddListingBtn { 1568 constructor(){ 1569 this.element = document.getElementById('add-listing-btn'); 1570 this.element.setAttribute('button_style', JSON.stringify({paddingLeft: '0px'})); 1571 this.element.addEventListener('on_press', (e) => { 1572 window.open('../../search.php', '_blank') 1573 }) 1574 } 1575 1576 hide() { 1577 this.element.style.display = `none`; 1578 } 1579 show() { 1580 this.element.style.display = `block`; 1581 } 1582 } 1583 1584 class Page { 1585 constructor(blueroofMiddlewareApi) { 1586 this.selectedCollection = {}; 1587 this.inPropertyView = false;
1588 this.lead = {} 1589 this.agent = {} 1590 this.isInMapView = false; 1591 this.isInListView = true; 1592 1593 this.authorizationData = JSON.parse(atob(blueroofMiddlewareApi.apiKey.split('.')[1])); 1594 this.is_blueroof_person = this.authorizationData?.is_blueroof_person; 1595 1596 1597 } 1598 1599 setSelectedCollection(collection) { 1600 this.selectedCollection = collection; 1601 } 1602 1603 setInPropertyView(inPropertyView) { 1604 this.inPropertyView = inPropertyView; 1605 } 1606 } 1607 1608 1609 class messagingEmitter extends Messaging.BaseEmitter { 1610 1611 newMessage(message) { 1612 Pubsub.publish('messaging_emitter_new_message', message); 1613 } 1614 } 1615 1616 1617 1618 (async () => { 1619 1620 const blueroofMiddlewareApi = new BlueroofMiddlewareApi(); 1621 const page = new Page(blueroofMiddlewareApi); 1622 1623 let url = 'https://messaging.brivity.com' 1624 const messaging = new Messaging.Service(url, blueroofMiddlewareApi.apiKey, new messagingEmitter()); 1625 1626 let lead = await blueroofMiddlewareApi.getLeadBasicInfo(); 1627 let agent = await blueroofMiddlewareApi.getAgentProfile(lead.data?.brivity_agent_id); 1628 1629 page.lead = lead.data; 1630 page.agent = agent.data; 1631 1632 const collectionsService = new Collections.Service(window?.globalSiteVariables?.options?.apis?.collections?.url ?? '',blueroofMiddlewareApi.apiKey, "sitebuilder", new logger()); 1633 1634 1635 const menu = new Menu(page?.is_blueroof_person || false, page?.agent, blueroofMiddlewareApi.baseUrl, blueroofMiddlewareApi.apiKey); 1636 const collectionSection = new CollectionSection() 1637 const propertySection = new PropertySection() 1638 const collectionModal = new CollectionModal(); 1639 const collectionCreatedModal = new CollectionCreatedModal(); 1640 const deleteCollectionModal = new DeleteCollectionModal();
1641 const editCollectionModal = new EditCollectionModal(); 1642 const shareSavedPropertyModal = new ShareSavedPropertyModal(); 1643 const deletePropertyModal = new DeletePropertyModal(); 1644 const copyPropertyToCollectionModal = new CopyPropertyToCollectionModal(); 1645 const pageSubHeader = new PageSubHeader(); 1646 const collectionPaging = new CollectionPaging(8) 1647 const propertyPaging = new PropertyPaging(8) 1648 const newCollectionBlock = new NewCollectionBlock(); 1649 const addListingsBlock = new AddListingsBlock(); 1650 const myFeed = new MyFeed(blueroofMiddlewareApi, collectionsService); 1651 const map = new Map(); 1652 const savedListings = new SavedListings(); 1653 const addListingBtn = new AddListingBtn(); 1654 1655 collectionPaging.hide(); 1656 propertySection.hide(); 1657 1658 let collections = []; 1659 let extraCollections = 0; 1660 let createCopyCollection = false; 1661 1662 if(!showCollectionByUUID){ 1663 const collectionDescription = document.getElementById("collectionDescription"); 1664 1665 collectionsService.getCollections(0, collectionPaging.collectionsPerPage).then((e) => { 1666 1667 extraCollections = e?.data?.totalCollections 1668 1669 if(e.data.TotalPages > 1) { 1670 collectionPaging.show() 1671 collectionPaging.setPageCount(e.data.TotalPages); 1672 } else { 1673 collectionPaging.setPageCount(1); 1674 } 1675 1676 1677 if(e?.data?.Items){ 1678 collections = e.data.Items; 1679 count = 100; 1680 e.data.Items.forEach((collection) => { 1681 count-- 1682 1683 collectionSection.addCollectionCard(collection, count) 1684 }); 1685 } 1686 1687 copyPropertyToCollectionModal.getCollectionList(collections) 1688 1689 if(collections.length == 0){ 1690 newCollectionBlock.show(); 1691 } 1692 1693 }).catch((e) => { 1694 if(collections.length == 0){ 1695 newCollectionBlock.show(); 1696 } 1697 }); 1698 } 1699 else{ 1700 collectionsService.getCollections(0, collectionPaging.collectionsPerPage).then((e) => { 1701 1702 if(e?.data?.Items){ 1703 collections = e.data.Items; 1704 } 1705 1706 }); 1707 } 1708 1709 Pubsub.subscription('property_card_mouseenter', (property) => { 1710 1711 document.querySelectorAll('place-propertycard').forEach((propertyCard) => { 1712 propertyCard.setAttribute('show_border', false); 1713 }) 1714 1715 if(page.isInMapView){ 1716 map.setSelectedMarker(property) 1717 } 1718 }).subscribe(); 1719 1720 Pubsub.subscription('property_card_mouseleave', () => { 1721 if(page.isInMapView){ 1722 map.clearSelectedMarker() 1723 } 1724 }).subscribe(); 1725 1726 Pubsub.subscription('messaging_emitter_new_message', (message) => { 1727 toast.show('New message from ' + message.createdByAlias) 1728 }).subscribe(); 1729 1730 Pubsub.subscription('property_section_show_map_view', (properties) => { 1731 map.setMarkers(properties); 1732 page.isInMapView = true; 1733 page.isInListView = false; 1734 1735 document.querySelectorAll('place-propertycard').forEach((propertyCard) => { 1736 propertyCard.setAttribute('show_border_on_hover', true); 1737 }) 1738 }).subscribe(); 1739 1740 Pubsub.subscription('property_section_show_list_view', (properties) => { 1741 page.isInMapView = false;
1742 page.isInListView = true; 1743 1744 document.querySelectorAll('place-propertycard').forEach((propertyCard) => { 1745 propertyCard.setAttribute('show_border_on_hover', false); 1746 }) 1747 1748 }).subscribe(); 1749 1750 Pubsub.subscription('property_page_changed', (page) => { 1751 collectionsService.getCollectionProperties(propertySection.collectionUUID, page, propertyPaging.propertiesPerPage).then((collectionProperties) => { 1752 map.setMarkers(collectionProperties?.data?.properties); 1753 savedListings.setCount(collectionProperties?.data?.totalListings || 0); 1754 propertySection.show(propertySection.collectionUUID,collectionProperties) 1755 propertySection.setPropertyCardWidth(); 1756 propertyPaging.setCurrentPage(page); 1757 }); 1758 }).subscribe(); 1759 1760 Pubsub.subscription("top_header_menu_item_pressed", (menuItemPressed) => { 1761 1762 if(menuItemPressed == 'Edit Collection'){ 1763 collectionModal.setName(page.selectedCollection.collectionName); 1764 collectionModal.setDescription(page.selectedCollection.collectionDescription); 1765 collectionModal.show(page.selectedCollection.collectionUUID, true); 1766 } 1767 else if(menuItemPressed == 'Delete Collection'){ 1768 deleteCollectionModal.show(page.selectedCollection); 1769 } 1770 }).subscribe(); 1771 1772 Pubsub.subscription('new_collection_block_create_collection_pressed', (e) => { 1773 collectionModal.show(0, false); 1774 }).subscribe(); 1775 1776 Pubsub.subscription('collection_card_pressed', (e) => { 1777 1778 window.location.hash = e.collection.collectionUUID; 1779 1780 page.setSelectedCollection(e.collection); 1781 1782 collectionsService.getCollectionProperties(e.collection.collectionUUID,1, propertyPaging.propertiesPerPage).then((collectionProperties) => { 1783 1784 1785 savedListings.setCount(collectionProperties?.data?.totalListings || 0); 1786 propertyPaging.setPageCount(collectionProperties.data.totalPages); 1787 1788 1789 if(collectionProperties?.data?.properties == null){ 1790 addListingsBlock.show(); 1791 } 1792 propertySection.show(e.collection.collectionUUID,collectionProperties) 1793 propertySection.setPropertyCardWidth(); 1794 1795 if(collectionProperties.data.totalPages > 1){ 1796 propertyPaging.show(); 1797 } 1798 1799 }); 1800 1801 1802 collectionSection.hide(); 1803 1804 let collectionList = []; 1805 1806 collections.forEach(collection => { 1807 if (collection.collectionName == e.collection.collectionName) return; 1808 1809 collectionList.push({ 1810 collection_title: collection.collectionName, 1811 id: collection.collectionUUID, 1812 propertiesImages: collection?.propertiesImages?.length > 0 ? collection?.propertiesImages : [], 1813 }) 1814 }); 1815 1816 copyPropertyToCollectionModal.getCollectionList(collections, e.collection.collectionName); 1817 1818 pageSubHeader.showTopHeader(); 1819 pageSubHeader.setTopHeaderTitle("Collections"); 1820 pageSubHeader.setTitle(e.collection.collectionName); 1821 pageSubHeader.hidePrimaryButton(); 1822 pageSubHeader.showMenuButton(); 1823 1824 if(window.innerWidth > 768 ){ 1825 pageSubHeader.showSecondaryButton(); 1826 } 1827 1828 page.setInPropertyView(true) 1829 1830 propertyPaging.setCurrentPage(1); 1831 propertySection.setView('list') 1832 1833 1834 const collectionDescription = document.getElementById('collection-description') 1835 collectionDescription.style.display="flex" 1836 collectionDescription.children[0].innerText = e?.collection.collectionDescription || "" 1837 }).subscribe(); 1838 1839 Pubsub.subscription('collection_card_menu_item_pressed', (e) => { 1840 if (e.menuItem == "Delete Collection") { 1841 1842 deleteCollectionModal.show(e.collection); 1843 1844 } else { 1845 1846 1847 collectionModal.setName(e.collection.collectionName); 1848 collectionModal.setDescription(e.collection.collectionDescription); 1849 collectionModal.show(e.collection.collectionUUID, true); 1850 } 1851 }).subscribe(); 1852 1853 Pubsub.subscription('property_card_menu_item_pressed', (e) => { 1854 if(e.menuItem == 'Remove from Collection') { 1855 deletePropertyModal.show(e.collectionUUID, e.propertyCollectionUUID); 1856 } 1857 else if(e.menuItem == 'Copy to Collection') { 1858 copyPropertyToCollectionModal.show(e.property); 1859 } 1860 else if(e.menuItem == 'Share Property') { 1861 1862 shareSavedPropertyModal.show(e.property); 1863 } 1864 }).subscribe(); 1865 1866 Pubsub.subscription('delete_property_modal_pressed', (e) => { 1867 deletePropertyModal.show(e.collectionUUID, e.propertyCollectionUUID); 1868 }).subscribe(); 1869 1870 Pubsub.subscription('show_new_collection_modal', (e) => { 1871 collectionModal.show(); 1872 copyPropertyToCollectionModal.hide(); 1873 createCopyCollection = true; 1874 }).subscribe(); 1875 1876 Pubsub.subscription('top_header_back_pressed', () => { 1877 window.location.hash = ''; 1878 pageSubHeader.hideTopHeader(); 1879 page.selectedCollection = {}; 1880 pageSubHeader.setTitle("COLLECTIONS"); 1881 pageSubHeader.showPrimaryButton(); 1882 pageSubHeader.hideSecondaryButton(); 1883 pageSubHeader.hideMenuButton(); 1884 1885 page.setInPropertyView(false) 1886 1887 collectionSection.show(); 1888 propertySection.hide() 1889 1890 propertyPaging.setCurrentPage(1); 1891 1892 copyPropertyToCollectionModal.getCollectionList(collections) 1893 1894 const collectionDescription = document.getElementById('collection-description') 1895 collectionDescription.style.display="none" 1896 collectionDescription.children[0].innerText = ""; 1897 addListingsBlock.hide(); 1898 }).subscribe() 1899 1900 Pubsub.subscription('create_new_collection_pressed', (e) => { 1901 collectionModal.show(0, false); 1902 }).subscribe(); 1903 1904 Pubsub.subscription('on_new_collection_saved', (e) => { 1905 if(e.type == 'save'){ 1906 1907 let people = [{ personUUID: page.lead.brivity_uuid, role: "lead" }]; 1908 let properties = [""]; 1909 collectionsService.createCollection(e.name, e.description, page.lead.brivity_uuid, people, properties).then((e) => { 1910 1911 collections.unshift(e.data); 1912 1913 extraCollections++ 1914 if(collections.length > 8) { 1915 collections.pop(); 1916 collectionPaging.show() 1917 collectionPaging.setPageCount(Math.ceil(extraCollections / 8)); 1918 } 1919 1920 count = 100; 1921 collectionSection.collections.innerHTML = ""; 1922 collections.forEach((collection) => { 1923 count-- 1924 collectionSection.addCollectionCard(collection, count) 1925 }); 1926 1927 let collectionsList = copyPropertyToCollectionModal.getCollectionData(); 1928 let newCollection = { 1929 collection_title: e.data.collectionName, 1930 id: e.data.collectionUUID, 1931 propertiesImages: [], 1932 } 1933 collectionsList.unshift(newCollection); 1934 copyPropertyToCollectionModal.setCollectionData(collectionsList); 1935 1936 if(!copyPropertyToCollectionModal.isVisible){ 1937 if (createCopyCollection) { 1938 copyPropertyToCollectionModal.isVisible = true; 1939 copyPropertyToCollectionModal.element.setAttribute('style', 'display:flex'); 1940 createCopyCollection = false;
1941 } else { 1942 collectionCreatedModal.show(e.data); 1943 } 1944 } 1945 1946 collectionModal.hide(); 1947 1948 newCollectionBlock.hide(); 1949 }).catch((e) => { 1950 collectionModal.showError(true) 1951 }); 1952 } 1953 else{ 1954 collectionsService.updateCollection(e.collectionUUID, e.name, e.description).then((collection) => { 1955 let element = document.getElementById(e.collectionUUID); 1956 element.setAttribute('title', e.name); 1957 element.setAttribute('description', e.description); 1958 if(Object.keys(page.selectedCollection).length !== 0){ 1959 pageSubHeader.setTitle(e.name); 1960 } 1961 const collectionDescription = document.getElementById('collection-description') 1962 collectionDescription.children[0].innerText = e.description; 1963 let updatedCollection = collections.findIndex((c) => c.collectionUUID == e.collectionUUID) 1964 if(updatedCollection != -1){ 1965 collections[updatedCollection].collectionName = e.name; 1966 collections[updatedCollection].collectionDescription = e.description; 1967 } 1968 collectionModal.hide(); 1969 editCollectionModal.show(); 1970 }); 1971 } 1972 }).subscribe(); 1973 1974 Pubsub.subscription('collection_created_modal_view_collection_pressed', (collection) => { 1975 Pubsub.publish('collection_card_pressed', {"collection": collection}) 1976 }).subscribe(); 1977 1978 Pubsub.subscription('delete_collection_modal_delete_pressed', (collection) => { 1979 collectionsService.deleteCollection(collection.collectionUUID).then((e) => { 1980 document.getElementById(collection.collectionUUID).remove(); 1981 toast.show('Collection was Deleted') 1982 1983 extraCollections-- 1984 1985 if(extraCollections.length < 9) { 1986 collectionPaging.hide() 1987 }else{ 1988 collectionPaging.setPageCount(Math.ceil(extraCollections / 8)); 1989 } 1990 1991 if(page.inPropertyView){ 1992 Pubsub.publish('top_header_back_pressed'); 1993 } 1994 }); 1995 }).subscribe(); 1996 1997 Pubsub.subscription('delete_property_modal_delete_pressed', (e) => { 1998 const currentPage = $("#property-pagination").find("#info-parent").filter( 1999 function() { 2000 return $(this).css("color") === "rgb(196, 196, 196)" 2001 } 2002 ).text(); 2003 2004 const propertiesPerPage = 8; 2005 const numOfProperties = $("#property-list .property-card-wrapper").length; 2006 const setPage = numOfProperties === 1 ? currentPage - 1 : currentPage; 2007 2008 collectionsService.removePropertyFromCollection(e.collectionUUID, e.propertyCollectionUUID) 2009 .then(() => { 2010 toast.show('Property removed from collection'); 2011 2012 return collectionsService.getCollectionProperties(e.collectionUUID, setPage, propertiesPerPage); 2013 }) 2014 .then((collectionProperties) => { 2015 const totalListingsCount = collectionProperties?.data?.totalListings; 2016 const properties = collectionProperties?.data?.properties; 2017 const totalPages = collectionProperties?.data?.totalPages; 2018 const currentCollection = $(`#${e.collectionUUID}`); 2019 2020 currentCollection.attr("num_properties", totalListingsCount); 2021 2022 map.setMarkers(properties); 2023 savedListings.setCount(totalListingsCount || 0); 2024 propertySection.show(propertySection.collectionUUID, collectionProperties); 2025 propertySection.setPropertyCardWidth(); 2026 2027 propertyPaging.setCurrentPage(setPage); 2028 propertyPaging.setPageCount(totalPages); 2029 2030 if (totalListingsCount <= 8) { 2031 propertyPaging.hide(); 2032 } 2033 }) 2034 .catch(error => { 2035 console.error("Error in collection operations:", error); 2036 }); 2037 }).subscribe(); 2038 2039 Pubsub.subscription('copy_property_to_collection_modal_save_pressed', (e) => { 2040 2041 let collectionUUID = e.collectionUUID; 2042 let blossorId = e.property.blossorId; 2043 collectionsService.addPropertyToCollection(collectionUUID, [blossorId]).then(() => { 2044 2045 2046 let data = copyPropertyToCollectionModal.getCollectionData(); 2047 let myFeedData = myFeed.getMlsData(); 2048 2049 collectionsService.getCollectionProperties(collectionUUID,1,1).then((e) => { 2050 2051 // update photos in add property to collection modal 2052 let collectionIndex = data.findIndex((x) => x.id == collectionUUID); 2053 let collection = data[collectionIndex]; 2054 let photo = e?.data?.properties[0]?.photos[0]?.url; 2055 2056 collection.propertiesImages = []; 2057 if(e?.data?.properties?.length > 0){ 2058 collection.propertiesImages.push({mainPhoto: photo}); 2059 } 2060 2061 data[collectionIndex] = collection; 2062 2063 copyPropertyToCollectionModal.setCollectionData(data); 2064 2065 2066 // update collection card if in collection view 2067 pageCollectionIndex = collections.findIndex((x) => x.collectionUUID == collectionUUID) 2068 2069 if(pageCollectionIndex > -1){ 2070 2071 let collectionCard = document.getElementById(collectionUUID); 2072 let numProperties = parseInt(collectionCard.getAttribute('num_properties')); 2073 numProperties++; 2074 collectionCard.setAttribute('num_properties', numProperties); 2075 2076 let images = collectionCard.getAttribute('image'); 2077 if(images){ 2078 images += "," + photo; 2079 } 2080 else{ 2081 images = photo; 2082 } 2083 2084 collectionCard.setAttribute('image', images); 2085 } 2086 2087 //update my feed to set property heart as favorited 2088 let myFeedPropertyIndex = myFeedData.findIndex((x) => x.blossorId == blossorId); 2089 if(myFeedPropertyIndex > -1){ 2090 myFeedData[myFeedPropertyIndex].favorite = true; 2091 myFeed.setMlsData(myFeedData); 2092 } 2093 2094 }) 2095 2096 copyPropertyToCollectionModal.hide(); 2097 toast.show('Property added to collection') 2098 2099 }).catch((e) => { 2100 toast.show('Error adding property to collection', true) 2101 }); 2102 }).subscribe(); 2103 2104 Pubsub.subscription('collection_page_changed', (e) => { 2105 collectionsService.getCollections(e, collectionPaging.collectionsPerPage).then((e) => { 2106 if(e?.data?.Items){ 2107 collections = e.data.Items; 2108 2109 collectionSection.collections.innerHTML = ""; 2110 count = 100;
2111 e.data.Items.forEach((collection) => { 2112 count-- 2113 2114 collectionSection.addCollectionCard(collection, count) 2115 }); 2116 } 2117 }); 2118 }).subscribe(); 2119 2120 Pubsub.subscription('share_saved_property_modal_share_pressed', (e) => { 2121 toast.show('Link Copied!') 2122 }).subscribe(); 2123 2124 Pubsub.subscription('my_feed_share_pressed', (e) => { 2125 shareSavedPropertyModal.show(e.property); 2126 }).subscribe(); 2127 2128 Pubsub.subscription('my_feed_add_collection_pressed', (e) => { 2129 copyPropertyToCollectionModal.setIsAddingToCollection(true); 2130 copyPropertyToCollectionModal.show(e.property); 2131 }).subscribe(); 2132 2133 Pubsub.subscription('map_marker_clicked', (id) => { 2134 propertySection.scrollIntoView(id); 2135 2136 document.querySelectorAll('place-propertycard').forEach((propertyCard) => { 2137 if(propertyCard.id == id) { 2138 propertyCard.setAttribute('show_border', true) 2139 } 2140 else { 2141 propertyCard.setAttribute('show_border', false) 2142 } 2143 }) 2144 }).subscribe(); 2145 2146 Pubsub.subscription('my_feed_on_favorite_pressed', (e) => { 2147 copyPropertyToCollectionModal.setIsAddingToCollection(true); 2148 copyPropertyToCollectionModal.show(e.property); 2149 }).subscribe(); 2150 2151 Pubsub.subscription('my_feed_on_unfavorite_pressed', (e) => { 2152 let blossorId = e.property.blossorId; 2153 let myFeedData = myFeed.getMlsData(); 2154 collectionsService.checkIfInCollection([blossorId]).then((propertiesInCollections) => { 2155 if(propertiesInCollections.data[blossorId]){ 2156 propertiesInCollections.data[blossorId].forEac
2156h((collection) => { 2157 collectionsService.removePropertyFromCollection(collection.collectionUUID, collection.propertyUUID).then(() => { 2158 2159 let data = copyPropertyToCollectionModal.getCollectionData(); 2160 let collectionUUID = collection.collectionUUID; 2161 collectionsService.getCollectionProperties(collectionUUID,1,1).then((e) => { 2162 2163 // update photos in add property to collection modal 2164 let collectionIndex = data.findIndex((x) => x.id == collectionUUID); 2165 let collection = data[collectionIndex]; 2166 let photo = e?.data?.properties?.length > 0 ? e?.data?.properties[0]?.photos[0]?.url : ''; 2167 2168 collection.propertiesImages = []; 2169 if(e?.data?.properties?.length > 0){ 2170 collection.propertiesImages.push({mainPhoto: photo}); 2171 } 2172 2173 data[collectionIndex] = collection; 2174 2175 copyPropertyToCollectionModal.setCollectionData(data); 2176 2177 2178 // update collection card if in collection view 2179 pageCollectionIndex = collections.findIndex((x) => x.collectionUUID == collectionUUID) 2180 2181 if(pageCollectionIndex > -1){ 2182 2183 let collectionCard = document.getElementById(collectionUUID); 2184 let numProperties = parseInt(collectionCard.getAttribute('num_properties')); 2185 numProperties--; 2186 collectionCard.setAttribute('num_properties', numProperties); 2187 2188 let images = collectionCard.getAttribute('image'); 2189 let newImages = images.split(',').filter((x) => x == photo).join(','); 2190 collectionCard.setAttribute('image', newImages); 2191 } 2192 2193 //update my feed to set property heart as not favorited 2194 let myFeedPropertyIndex = myFeedData.findIndex((x) => x.blossorId == blossorId); 2195 if(myFeedPropertyIndex > -1){ 2196 myFeedData[myFeedPropertyIndex].favorite = false; 2197 myFeed.setMlsData(myFeedData); 2198 } 2199 }) 2200 toast.show('Property removed from collection'); 2201 }).catch((e) => { 2202 toast.show('Error removing from collection', true); 2203 }); 2204 }); 2205 } 2206 }); 2207 }).subscribe(); 2208 2209 let modalBackdrop = document.getElementsByClassName('center-modal'); 2210 for(let i = 0; i < modalBackdrop.length; i++){ 2211 modalBackdrop[i].addEventListener('click', (e) => { 2212 if(e.target == modalBackdrop[i]){ 2213 modalBackdrop[i].style.display = 'none'; 2214 } 2215 }); 2216 } 2217 2218 window.addEventListener( "hashchange", function( event ) { 2219 if(window.location.hash == ''){ 2220 Pubsub.publish("top_header_back_pressed"); 2221 } 2222 }); 2223 2224 2225 document.addEventListener("click", (e) => { 2226 2227 const elements = document.querySelectorAll("[show_menu]");
2228 elements.forEach((el) => { 2229 el.setAttribute("show_menu", "false"); 2230 }); 2231 2232 document.getElementById("c2dfac72-6233-4e8d-b0d2-f44e4240ebb4")?.setAttribute("show_menu", "false"); 2233 }); 2234 if(window.innerWidth < 768 ){ 2235 savedListings.hide(); 2236 pageSubHeader.hideSecondaryButton(); 2237 } else{ 2238 addListingBtn.hide(); 2239 } 2240 })(); 2241 } 2242 }) 2243 2244</script>
2244 <div id="myportal-page" style="display:none"> <div style="position:relative; width:100%;"> <div style="position:absolute;z-index:110; top:0; bottom:0; "> <place-menu></place-menu> </div> <div class="collection-page" style="flex:1;"> <div class="page-width-parent"> <place-pagesubheader title="COLLECTIONS" show_top_header="false" button_title="Create New" button_icon="plus" secondary_button_icon="plus" secondary_button_title="Add Listings" show_secondary_button="false" show_menu="false" menu_items='[{ "icon": "edit-2", "text": "Edit Collection" },{ "icon": "trash", "text": "Delete Collection" }]' ></place-pagesubheader> <div id="collection-description" class="collection-description" style="display:none;"> <p class="collection-description-text" style="" ></p> </div> <div id="collection-section" style="margin-top:24px;"> <div id="collections" style="display:flex; flex-wrap:wrap"> <place-actioncard id="new-collection-block" style="display:none;" title="Create A Collection" sub_title="You can create a collection to save and keep track of your favorite properties." button_text="Create New" button_icon="plus" button_icon_fill="white" card_width="300" /> </div> <place-pagination id="collection-pagination" style="display:none"></place-pagination> <div class="my-feed-parent"> <place-myfeedblock style="display:none" display_menu="false"></place-myfeedblock> </div> </div> <div id="property-section"> <div id="property-header" style="display:flex; justify-content: space-between"> <p id="collection-saved-listings" class="collection-saved-listings"></p> <place-button icon="plus" ghost="true" btn_text_styles="text-[#5386E4]" icon_stroke="#5386E4" id="add-listing-btn" title="Add Listing"></place-button> <div style="padding: 0 5px; display:flex"> <place-icon id="property-list-icon" style="margin-right:10px" name="list" size="24" fill="none" stroke="black"></place-icon> <place-icon id="property-map-icon" name="map" size="24" fill="none" stroke="gray"></place-icon> </div> </div> <div class="property-container" style=""> <div id="property-list-parent"> <div id="property-list" class="property-list-list-view"> </div> <div> <place-actioncard id="add-listings-block" style="display:none;" title="Add Listings" sub_title="You can search and add properties to a collection to keep track of your favorite homes using the heart icon." button_text="Search Listings" button_icon="search" button_icon_fill="white" card_width="300" /> </div> </div> <div id="property-map" class="property-map-container" style="display:none" > <place-map map_type_control="true" zoom_control="true"> </place-map> </div> </div> <place-pagination id="property-pagination" class="property-pagination" style="display:none"></place-pagination> </div> </div> </div> </div> <place-basicmodal id="collection-created-modal" class="center-modal" style="display:none" title="Collection Created" sub_title="Would you like to add listings to your new collection? You can search for new listings or copy them from an existing collection." title_icon="heart" primary_button_text="View Collection" tertiary_button_text="Search" stacked_buttons="true" ></place-basicmodal> <place-basicmodal id="delete-collection-modal" class="center-modal" style="display:none" title="Delete Collection" sub_title="Deleting a collection will permanently remove it from your account. Your saved properties will only be visible in your Favorites collection." description="Are you sure you would like to delete this collection?" title_icon="trash" primary_button_text="Delete" tertiary_button_text="Cancel" no_stack_buttons="true" ></place-basicmodal> <place-basicmodal id="edit-collection-modal" class="center-modal" style="display:none" title="Changes Saved" sub_title="The changes to your collection have been saved." title_icon="check" primary_button_text="Close" ></place-basicmodal> <place-basicmodal id="delete-property-modal" class="center-modal" style="display:none" title="Remove Property" sub_title="Deleting this property will remove it from the current collection. Are you sure you would like to delete this property from your collection?" title_icon="trash" primary_button_text="Delete" tertiary_button_text="Cancel" no_stack_buttons="true" ></place-basicmodal> <place-basicmodal id="share-saved-property-modal" class="center-modal" style="display:none" title="Share Property" sub_title="Copy link to share property." title_icon="share" primary_button_text="Copy Link" ></place-basicmodal> <place-copycollectionmodal class="center-modal" style="display:none" collections='[]' ></place-copycollectionmodal> <place-collectionpopup class="center-modal" style="display:none"></place-collectionpopup> </div> <footer id="footer-8n" style="padding: 100px 0px; background-color: rgb(255, 255, 255) !important; outline: none; cursor: inherit;" data-selector="footer"><div class="container"> <div class="row"> <div class="col-sm-4"> <div class="footer-logo-container"> <img class="img-responsive" src="https://images.brivityidx.com/assets/images/uploads/7586/logo-01.png" alt="" data-selector="img" style="border-radius: 0px !important; border-color: rgb(128, 128, 128) !important; border-style: none !important; border-width: 0px !important; height: 70px !important; width: 200px !important; outline: none; cursor: inherit;"></div> <div> <p data-selector="p" style="outline: none; cursor: inherit;"><span class="agent_address_dynamic dynamic_loading dynamic_loading dynamic_loading">7455 McVay Station Ct</span><br><span class="agent_city_dynamic dynamic_loading dynamic_loading dynamic_loading">Germantown</span>, <span class="agent_state_dynamic dynamic_loading dynamic_loading dynamic_loading">TN</span> <span class="agent_zip_dynamic dynamic_loading dynamic_loading dynamic_loading">38138</span></p> <p data-selector="p" style="outline: none; cursor: inherit;"><a class="agent_phone_dynamic dynamic_loading dynamic_loading dynamic_loading" href="tel:9016255200" src="tel:" style="outline: none; cursor: inherit;">(901) 625-5200</a><br> </p></div> </div> <div class="col-sm-3"> <hr data-selector="hr" style="outline: none; cursor: inherit;"><h3 class="ediContent" data-selector="h1, h2, h3, h4, h5, h6" style="">Quick Links</h3> <ul class="list-unstyled editContent" style="" data-selector=".editContent"><li data-selector="li" style="outline: none; cursor: inherit;"><a href="/home_value" style="outline: none; cursor: inherit;">See Home Value</a></li> <li data-selector="li" style="outline: none; cursor: inherit;"><a id="top-nav-marketing-plan" data-toggle="modal" data-target="#sell-modal" style="outline: none; cursor: inherit;">Get Marketing Plan</a></li> </ul></div> <div class="col-sm-5"> <hr data-selector="hr" style="outline: none; cursor: inherit;"><h3 class="editContent" data-selector=".editContent" style="outline: none; cursor: inherit;">More</h3> <ul class="list-unstyled" style="outline: none; cursor: inherit;"><li data-selector="li" style="outline: none; cursor: inherit;"><a href="/index" style="outline: none; cursor: inherit;">Home </a></li> <li data-selector="li" style="outline: none; cursor: inherit;"><a href="/why_list_with_us" style="outline: none; cursor: inherit;">Why List with Us?</a></li> </ul></div> <div class="col-sm-5"> <hr data-selector="hr" style="outline: none; cursor: inherit;"><h3 class="editContent" data-selector=".editContent" style="">OUR LOCATIONS</h3> <ul class="list-unstyled" style=""><li data-selector="li" style="outline: none; cursor: inherit;"><a href="/index" style="">Germantown, Collierville, Arlington, Lakeland, Cordova, Bartlett, Memphis </a></li> </ul></div> </div> <div class="row margin-top-40"> <div class="col-sm-4 anchor-col"> <ul class="list-inline social" style="outline: none; cursor: inherit;"><li data-selector="li" style="outline: none; cursor: inherit;"> <a class="agent_facebook_dynamic dynamic_loading dynamic_loading dynamic_loading" href="https://www.facebook.com/livelovememphis/" target="_blank" style="outline: none; cursor: inherit;"> <svg viewbox="0 0 24 24" width="24" height="24" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round" class="css-i6dzq1"><path d="M18 2h-3a5 5 0 0 0-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3z"></path></svg></a> </li> <li data-selector="li" style="outline: none; cursor: inherit;"> <a class="agent_twitter_dynamic dynamic_loading dynamic_loading dynamic_loading" href="https://twitter.com/livelovememphis?lang=en" target="_blank" style="outline: none; cursor: inherit;"> <svg viewbox="0 0 24 24" width="24" height="24" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round" class="css-i6dzq1"><path d="M23 3a10.9 10.9 0 0 1-3.14 1.53 4.48 4.48 0 0 0-7.86 3v1A10.66 10.66 0 0 1 3 4s-4 9 5 13a11.64 11.64 0 0 1-7 2c9 5 20 0 20-11.5a4.5 4.5 0 0 0-.08-.83A7.72 7.72 0 0 0 23 3z"></path></svg></a> </li> <li data-selector="li" style="outline: none; cursor: inherit;"> <a class="agent_instagram_dynamic dynamic_loading dynamic_loading dynamic_loading" href="https://www.instagram.com/livelovememphis/?hl=en" target="_blank" style="outline: none; cursor: inherit;"> <svg viewbox="0 0 24 24" width="24" height="24" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round" class="css-i6dzq1"><rect x="2" y="2" width="20" height="20" rx="5" ry="5"></rect><path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"></path><line x1="17.5" y1="6.5" x2="17.5" y2="6.5"></line></svg></a> </li> </ul></div> <div class="col-sm-8 anchor-col"> <p class="margin-bottom-0" data-selector="p" style="outline: none; cursor: inherit;"><span class="get_this_year"></span> © The Live Love Memphis Group | Real Estate Agency. <span>All rights reserved.</span></p> <p style="margin: 10px 0px; outline: none; cursor: inherit;" data-selector="p"> <img src="https://images.brivityidx.com/assets/images/uploads/1428/Equal-Housing-Realtor_gray50.png" alt="Equal Housing | Realtor" style="width: 50px; outline: none; cursor: inherit;" data-selector="img">  Each office is independently owned and operated. </p> </div> </div> </div> </footer> </div> <section id="seo-anchor"> <div class="container"> <ul class="powered-by"> <li>Powered by <a class="pb-vendor" href="https://www.brivity.com/"> Brivity</a></li> <li class="pb-admin-login"><a href="https://login.brivityidx.com/login"><span class='pb-admin-login-text'>Admin Log In</span></a></li> </ul> <ul class="seo-anchor-links"> <li><a href="/privacy_policy">Privacy Policy</a></li> <li><a href="/tos">DMCA & Terms of Service</a></li> <li><a id='sitemapUrl' href='/sitemap' style='display: inline;'>Sitemap</a></li> </ul> </div> </section> <input type="hidden" id="hchatbot_settings" data-chatbot-version="1" value="{"chat_position":"right","call_to_action_text":"Hi there! Please let us know if you have any questions and an agent will reach out to you as soon as possible.","initial_message":"Enter your question below and an agent will be in touch with you.","tags":"IDX Chat","version":"1"}"> 2245<!-- chatbot v1 --> 2246<!-- Chatbot drawer container --> 2247<div class="chatbot-drawer-container loading"> 2248 <div class="chatbot-content-wrapper"> 2249 <div class="chatbot-outside-content"> 2250 <div class="chatbot-bubble-message-container cb-hide"> 2251 <img src="https://cdn.brivity.com/images/people/16717093/54cd6c6a08d4cae8e13641572de36ac9f72adcfa-original.jpg?1755537591" class="chatbot-agent-img" alt="Agent profile image in chat bubble"/> 2252 <div id="call-to-action" class="bubble-message"></div> 2253 <button type="button" class="chatbox-bubble-close" data-dismiss="modal" aria-label="Close">
2254 <span aria-hidden="true">×</span> 2255 </button> 2256 </div> 2257 <button id="chatbot-open-btn" class="chatbot-open-btn bg-prmry" aria-label="Chatbot Open Button"> 2258 <svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg"> 2259 <path d="M20.8 6.35501V16C20.8 17.765 19.365 19.195 17.6 19.195L11.2 19.2L5.755 22.28C5.645 22.365 5.52 22.4 5.4 22.4C5.09 22.4 4.8 22.155 4.8 21.8V19.2H3.2C1.4375 19.2 0 17.765 0 16V6.35501C0 4.63751 1.4375 3.20001 3.2 3.20001H17.6C19.365 3.20001 20.8 4.63751 20.8 6.35501ZM7.2 18.705L10.57 16.8H17.6C18.035 16.8 18.4 16.44 18.4 16V6.40001C18.4 5.96251 18.035 5.60001 17.6 5.60001H3.2C2.7625 5.60001 2.4 5.96251 2.4 6.40001V16C2.4 16.44 2.7625 16.8 3.2 16.8H7.2V18.705ZM12.8 22.4V20.8H15.2V22.4C15.2 22.835 15.56 23.2 16 23.2H21.43L24.8 25.105V23.2H28.8C29.235 23.2 29.6 22.835 29.6 22.4V12.8C29.6 12.365 29.235 12 28.8 12H22.4V9.60001H28.8C30.565 9.60001 32 11.035 32 12.755V22.4C32 24.165 30.565 25.6 28.8 25.6H27.2V28.2C27.2 28.555 26.91 28.8 26.6 28.8C26.48 28.8 26.355 28.765 26.245 28.68L20.8 25.6L16 25.595C14.24 25.595 12.8 24.165 12.8 22.4Z" fill="white"/> 2260 </svg> 2261 </button> 2262 </div> 2263 <div class="chatbot-drawer"> 2264 <div class="chatbot-header bg-prmry"> 2265 <div class="chatbot-agent-info"> 2266 <img src="https://cdn.brivity.com/images/people/16717093/54cd6c6a08d4cae8e13641572de36ac9f72adcfa-original.jpg?1755537591" class="chatbot-agent-img" alt="Agent profile image in chat header"/> 2267 <div class="chatbot-agent"> 2268 <h3 class="chatbot-agent-name">Jen Carstensen</h3> 2269 <h4><span class="chatbot-agent-title">Broker/Owner</span> | <span class="chatbot-agent-company">Real Estate Agency</span></h4> 2270 </div> 2271 <a id="chatbot-agent-phone" style="display: none;">(901) 201-0280</a> 2272 </div> 2273 <button id="close-chatbot-drawer" type="button" class="chatbox-modal-close" data-dismiss="modal" aria-label="Close"> 2274 <span aria-hidden="true">×</span> 2275 </button> 2276 </div> 2277 <div class="chatbot-body"> 2278 <div class="chatbot-message-container"> 2279 <img src="https://cdn.brivity.com/images/people/16717093/54cd6c6a08d4cae8e13641572de36ac9f72adcfa-original.jpg?1755537591" class="chatbot-agent-img" alt="Agent profile image in message"/> 2280 <h4 id="initial_message" class="chatbot-chat-messages not-loaded"></h4> 2281 <div class="chatbot-chat-messages loading"> 2282 <span class="typing-indicator"> 2283 <span></span> 2284 <span></span> 2285 <span></span> 2286 </span> 2287 </div> 2288 </div> 2289 <form id="chatbotForm" class="chatbot-form"> 2290 <input type="name" id="chatbot_fullname" class="chatbox-form-control no-native-focus" placeholder="Full Name" 2291 pattern="^[A-Za-z'\- ]+ [A-Za-z'\- ]+$" 2292 required /> 2293 <input type="tel" id="chatbot_phone" class="chatbox-form-control no-native-focus" placeholder="Phone" required /> 2294 <input type="email" id="chatbot_email" class="chatbox-form-control no-native-focus" placeholder="Email" 2295 pattern="^[^@\s]+@[^@\s]+\.[^@\s]+$" 2296 required /> 2297 <textarea id="chatbot_message" class="chatbox-form-control chatbot-message" rows="5" name="notes" placeholder="Any Comments or Questions"></textarea> 2298 <div class="chatbot-consent-container"> 2299 <div class="chatbot-toggle"> 2300 By proceeding and clicking the sign up button, you consent to receive calls and texts (SMS/MMS) including marketing and promotional communications, from <span class="agent_name_dynamic"></span>, its affiliates, and agents or vendors acting on their behalf. These
2300communications may be delivered using an automatic telephone dialing system or by using an artificial or prerecorded voice. Message and data rates may apply. To opt out of text messages, reply STOP. Your consent is not required as a condition of any purchase. By continuing, you also agree to our <a class="opt-out-href" href="/tos">Terms of Use</a> and <a class="opt-out-href" href="/privacy_policy">Privacy Policy</a>. 2301 </div> 2302 </div> 2303 <input type="hidden" id="chatbot_tags"> 2304 </form> 2305 </div> 2306 <div class="chatbot-footer"> 2307 <button type="submit" form="chatbotForm" class="chatbot-send bg-prmry chatbot-btn-disabled" data-dismiss="modal" aria-label="Close" disabled> 2308 Send 2309 <span aria-hidden="true"> 2310 <svg class="chatbot-btn-icon" width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> 2311 <g clip-path="url(#clip0_2435_997)"> 2312 <path d="M14.6667 1.33331L7.33337 8.66665" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> 2313 <path d="M14.6667 1.33331L10 14.6666L7.33337 8.66665L1.33337 5.99998L14.6667 1.33331Z" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> 2314 </g> 2315 <defs> 2316 <clipPath id="clip0_2435_997"> 2317 <rect width="16" height="16" fill="white"/> 2318 </clipPath> 2319 </defs> 2320 </svg> 2321 </span> 2322 </button> 2323 </div> 2324 </div> 2325 </div> 2326</div> <style> 2327 .signup-consent-checkbox-section { 2328 display: none; 2329 flex-direction:column; 2330 align-items:flex-start; 2331 padding: 6px 0; 2332 } 2333 2334 .signup-consent-checkbox-section .checkbox { 2335 display:flex; 2336 align-items:flex-start; 2337 justify-content:center; 2338 gap:8px; 2339 padding:0 !important; 2340 } 2341 2342 .signup-consent-checkbox-section .checkbox input { 2343 position:unset; 2344 margin:2px 0 0 0 !important; 2345 } 2346 2347 .signup-consent-checkbox-section .checkbox span { 2348 color: #666666; 2349 font-size: 14px; 2350 font-weight: 400; 2351 line-height:16px; 2352 } 2353 2354 .signup-verbage { 2355 text-align:center; 2356 font-size:10px; 2357 line-height:16px; 2358 } 2359 2360 .signup-verbage span { 2361 color: #8C8C8C; 2362 font-weight:600; 2363 } 2364 2365 .signup-verbage a { 2366 color:#5386E4 !important; 2367 font-weight:400; 2368 } 2369 2370 .signup-verbage .twilio-enabled-verbage { 2371 display:none; 2372 } 2373 2374 2375 2376 </style> <div id="modal-mount" data-modal-bundle="https://cdn1.brivityidx.com/assets/modals/v1/all.html?ck=1790798866"></div>
2376 <div id="credential_picker_container_centered"> <div id="credential_picker_header_bar"> <p><button class="signOrLogBtn" onclick="showSignupModal();">Sign up</button> or <button class="signOrLogBtn" onclick="showLoginModal();">Login</button> another way</p> </div> <div id="credential_picker_header_bar_separator"></div> </div> <place-getyourhomecta id="contact_modal" style="display:none; justify-content: center; align-items: center; position:fixed; background-color:rgba(0,0,0,0.4); left:0; top:0; right:0; bottom:0; z-index: 100;" interest_items='[{"text":"Looking to sell ASAP"},{"text":"Looking to sell (1-3 months)"},{"text":"Looking to sell (3-6 months)"}, {"text":"Looking to sell (6-12 months)"},{"text":"Looking to sell (12+ months)"}, {"text":"Just curious"}]' > </place-getyourhomecta> <place-generictoast appear_from_both="true" container_style="right-1/2 z-200"></place-generictoast>
2376<script> 2377 document.addEventListener("DOMContentLoaded", () => { 2378 class Toast { 2379 constructor() { 2380 this.element = document.querySelector('place-generictoast'); 2381 } 2382 2383 show(message, error = false, link) { 2384 var dispatch = function () { 2385 window.dispatchEvent( 2386 new CustomEvent("ShowToast", { 2387 detail: { 2388 text: message, 2389 error: error, 2390 link: link, 2391 }, 2392 }) 2393 ); 2394 }; 2395 if (window.sitebuilderPlaceComponents && window.sitebuilderPlaceComponents.ensureLoaded) { 2396 window.sitebuilderPlaceComponents 2397 .ensureLoaded('place-generictoast') 2398 .then(dispatch) 2399 .catch(function (err) { 2400 console.warn('toast.show fallback (web-components unavailable):', message, err); 2401 }); 2402 } else { 2403 dispatch(); 2404 } 2405 } 2406 } 2407 2408 window.toast = new Toast(); 2409 }); 2410 </script>
2410
2410<script src="https://cdn.jsdelivr.net/npm/@turf/[email protected]/turf.min.js"></script>
2410
2410<script src="https://maps.googleapis.com/maps/api/js?libraries=geocoding,places,marker,drawing&key=AIzaSyAjpuNg6WGCMV5rzoJcIP2QmMTVto6hYmc&map_ids=85c127b7bf0255d9"></script>
2410
2410<script src="https://cdn1.brivityidx.com/assets/js/build.min.js?ck="></script>
2410
2410<script src="https://cdn1.brivityidx.com/assets/js/top_bar_v2.min.js?ck="></script>
2410
2410<script src="https://cdn1.brivityidx.com/assets/js/global_js.min.js?ck=1790798865"></script>
2410
2410<script>deferScript("https://cdn1.brivityidx.com/assets/js/global_js_defer.min.js?ck=1790798865", 5000);</script>
2410
2410<script> 2411 function shouldLoadChatbotImmediately() { 2412 const settingsEl = document.getElementById('hchatbot_settings'); 2413 if (!settingsEl) return false; 2414 2415 const version = Number(settingsEl.dataset.chatbotVersion); 2416 let isInitialized = false; 2417 2418 try { 2419 const session = JSON.parse(sessionStorage.getItem('cbSession') || '{}'); 2420 isInitialized = session.chatbotInitialized === true; 2421 } catch (e) {} 2422 2423 return version > 1 && isInitialized; 2424 } 2425 </script>
2425
2425<script>document.getElementById('hchatbot_settings') && Number(document.getElementById('hchatbot_settings').dataset.chatbotVersion) > 1 && deferScript("https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/9.0.6/signalr.min.js", 0);</script>
2425
2425<script>document.getElementById('hchatbot_settings') && deferScript(Number(document.getElementById('hchatbot_settings').dataset.chatbotVersion) > 1 ? "https://cdn1.brivityidx.com/assets/js/chatbot_v2.min.js?ck=1790798864" : "https://cdn1.brivityidx.com/assets/js/chatbot.min.js?ck=1790798864", shouldLoadChatbotImmediately() ? 50 : 5000);</script>
2425
2425<script type="text/javascript" src="https://cdn1.brivityidx.com/assets/js/jquery.geocomplete.min.js"></script>
2425<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery.bootstrapvalidator/0.5.3/js/bootstrapValidator.min.js"></script>
2425<script type="text/javascript" src="https://cdn1.brivityidx.com/assets/js/member_area_components.js"></script>
2425<script type="text/javascript" src="https://cdn1.brivityidx.com/assets/js/update_agent_info.js"></script>
2425
2425<script src="https://mobile-component-services-library.s3.amazonaws.com/collections_service.min.js?ck=1"></script>
2425
2425<script src="https://mobile-component-services-library.s3.amazonaws.com/messaging_service.min.js?ck=1"></script>
vendor: 68 bytes, line 2425
2425 <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=
2425GTM-K2WGMDL
vendor: 83 bytes, line 2425
2425" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
2425<script>$(document).ready(function(){$("ul.seo-anchor-links li:nth-of-type(4) a").attr("href","/search")})</script>
2425
2425<script>$(document).ready(function(){$("#sitemap-listings > div.container > div > div.col-xs-12.col-md-12.col-lg-4.col-lg-push-8.seo-intro > a").attr("href","/search")})</script>
2425</body> </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.