RealMæglerne Renny Clemmensen ApS
Error executing template "Designs/rm/eCom/Product/Boligvisning.cshtml"
System.InvalidOperationException: Sequence contains no elements
   at System.Linq.ThrowHelper.ThrowNoElementsException()
   at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
   at CompiledRazorTemplates.Dynamic.RazorEngine_8dded3753b1e4b188d1e212eb99d857d.ExecuteAsync()
   at RazorEngine.Templating.TemplateBase.Run(ExecuteContext context, TextWriter reader)
   at RazorEngine.Templating.RazorEngineCore.RunTemplate(ICompiledTemplate template, TextWriter writer, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.RazorEngineService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.DynamicWrapperService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.RazorEngineServiceExtensions.Run(IRazorEngineService service, String name, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
   at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass23_0.<Run>b__0(TextWriter writer)
   at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter)
   at RazorEngine.Templating.RazorEngineServiceExtensions.Run(IRazorEngineService service, String name, Type modelType, Object model, DynamicViewBag viewBag)
   at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template)
   at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template)
   at Dynamicweb.Rendering.Template.RenderRazorTemplate()

1 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 2 @using Custom.Tracking; 3 @using Dynamicweb; 4 @using Dynamicweb.Content.Items; 5 @using Dynamicweb.Core; 6 @using Dynamicweb.Core.Encoders; 7 @using RealMaeglerne.Library; 8 @using RealMaeglerne.Library.Models 9 @using System 10 @using System.Linq; 11 12 @functions { 13 string FormatPrice(int price, bool currencyBefore = false) 14 { 15 return currencyBefore ? "kr. " + price.ToString("#,##0") : price.ToString("#,##0") + " kr."; 16 } 17 18 string GetFullAddress(Dynamicweb.Security.UserManagement.UserGroup user) 19 { 20 if (user == null) { return string.Empty; } 21 22 var hasAddress = !string.IsNullOrEmpty(user.Address); 23 var hasZip = !string.IsNullOrEmpty(user.ZipCode); 24 var hasCity = !string.IsNullOrEmpty(user.City); 25 26 if (!hasAddress && !hasZip && !hasCity) return string.Empty; 27 28 return $"{(hasAddress ? user.Address + ", " : "")}{(hasZip ? user.ZipCode + " " : "")}{(hasCity ? user.City : "")}".TrimEnd(' ', ','); 29 } 30 31 string SetMaxLength(string s, int length) 32 { 33 return s == null ? string.Empty : s.Substring(0, Math.Min(length, s.Length)); 34 } 35 36 string StripHtml(string input) 37 { 38 if (string.IsNullOrEmpty(input)) return string.Empty; 39 return System.Text.RegularExpressions.Regex.Replace(input, "<.*?>", string.Empty).Trim(); 40 } 41 } 42 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 43 @using Dynamicweb.Content.Items; 44 45 @functions{ 46 void RenderErhvervsTypeCheckboxes(string productGroupFilter) 47 { 48 <div class="col-xs-6 col-md-4"> 49 <div class="checkbox"> 50 <label> 51 <input type="checkbox" name="propertytype" value="bolig/erhverv, kombineret erhverv og bolig, byejendom (kontor, butik, beboelse)" /> 52 <span>Bolig/erhverv</span> 53 </label> 54 </div> 55 <div class="checkbox"> 56 <label> 57 <input type="checkbox" name="propertytype" value="erhvervsgrund" /> 58 <span>Erhvervsgrund</span> 59 </label> 60 </div> 61 <div class="checkbox"> 62 <label> 63 <input type="checkbox" name="propertytype" value="boligudlejning" /> 64 <span>Boligudlejningsejendom</span> 65 </label> 66 </div> 67 <div class="checkbox"> 68 <label> 69 <input type="checkbox" name="propertytype" value="kontor, klinik, kontorhotel, showroom, undervisningslokaler" /> 70 <span>Kontor</span> 71 </label> 72 </div> 73 </div> 74 <div class="col-xs-6 col-md-4"> 75 <div class="checkbox"> 76 <label> 77 <input type="checkbox" name="propertytype" value="butik / detail, butik / detailhandel" /> 78 <span>Butik/detailhandel</span> 79 </label> 80 </div> 81 <div class="checkbox"> 82 <label> 83 <input type="checkbox" name="propertytype" value="industri / logistik, håndværk, industri, kontor / lager, logistik" /> 84 <span>Produktion/lager</span> 85 </label> 86 </div> 87 <div class="checkbox"> 88 <label> 89 <input type="checkbox" name="propertytype" value="hotel - kursusejendom, restaurant" /> 90 <span>Hotel og restaurant</span> 91 </label> 92 </div> 93 <div class="checkbox"> 94 <label> 95 <input type="checkbox" name="propertytype" value="projekt ejendom" /> 96 <span>Projektejendom</span> 97 </label> 98 </div> 99 </div> 100 <div class="col-xs-6 col-md-4"> 101 <div class="checkbox"> 102 <label> 103 <input type="checkbox" name="propertytype" value="andet" /> 104 <span>Andet</span> 105 </label> 106 </div> 107 </div> 108 109 <input type="hidden" name="propertycategory" value="erhverv, udlejning" /> 110 <input type="hidden" name="filtrering" value="@productGroupFilter" /> 111 } 112 void RenderBoligtypeCheckboxes() 113 { 114 <div class="col-6 col-md-4"> 115 <div class="checkbox"> 116 <label> 117 <input type="checkbox" name="propertytype" value="villa" /> 118 <span>Villa</span> 119 </label> 120 </div> 121 <div class="checkbox"> 122 <label> 123 <input type="checkbox" name="propertytype" value="rækkehus" /> 124 <span>Rækkehus</span> 125 </label> 126 </div> 127 <div class="checkbox"> 128 <label> 129 <input type="checkbox" name="propertytype" value="villalejlighed" /> 130 <span>Villalejlighed</span> 131 </label> 132 </div> 133 <div class="checkbox"> 134 <label> 135 <input type="checkbox" name="propertytype" value="andelsbolig" /> 136 <span>Andelsbolig</span> 137 </label> 138 </div> 139 </div> 140 <div class="col-6 col-md-4"> 141 <div class="checkbox"> 142 <label> 143 <input type="checkbox" name="propertytype" value="fritidshus, fritidsbolig" /> 144 <span>Fritidsbolig</span> 145 </label> 146 </div> 147 <div class="checkbox"> 148 <label> 149 <input type="checkbox" name="propertytype" value="ejerlejlighed" class="specialOption" data-disable-slider="#grundareal" data-disable-slider-ranges="#grundarealmin,#grundarealmax" /> 150 <span>Ejerlejlighed</span> 151 </label> 152 </div> 153 <div class="checkbox"> 154 <label> 155 <input type="checkbox" name="propertytype" value="helårsgrund" class="specialOption" data-disable-slider="#boligareal,#roomsslider" data-disable-slider-ranges="#boligarealmin,#boligarealmax,#roomsmin" /> 156 <span>Helårsgrund</span> 157 </label> 158 </div> 159 <div class="checkbox"> 160 <label> 161 <input type="checkbox" name="propertytype" value="fritidsgrund" class="specialOption" data-disable-slider="#boligareal,#roomsslider" data-disable-slider-ranges="#boligarealmin,#boligarealmax,#roomsmin" /> 162 <span>Fritidsgrund</span> 163 </label> 164 </div> 165 </div> 166 <div class="col-6 col-md-4"> 167 <div class="checkbox"> 168 <label> 169 <input type="checkbox" name="propertytype" value="landejendom, lystejendom" class="specialOption" data-disable-checkbox="true" /> 170 <span>Landejendom</span> 171 </label> 172 </div> 173 <div class="checkbox"> 174 <label> 175 <input type="checkbox" name="propertytype" value="erhverv" class="specialOption" data-disable-checkbox="true" data-disable-slider="#roomsslider" data-disable-slider-ranges="#roomsmin" /> 176 <span>Erhverv</span> 177 </label> 178 </div> 179 </div> 180 } 181 182 void RenderChecked(string queryString) 183 { 184 if (Dynamicweb.Context.Current.Request.QueryString["propertytype"] == queryString) 185 { 186 @("checked") 187 } 188 } 189 190 void RenderBoligtypeCheckboxesDropdown() 191 { 192 Dictionary<string, string> propertyTypes = new Dictionary<string, string>(){ 193 { "Villa", "villa" }, { "Rækkehus", "rækkehus" }, { "Villalejlighed", "villalejlighed" }, 194 { "Andelsbolig", "andelsbolig" } 195 }; 196 foreach (KeyValuePair<string, string> type in propertyTypes) 197 { 198 bool ischecked = false; 199 string[] propertytypeSplit = new string[0]; 200 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["propertytype"])) 201 { 202 propertytypeSplit = Dynamicweb.Context.Current.Request.QueryString["propertytype"].Split(','); 203 } 204 foreach (var propertytypeParams in propertytypeSplit) 205 { 206 if (propertytypeParams == type.Value) 207 { 208 ischecked = true; 209 } 210 } 211 <li> 212 <label class="checkbox-container d-flex"> 213 @Translate("Smartpage:Search.DropDown." + type.Key + "", "" + type.Key + "") 214 <input type="checkbox" name="propertytype" value="@type.Value" class="js-input-check datavalue js-datavalue js-count" data-val="@type.Key" onchange="submitFilter()" checked="@ischecked" /> 215 <span class="checkmark grey"></span> 216 </label> 217 </li> 218 } 219 220 <li> 221 <label class="checkbox-container d-flex"> 222 @Translate("Smartpage:Search.DropDown.Blandet Bolig/Erhverv", "Blandet Bolig/Erhverv") 223 @{ 224 bool blboligcheck = false; 225 } 226 @if (Dynamicweb.Context.Current.Request.QueryString["propertycategory"] == "Blandet Bolig/Erhverv") 227 { 228 blboligcheck = true; 229 } 230 <input type="checkbox" name="propertycategory" value="Blandet Bolig/Erhverv" class="specialOption js-input-check js-datavalue js-count" data-disable-checkbox="true" data-disable-slider="#roomsslider" data-disable-slider-ranges="#roomsmin" checked="@blboligcheck" /> 231 <span class="checkmark grey"></span> 232 </label> 233 </li> 234 235 Dictionary<string, string> propertyTypes2 = new Dictionary<string, string>(){ 236 { "Fritidsbolig", "fritidshus, fritidsbolig" }, { "Ejerlejlighed", "ejerlejlighed" }, { "Helårsgrund", "helårsgrund" }, 237 { "Fritidsgrund", "fritidsgrund" }, { "Landejendom", "landejendom, lystejendom" } 238 }; 239 foreach (KeyValuePair<string, string> type in propertyTypes2) 240 { 241 bool ischecked = false; 242 string[] propertytypeSplit2 = new string[0]; 243 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["propertytype"])) 244 { 245 propertytypeSplit2 = Dynamicweb.Context.Current.Request.QueryString["propertytype"].Split(','); 246 } 247 foreach (var propertytypeParams in propertytypeSplit2) 248 { 249 if (propertytypeParams == type.Value) 250 { 251 ischecked = true; 252 } 253 } 254 <li> 255 <label class="checkbox-container d-flex"> 256 @Translate("Smartpage:Search.DropDown." + type.Key + "", "" + type.Key + "") 257 @if (type.Value == "ejerlejlighed") 258 { 259 <input type="checkbox" name="propertytype" value="@type.Value" class="js-input-check datavalue" data-disable-slider="#grundareal" data-disable-slider-ranges="#grundarealmin,#grundarealmax" data-val="@type.Key" onchange="submitFilter()" checked="@ischecked" /> 260 } 261 else if (type.Value == "helårsgrund") 262 { 263 <input type="checkbox" name="propertytype" value="@type.Value" class="js-input-check datavalue" data-disable-slider="#boligareal,#roomsslider" data-disable-slider-ranges="#boligarealmin,#boligarealmax,#roomsmin" data-val="@type.Key" onchange="submitFilter()" checked="@ischecked" /> 264 } 265 else if (type.Value == "fritidsgrund") 266 { 267 <input type="checkbox" name="propertytype" value="@type.Value" class="js-input-check datavalue" data-disable-slider="#boligareal,#roomsslider" data-disable-slider-ranges="#boligarealmin,#boligarealmax,#roomsmin" data-val="@type.Key" onchange="submitFilter()" checked="@ischecked" /> 268 } 269 else 270 { 271 <input type="checkbox" name="propertytype" value="@type.Value" class="js-input-check datavalue" data-val="@type.Key" onchange="submitFilter()" checked="@ischecked" /> 272 } 273 <span class="checkmark grey"></span> 274 </label> 275 </li> 276 } 277 } 278 279 void RenderBoligTypeErhverv(bool submitOnChange = false, bool frontpage = false) 280 { 281 Dictionary<string, string> erhverType = new Dictionary<string, string>(){ 282 { "Kontor", "OwnUseOffices" }, { "Lager + Produktion", "OwnUseStoresAndProductions" }, { "Detailhandel", "OwnUseRetailAndStores" }, 283 { "Grunde", "OwnUseParcel" }, { "Andre typer", "OwnUseOtherTypes" }, { "Hotel + Restaurant", "OwnUseHotelsAndRestaurants" } 284 }; 285 var submitonchange = ""; 286 if (submitOnChange) 287 { 288 submitonchange = "onchange='submitFilter()'"; 289 } 290 291 foreach (KeyValuePair<string, string> type in erhverType) 292 { 293 string ischecked = ""; 294 string[] olineParamsSplit = new string[0]; 295 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["olinecategory"])) 296 { 297 olineParamsSplit = Dynamicweb.Context.Current.Request.QueryString["olinecategory"].Split(','); 298 } 299 foreach (var olineParams in olineParamsSplit) 300 { 301 if (olineParams == type.Value) 302 { 303 ischecked = "checked"; 304 } 305 } 306 307 <li> 308 <label class="checkbox-container d-flex"> 309 @Translate("Smartpage:Search.DropDown." + type.Key + "", "" + type.Key + "") 310 <input type="checkbox" name="olinecategory" value="@type.Value" class="js-input-check datavalue" data-val="@type.Key" @submitonchange @ischecked /> 311 <span class="checkmark grey"></span> 312 </label> 313 </li> 314 } 315 316 317 bool ischeckedpropertycat = false; 318 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["propertycategory"])) 319 { 320 if (Dynamicweb.Context.Current.Request.QueryString["propertycategory"] == "Blandet Bolig/Erhverv") 321 { 322 ischeckedpropertycat = true; 323 } 324 } 325 <li> 326 <label class="checkbox-container"> 327 @Translate("Smartpage:Search.DropDown.Blandet Bolig/Erhverv", "Blandet Bolig/Erhverv") 328 <input type="checkbox" name="propertycategory" value="Blandet Bolig/Erhverv" class="js-input-check datavalue" data-val="Blandet Bolig/Erhverv" onchange="submitFilter()" checked="@ischeckedpropertycat" /> 329 <span class="checkmark grey"></span> 330 </label> 331 </li> 332 } 333 334 void RenderBoligTypeErhvervInvest(bool submitOnChange = false) 335 { 336 Dictionary<string, string> erhverType = new Dictionary<string, string>(){ 337 { "Kontor", "Kontor" }, { "Lager + Produktion", "InvestmentStoresAndProductions" }, { "Boligudlejning", "InvestmentHousingRental" }, 338 { "Detailhandel", "InvestmentRetailAndStores" }, { "Grunde", "InvestmentParcel" }, { "Hotel + Restaurant", "InvestmentHotelsAndRestaurants" }, { "Andre typer", "InvestmentOtherTypes" } 339 }; 340 341 foreach (KeyValuePair<string, string> type in erhverType) 342 { 343 bool ischecked = false; 344 string[] olineParamsSplit = new string[0]; 345 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString["olinecategory"])) 346 { 347 olineParamsSplit = Dynamicweb.Context.Current.Request.QueryString["olinecategory"].Split(','); 348 } 349 foreach (var olineParams in olineParamsSplit) 350 { 351 if (olineParams == type.Value) 352 { 353 ischecked = true; 354 } 355 } 356 357 <li> 358 <label class="checkbox-container"> 359 @Translate("Smartpage:Search.DropDown." + type.Key + "", "" + type.Key + "") 360 <input type="checkbox" name="olinecategory" value="@type.Value" class="js-input-check datavalue" data-val="@type.Key" onchange="submitFilter()" checked="@ischecked" /> 361 <span class="checkmark grey"></span> 362 </label> 363 </li> 364 } 365 } 366 int GetWebsiteSettingsPageId(string pageSysName) 367 { 368 int sideId = 0; 369 370 var pw = Dynamicweb.Frontend.PageView.Current(); 371 372 string settingsItemId = "1"; 373 374 if ((pw.Area.Item.ContainsKey("Type") && pw.Area.Item["Type"].ToString() == "bone") || Dynamicweb.Context.Current.Request.QueryString["bone"] == "true") 375 { 376 settingsItemId = "2"; 377 } 378 379 var settingsItem = ItemManager.Storage.GetById("Delte_Egenskaber", settingsItemId); 380 381 if (settingsItem == null || !settingsItem.ContainsKey(pageSysName)) 382 { 383 return sideId; 384 } 385 386 string boligsideLink = settingsItem[pageSysName] as String; 387 string linkPrefix = "Default.aspx?ID="; 388 389 if (!String.IsNullOrEmpty(boligsideLink) && boligsideLink.ToLower().StartsWith(linkPrefix.ToLower())) 390 { 391 Int32.TryParse(boligsideLink.Substring(linkPrefix.Length), out sideId); 392 } 393 394 return sideId; 395 } 396 397 int GetPageSettingsPageId(string pageSysName) 398 { 399 int sideId = 0; 400 401 var pw = Dynamicweb.Frontend.PageView.Current(); 402 403 if (pw.Page == null || pw.Page.PropertyItem == null || !pw.Page.PropertyItem.ContainsKey(pageSysName)) 404 { 405 return sideId; 406 } 407 408 string boligsideLink = pw.Page.PropertyItem[pageSysName] as String; 409 string linkPrefix = "Default.aspx?ID="; 410 411 if (!String.IsNullOrEmpty(boligsideLink) && boligsideLink.ToLower().StartsWith(linkPrefix.ToLower())) 412 { 413 Int32.TryParse(boligsideLink.Substring(linkPrefix.Length), out sideId); 414 } 415 416 return sideId; 417 } 418 void RenderMobileSelectBox(string name, int max, int step, string className, string inputname) 419 { 420 <select class="form-control d-block d-lg-none mb-10 @className" onchange="submitFilter()" name="@inputname"> 421 <option selected="true" disabled="disabled">@Translate("Smartpage:Search.Placeholder." + name + "", "" + name + "")</option> 422 423 @for (var i = 0; i <= max; i += step) 424 { 425 var selected = string.Empty; 426 var current = string.Empty; 427 if (i == max) 428 { 429 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString[inputname]) && Dynamicweb.Context.Current.Request.QueryString[inputname] == Convert.ToString(i)) 430 { 431 <option value="@i" data-value='@Convert.ToInt32(i).ToString("N0")' selected="selected">@Convert.ToInt32(i).ToString("N0")+</option> 432 } 433 else 434 { 435 <option value="@i" data-value='@Convert.ToInt32(i).ToString("N0")'>@Convert.ToInt32(i).ToString("N0")+</option> 436 } 437 } 438 else 439 { 440 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString[inputname]) && Dynamicweb.Context.Current.Request.QueryString[inputname] == Convert.ToString(i)) 441 { 442 <option value="@i" data-value='@Convert.ToInt32(i).ToString("N0")' selected="selected">@Convert.ToInt32(i).ToString("N0")</option> 443 } 444 else 445 { 446 <option value="@i" data-value='@Convert.ToInt32(i).ToString("N0")'>@Convert.ToInt32(i).ToString("N0")</option> 447 } 448 } 449 } 450 </select> 451 } 452 453 void RenderTopFilter(string parameter) 454 { 455 if (parameter == "pricemin" || parameter == "pricemax") 456 { 457 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request["pricemin"])) 458 { 459 if (parameter == "pricemin") 460 { 461 @("<div class='search-terms' id='priceFilter'>") 462 @("Pris ") @Dynamicweb.Context.Current.Request[parameter] 463 } 464 465 else 466 { 467 @(" - ") @Dynamicweb.Context.Current.Request[parameter] @(" kr.") <i class="fa fa-times ml-2 pointer" onclick="removeParams(this)" data-tag="pricemin,pricemax"></i> 468 @("</div>") 469 } 470 } 471 } 472 473 else if (parameter == "subsidymin" || parameter == "subsidymax") 474 { 475 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request["subsidymin"])) 476 { 477 if (parameter == "subsidymin") 478 { 479 @("<div class='search-terms' id='subsidyFilter'>") 480 @("Årlig leje ") @Dynamicweb.Context.Current.Request[parameter] 481 } 482 483 else 484 { 485 @(" - ") @Dynamicweb.Context.Current.Request[parameter] @(" kr.") <i class="fa fa-times ml-2 pointer" onclick="removeParams(this)" data-tag="subsidymin,subsidymax"></i> 486 @("</div>") 487 } 488 } 489 } 490 else if (parameter == "etagearealmin" || parameter == "etagearealmax") 491 { 492 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request["etagearealmin"])) 493 { 494 if (parameter == "etagearealmin") 495 { 496 @("<div class='search-terms' id='etagearealFilter'>") 497 @("Etageareal ") @Dynamicweb.Context.Current.Request[parameter] 498 } 499 500 else 501 { 502 @(" - ") @Dynamicweb.Context.Current.Request[parameter] @(" kvm.") <i class="fa fa-times ml-2 pointer" onclick="removeParams(this)" data-tag="etagearealmin,etagearealmax"></i> 503 @("</div>") 504 } 505 } 506 } 507 508 else if (parameter == "grundarealmin" || parameter == "grundarealmax") 509 { 510 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request["grundarealmin"])) 511 { 512 if (parameter == "grundarealmin") 513 { 514 @("<div class='search-terms' id='grundarealFilter'>") 515 @("Grundareal ") @Dynamicweb.Context.Current.Request[parameter] 516 } 517 518 else 519 { 520 @(" - ") @Dynamicweb.Context.Current.Request[parameter] @(" kvm.") <i class="fa fa-times ml-2 pointer" onclick="removeParams(this)" data-tag="grundarealmin,grundarealmax"></i> 521 @("</div>") 522 } 523 } 524 } 525 526 else if (parameter == "subsidykvmmin" || parameter == "subsidykvmmax") 527 { 528 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request["subsidykvmmin"])) 529 { 530 if (parameter == "subsidykvmmin") 531 { 532 @("<div class='search-terms' id='subsidykvmFilter'>") 533 @("Årlig leje kvm ") @Dynamicweb.Context.Current.Request[parameter] 534 } 535 536 else 537 { 538 @(" - ") @Dynamicweb.Context.Current.Request[parameter] @(" kr.") <i class="fa fa-times ml-2 pointer" onclick="removeParams(this)" data-tag="subsidykvmmin,subsidykvmmax"></i> 539 @("</div>") 540 } 541 } 542 } 543 544 else if (parameter == "olinecategory") 545 { 546 547 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request["olinecategory"])) 548 { 549 Dictionary<string, string> erhverType = new Dictionary<string, string>(){ 550 {"OwnUseOffices", "Kontor" }, { "OwnUseStoresAndProductions","Lager + Produktion" }, { "OwnUseRetailAndStores","Detailhandel" }, 551 { "OwnUseParcel", "Grunde" }, { "OwnUseHotelsAndRestaurants", "Hotel + Restaurant" }, { "OwnUseOtherTypes", "Andre typer"}, 552 { "Kontor", "Kontor" }, { "InvestmentStoresAndProductions", "Lager + Produktion" }, { "InvestmentHousingRental", "Boligudlejning" }, 553 { "InvestmentRetailAndStores", "Detailhandel" }, { "InvestmentParcel", "Grunde" }, { "InvestmentHotelsAndRestaurants", "Hotel + Restaurant" }, { "InvestmentOtherTypes", "Andre typer" } 554 }; 555 556 557 foreach (var er in erhverType) 558 { 559 if (Dynamicweb.Context.Current.Request[parameter].Contains(er.Key)) 560 { 561 <div class="search-terms" id="@parameter"> 562 @er.Value <i class="fa fa-times ml-2 pointer" onclick="removeParams(this)" data-tag="@parameter" data-val="@er.Key"></i> 563 </div> 564 } 565 } 566 } 567 } 568 else if (parameter == "propertycategory") 569 { 570 571 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request["propertycategory"])) 572 { 573 Dictionary<string, string> erhverType = new Dictionary<string, string>(){ 574 { "propertycategory", "Blandet Bolig/Erhverv" } 575 }; 576 577 foreach (var er in erhverType) 578 { 579 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request[parameter]) && Dynamicweb.Context.Current.Request[parameter] == er.Value) 580 { 581 <div class="search-terms" id="@parameter"> 582 @er.Value <i class="fa fa-times ml-2 pointer" onclick="removeParams(this)" data-tag="@parameter" data-val="@er.Key"></i> 583 </div> 584 } 585 } 586 } 587 } 588 else if (parameter == "search") 589 { 590 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request["search"])) 591 { 592 <div class="search-terms" id="@parameter"> 593 @Dynamicweb.Context.Current.Request[parameter] <i class="fa fa-times ml-2 pointer" onclick="removeParams(this)" data-tag="@parameter"></i> 594 </div> 595 } 596 } 597 else 598 { 599 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request[parameter])) 600 { 601 Dictionary<string, string> 602 ubudsform = new Dictionary<string, string> 603 (){ 604 {"salg", "Salg" }, { "leje","Leje" } 605 }; 606 607 foreach (var er in ubudsform) 608 { 609 if (Dynamicweb.Context.Current.Request[parameter].Contains(er.Key)) 610 { 611 <div class="search-terms" id="@parameter"> 612 @er.Value <i class="fa fa-times ml-2 pointer" onclick="removeParams(this)" data-tag="@parameter" data-val="@er.Key"></i> 613 </div> 614 } 615 } 616 617 618 } 619 } 620 } 621 622 void RenderSelectValue(string dropdownname, string dropdownvalue, string queryString) 623 { 624 var selected = ""; 625 if (!string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString[queryString]) && Dynamicweb.Context.Current.Request.QueryString[queryString] == dropdownvalue) 626 { 627 selected = "selected"; 628 } 629 630 var current = string.Format("<option value='" + dropdownvalue + "'>" + dropdownname + "</option>", selected); 631 632 @current 633 } 634 635 void RenderSearchForHousing(int searchPageId, string querySearch, string querySearchNameAttr, string queryZipCodeFrom, string queryZipCodeTo, string template, Item SettingsItem, string cssClasses = "") 636 { 637 <div class="main-search-form frontpage @cssClasses"> 638 <div class="dropdown-overlay"></div> 639 <div class="row mb-3 align-items-center"> 640 <div class="col-xs-12 col-md-3 border-right"> 641 <h3>@Translate("Smartpage:Search.Søg bolig", "Søg bolig")</h3> 642 </div> 643 <div class="col-xs-12 col-md-9 home-count d-none d-md-block"> 644 <span class="search-count" id="searchCounter">0</span> <span>@Translate("Smartpage:Search.BoligerTilSalg", "Boliger til salg")</span> 645 </div> 646 </div> 647 648 <form id="main-search-frontpage" class="searchbar-wrapper" action="/Default.aspx" method="GET"> 649 <input type="hidden" name="ID" value='@searchPageId' id="searchPageId-frontpage" disabled="disabled" /> 650 <div class="row form-wrapper no-gutters"> 651 652 <div class="col-xs-12 col-md-5 col-searchbar"> 653 <div class="searchbar"> 654 <input type="text" name="@querySearchNameAttr" id="searchfield-frontpage" class="search-input" placeholder="Postnummer, by, vej eller sagsnummer" tabindex="1" value="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(querySearch)" /> 655 <input type="hidden" id="zipcodefrom-frontpage" name="zipcodefrom" value="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(queryZipCodeFrom)" /> 656 <input type="hidden" id="zipcodeto-frontpage" name="zipcodeto" value="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(queryZipCodeTo)" /> 657 </div> 658 </div> 659 <div class="col-xs-12 col-md-5"> 660 <div class="row no-gutters"> 661 <div class="col-xs-12 col-md-6 input-col"> 662 <div class="dropdown w-overlay"> 663 <button class="btn btn-dropdown dropdown-toggle reverse position-absolute-md" type="button" id="Boligtype-frontpage" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> 664 @Translate("Smartpage:Search.Boligtype", "Boligtype") 665 </button> 666 <div class="dropdown-menu box-shadow bolig-dropdown-container" aria-labelledby="Boligtype"> 667 <ul class="bolig-dropdown list-unstyled"> 668 @{ 669 RenderBoligtypeCheckboxesDropdown(); 670 } 671 </ul> 672 <span class="border-fat"></span> 673 <button class="btn btn-primary js-close-dropdown">@Translate("Smartpage:Search.Anvend", "Anvend")</button> 674 </div> 675 676 </div> 677 678 </div> 679 <div class="col-xs-12 col-md-6 input-col"> 680 <div class="dropdown w-overlay"> 681 <button class="btn btn-dropdown dropdown-toggle reverse position-absolute-md" type="button" id="Pris-frontpage" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> 682 @Translate("Smartpage:Search.Pris", "Pris") 683 </button> 684 <div class="dropdown-menu box-shadow dropdown-price" aria-labelledby="Pris"> 685 <input type="text" class="form-control mb-10 js-auto-thousand js-pricemin-frontpage-input" placeholder='@Translate("Smartpage:Search.Placeholder.MinPris","Min. pris")' /> 686 <select class="form-control js-pricemin-frontpage-select js-input-min-select mb-10"> 687 <option selected="true" disabled="disabled">@Translate("Smartpage:Search.Placeholder.MinPris", "Min. pris")</option> 688 @for (var i = 0; i <= 10000000; i += 100000) 689 { 690 if (i == 10000000) 691 { 692 <option value="@i" data-value='@Convert.ToInt32(i).ToString("N0")+'>@Convert.ToInt32(i).ToString("N0")+</option> 693 } 694 else 695 { 696 <option value="@i" data-value='@Convert.ToInt32(i).ToString("N0")'>@Convert.ToInt32(i).ToString("N0")</option> 697 } 698 } 699 </select> 700 <input type="hidden" id="pricemin-frontpage" name="pricemin" /> 701 702 <input type="text" class="form-control js-auto-thousand js-pricemax-frontpage-input" placeholder='@Translate("Smartpage:Search.Placeholder.MaxPris","Max. pris")' /> 703 <select class="form-control js-pricemax-frontpage-select js-input-max-select"> 704 <option selected="true" disabled="disabled">@Translate("Smartpage:Search.Placeholder.MaxPris", "Max. pris")</option> 705 @for (var i = 0; i <= 10000000; i += 100000) 706 { 707 if (i == 10000000) 708 { 709 <option value="@i" data-value='@Convert.ToInt32(i).ToString("N0")+'>@Convert.ToInt32(i).ToString("N0")+</option> 710 } 711 else 712 { 713 <option value="@i" data-value='@Convert.ToInt32(i).ToString("N0")'>@Convert.ToInt32(i).ToString("N0")</option> 714 } 715 } 716 </select> 717 <input type="hidden" id="pricemax-frontpage" name="pricemax" /> 718 <button class="btn btn-primary js-close-dropdown mt-3">@Translate("Smartpage:Search.Anvend", "Anvend")</button> 719 </div> 720 </div> 721 </div> 722 </div> 723 </div> 724 <div class="col-xs-12 col-md-2 d-none d-md-block"> 725 <button type="submit" class="btn btn-block btn-search"><i class="fa fa-search"></i> @Translate("Smartpage:Search.Søg", "Søg")</button> 726 </div> 727 </div> 728 729 <div class="row moresearch-btn no-gutters"> 730 <div class="col-sm-12"> 731 <div class="row align-items-center no-gutters"> 732 <div class="col-12 col-md-4"> 733 <button class="btn-blank js-search-collapse" type="button" data-toggle="collapse" data-target="#moreSearch" aria-expanded="false" aria-controls="moreSearch"> 734 <span class="moreSearch-text"><i class="fas fa-plus open-close"></i> <span class="not-open">@Translate("Smartpage:Search.Flere søgemuligheder", "Flere søgemuligheder")</span> <span class="open"><span class="js-filter-count">0</span> @Translate("Smartpage:Search.FiltreAnvendt", "filtre anvendt") </span></span> 735 </button> 736 </div> 737 <div class="col-6 col-md-2 mb-xs-4"> 738 <a class="js-reset reset-btn">@Translate("Smartpage:Search.NulstilValg", "Nulstil valg")</a> 739 </div> 740 </div> 741 742 <div class="collapse" id="moreSearch"> 743 <h4 class="mt-20"><b>@Translate("Smartpage:Search.Bolig", "Bolig")</b></h4> 744 <div class="row align-items-end mb-30"> 745 <div class="col-12 col-sm-6 col-lg-3 mb-3 mb-lg-0"> 746 <div class="filter-container row"> 747 <label class="d-block col-12">@Translate("Smartpage:Search.Boligareal", "Boligareal")</label> 748 <div class="col-6 pr-sm-0 pr-2"> 749 <input type="text" name="boligarealmin" id="boligarealmin-frontpage" class="form-control js-boligarealmin-frontpage-input js-count" placeholder='@Translate("Smartpage:Search.Placeholder.Minm2","Min. m2")' /> 750 <select class="form-control js-boligarealmin-frontpage-select js-count"> 751 <option selected="true" disabled="disabled">@Translate("Smartpage:Search.Placeholder.Minm2", "Min. m2")</option> 752 @for (var i = 0; i <= 300; i += 10) 753 { 754 if (i == 300) 755 { 756 <option value="@i">@i+</option> 757 } 758 else 759 { 760 <option value="@i">@i</option> 761 } 762 } 763 </select> 764 </div> 765 <div class="col-6 pl-sm-0 pl-2"> 766 <input type="text" name="boligarealmax" id="boligarealmax-frontpage" class="form-control js-boligarealmax-frontpage-input js-count" placeholder='@Translate("Smartpage:Search.Placeholder.Maxm2","Max. m2")' /> 767 <select class="form-control js-boligarealmax-frontpage-select js-count"> 768 <option selected="true" disabled="disabled">@Translate("Smartpage:Search.Placeholder.Maxm2", "Max. m2")</option> 769 @for (var i = 0; i <= 300; i += 10) 770 { 771 if (i == 300) 772 { 773 <option value="@i">@i+</option> 774 } 775 else 776 { 777 <option value="@i">@i</option> 778 } 779 } 780 </select> 781 </div> 782 </div> 783 </div> 784 <div class="col-12 col-sm-6 col-lg-3 mb-3 mb-lg-0"> 785 <div class="filter-container row"> 786 <label class="d-block col-12">@Translate("Smartpage:Search.Grundareal", "Grundareal")</label> 787 <div class="col-6 pr-sm-0 pr-2"> 788 <input type="text" name="grundarealmin" id="grundarealmin-frontpage" class="form-control js-grundarealmin-frontpage-input js-count" placeholder='@Translate("Smartpage:Search.Placeholder.Minm2","Min. m2")' /> 789 <select class="form-control js-grundarealmin-frontpage-select js-count"> 790 <option selected="true" disabled="disabled">@Translate("Smartpage:Search.Placeholder.Minm2", "Min. m2")</option> 791 @for (var i = 0; i <= 10000; i += 100) 792 { 793 if (i == 10000) 794 { 795 <option value="@i">@i+</option> 796 } 797 else 798 { 799 <option value="@i">@i</option> 800 } 801 } 802 </select> 803 </div> 804 <div class="col-6 pl-sm-0 pl-2"> 805 <input type="text" name="grundarealmax" id="grundarealmax-frontpage" class="form-control js-grundarealmax-frontpage-input js-count" placeholder='@Translate("Smartpage:Search.Placeholder.Maxm2","Max. m2")' /> 806 <select class="form-control js-grundarealmax-frontpage-select js-count"> 807 <option selected="true" disabled="disabled">@Translate("Smartpage:Search.Placeholder.Maxm2", "Max. m2")</option> 808 @for (var i = 0; i <= 10000; i += 100) 809 { 810 if (i == 10000) 811 { 812 <option value="@i">@i+</option> 813 } 814 else 815 { 816 <option value="@i">@i</option> 817 } 818 } 819 </select> 820 </div> 821 </div> 822 </div> 823 <div class="col-12 col-sm-6 col-lg-3 mb-3 mb-lg-0"> 824 <div class="filter-container row"> 825 <label class="d-block col-12">Antal rum</label> 826 827 <div class="col-6 pr-sm-0 pr-2"> 828 <select name="roomsmin" id="roomsmin-frontpage" class="form-control reverse js-count"> 829 <option selected="true" disabled="disabled">@Translate("Smartpage:Search.Placeholder.Min", "Min")</option> 830 <option value="1">1</option> 831 <option value="2">2</option> 832 <option value="3">3</option> 833 <option value="4">4</option> 834 <option value="5+">5+</option> 835 </select> 836 </div> 837 <div class="col-6 pl-sm-0 pl-2"> 838 <select name="roomsmax" id="roomsmax-frontpage" class="form-control reverse js-count"> 839 <option selected="true" disabled="disabled">@Translate("Smartpage:Search.Placeholder.Max", "Max")</option> 840 <option value="1">1</option> 841 <option value="2">2</option> 842 <option value="3">3</option> 843 <option value="4">4</option> 844 <option value="5+">@Translate("Smartpage:Rooms.5", "5")</option> 845 </select> 846 </div> 847 </div> 848 </div> 849 <div class="col-12 col-sm-6 col-lg-3 mb-3 mb-lg-0"> 850 <div class="row"> 851 <div class="col-12"> 852 <div class="filter-container"> 853 <label class="d-block">Energimærke</label> 854 <select name="energylabel" id="energylabel-frontpage" class="form-control reverse js-count"> 855 <option disabled selected="selected">@Translate("Smartpage:Search.Vælg", "Vælg")</option> 856 <option value="01">G</option> 857 <option value="02">F</option> 858 <option value="03">E</option> 859 <option value="04">D</option> 860 <option value="05">C</option> 861 <option value="06">B</option> 862 <option value="07">A</option> 863 <option value="08">A2010</option> 864 <option value="09">A2015</option> 865 <option value="10">A2020+</option> 866 </select> 867 </div> 868 </div> 869 </div> 870 </div> 871 <div class="col-12 col-sm-6 col-lg-3 mt-3"> 872 <h4 class=""><b>@Translate("Smartpage:Search.Økonomi", "Økonomi")</b></h4> 873 <div class="filter-container row"> 874 <label class="d-block col-12">@Translate("Smartpage:Search.Ejerudgift/boligydelse pr. måned", "Ejerudgift/boligydelse pr. måned")</label> 875 <div class="col-6 pr-sm-0 pr-2"> 876 <input type="text" name="subsidymin" id="subsidymin-frontpage" class="form-control js-subsidymin-frontpage-input js-count" placeholder='@Translate("Smartpage:Search.Placeholder.MinDKK","Min. DKK")' /> 877 <select class="form-control js-subsidymin-frontpage-select js-count"> 878 <option selected="true" disabled="disabled">@Translate("Smartpage:Search.Placeholder.MinDKK", "Min. DKK")</option> 879 @for (var i = 0; i <= 25000; i += 1250) 880 { 881 if (i == 25000) 882 { 883 <option>@Convert.ToInt32(i).ToString("N0")+</option> 884 } 885 else 886 { 887 <option>@Convert.ToInt32(i).ToString("N0")</option> 888 } 889 } 890 </select> 891 </div> 892 <div class="col-6 pl-sm-0 pl-2"> 893 <input type="text" name="subsidymax" id="subsidymax-frontpage" class="form-control js-subsidymax-frontpage-input js-count" placeholder='@Translate("Smartpage:Search.Placeholder.MaxDKK","Max. DKK")' /> 894 <select class="form-control js-subsidymax-frontpage-select js-count"> 895 <option selected="true" disabled="disabled">@Translate("Smartpage:Search.Placeholder.MaxDKK", "Max. DKK")</option> 896 @for (var i = 0; i <= 25000; i += 1250) 897 { 898 if (i == 25000) 899 { 900 <option value="@Convert.ToInt32(i)">@Convert.ToInt32(i).ToString("N0")+</option> 901 } 902 else 903 { 904 <option value="@Convert.ToInt32(i)">@Convert.ToInt32(i).ToString("N0")</option> 905 } 906 } 907 </select> 908 </div> 909 </div> 910 </div> 911 <div class="col-12 col-sm-6 col-lg-4 offset-lg-5 mt-3 mt-sm-0"> 912 <button type="submit" class="btn btn-block btn-search"><i class="fa fa-search"></i> @Translate("Smartpage:Search.AnvendFiltre", "Anvend filtre")</button> 913 </div> 914 </div> 915 </div> 916 </div> 917 </div> 918 919 <div class="row d-block d-md-none form-wrapper no-gutters"> 920 <div class="col-xs-12 col-md-2"> 921 <button type="submit" class="btn btn-block btn-search btn-mobile-search">@Translate("Smartpage:Search.SøgBolig", "Søg Bolig")<i class="fa fa-search cta-icon"></i></button> 922 </div> 923 </div> 924 </form> 925 <div class="front-page-actions d-md-none"> 926 <div> 927 <button class="btn btn-block btn-search btn-mobile-search js-search-mobile">@Translate("Smartpage:Search.SøgBolig", "Søg Bolig")<i class="fa fa-search cta-icon"></i></button> 928 </div> 929 <div> 930 @{ 931 string brokerSearchId = SettingsItem != null ? Dynamicweb.Core.Converter.ToString(SettingsItem["Maeglersogning"]).Replace("Default.aspx?Id=", "") : ""; 932 string ctaText = Translate("Smartpage.Frontpage.Mobile.FindBroker", "FIND EJENDOMSMÆGLER"); 933 <form method="GET" action="/Default.aspx"> 934 <input name="id" value="@brokerSearchId" type="hidden" /> 935 <div class="icon-wrapper-wclick"> 936 <i class="fas fa-search ta-submit-on-icon-click"></i> 937 <input class="box-cta-input ta-postnummer ta-submit-on-select ta-submit-on-enter" name="q" type="text" placeholder="@ctaText" onfocus="this.placeholder = ''" onblur="this.placeholder='@ctaText'" /> 938 </div> 939 </form> 940 } 941 </div> 942 <div> 943 <a href="javascript:panelSalgsvurdering('Hovedmenu')" class="btn btn-orange btn-block">@Translate("Smartpage:Frontpage.Mobile.GetFreeAppraisal", "BESTIL GRATIS VURDERING")<i class="cta-icon fa fa-angle-right"></i></a> 944 </div> 945 </div> 946 </div> 947 948 } 949 Custom.Integration.Brokers.Models.BrokerEmployee GetBrokerFromCurrentProduct() 950 { 951 string productId = Dynamicweb.Context.Current.Request["ProductId"]; 952 953 if (string.IsNullOrWhiteSpace(productId)) 954 { 955 return null; 956 } 957 958 var propertyProduct = Dynamicweb.Ecommerce.Services.Products.GetProductById(productId, string.Empty, true); 959 if (propertyProduct == null) 960 { 961 return null; 962 } 963 964 string employee = Dynamicweb.Core.Converter.ToString( 965 Dynamicweb.Ecommerce.Services.Products.GetProductFieldValue(propertyProduct, "xAktoererMaeglerKontaktEmail") 966 ); 967 string storeId = Dynamicweb.Core.Converter.ToString( 968 Dynamicweb.Ecommerce.Services.Products.GetProductFieldValue(propertyProduct, "xButikID") 969 ); 970 971 if (string.IsNullOrWhiteSpace(employee) || string.IsNullOrWhiteSpace(storeId)) 972 { 973 return null; 974 } 975 976 return Custom.Integration.Brokers.Search.GetEmployee(storeId, employee); 977 } 978 979 string GetAgentTitleFromCurrentProduct() 980 { 981 var propBroker = GetBrokerFromCurrentProduct(); 982 983 if (propBroker?.Broker == null) 984 { 985 return string.Empty; 986 } 987 988 if (!string.IsNullOrEmpty(propBroker.Broker.CompanyName)) 989 { 990 return propBroker.Broker.CompanyName; 991 } 992 993 return propBroker.Broker.Name ?? string.Empty; 994 } 995 996 string GetMasterBrokerUrlFromCurrentProduct() 997 { 998 var propBroker = GetBrokerFromCurrentProduct(); 999 1000 var itemId = propBroker?.Broker?.ItemId; 1001 var itemType = propBroker?.Broker?.ItemType; 1002 1003 if (string.IsNullOrWhiteSpace(itemId) || string.IsNullOrWhiteSpace(itemType)) 1004 { 1005 return string.Empty; 1006 } 1007 var brokerItem = Dynamicweb.Content.Items.ItemManager.Storage.GetById(itemType, itemId); 1008 1009 if (brokerItem == null) 1010 { 1011 return string.Empty; 1012 } 1013 1014 var websiteId = Dynamicweb.Core.Converter.ToInt32(brokerItem["WebsiteId"]); 1015 var page = Dynamicweb.Content.Services.Pages.GetFirstPageForArea(websiteId); 1016 return Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl("Default.aspx?Id=" + page?.ID); 1017 } 1018 } 1019 1020 @{ 1021 1022 var settingsItem = ItemManager.Storage.GetById("Delte_Egenskaber", "1"); 1023 var settingsActivateGreenMobility = Dynamicweb.Frontend.PageView.Current().AreaSettings.GetBoolean("Activate_Green_Mobility"); 1024 1025 var iconPath = "/Files/Templates/Designs/rm/assets/images/svg/"; 1026 var iconPngPath = "/Files/Templates/Designs/rm/assets/images/icons/"; 1027 var imagePath = "/Files/Images/RM billeder/"; 1028 string fallbackImage = "/Files/Templates/Designs/rm/assets/images/na-real.png"; 1029 1030 string productId = GetString("Ecom:Product.ID"); 1031 var product = Dynamicweb.Ecommerce.Services.Products.GetProductById(productId, string.Empty, true); 1032 string propCategory = GetString("Ecom:Product:Field.xEjendomEjendomskategori"); 1033 string propType = GetString("Ecom:Product:Field.xEjendomEjendomstype"); 1034 string propTypeCategory = ""; 1035 if (!string.IsNullOrEmpty(propType)) 1036 { 1037 propTypeCategory = RealMaeglerne.Dynamicweb.PropertyClassification.GetCategoryByTypeName(propType).ToLower(); 1038 } 1039 1040 string propTypeDisplay = !string.IsNullOrWhiteSpace(propCategory) ? propCategory : propTypeCategory; 1041 bool isRental = (propCategory != null && GetString("Ecom:Product:Field.xUdbudsForm").ToLower() == "leje" && !propCategory.Contains("erhverv")) || Converter.ToBoolean(Dynamicweb.Context.Current.Request["Udlejning"]); 1042 1043 string Employee = GetString("Ecom:Product:Field.xAktoererMaeglerKontaktEmail"); 1044 Custom.Integration.Brokers.Models.BrokerEmployee propBroker = Custom.Integration.Brokers.Search.GetEmployee(GetString("Ecom:Product:Field.xButikID"), Employee); 1045 var employeeItem = Dynamicweb.Content.Items.ItemManager.Storage.GetById(propBroker?.Employee?.ItemType, propBroker?.Employee?.ItemId); 1046 var brokerItem = Dynamicweb.Content.Items.ItemManager.Storage.GetById(propBroker?.Broker?.ItemType, propBroker?.Broker?.ItemId); 1047 1048 Custom.Tracking.Providers.TrackingProvider.AddData("PropertyView", productId, GetString("Ecom:Product:Field.xREID")); 1049 var popularityMetrics = Custom.Tracking.Providers.TrackingProvider.GetPopularityMetrics(productId); 1050 1051 bool isValidForGreenMobility = false; 1052 1053 if (settingsActivateGreenMobility) 1054 { 1055 var settingsGreenMobilityPostalCodes = Dynamicweb.Frontend.PageView.Current().AreaSettings.GetItems("Green_Mobility_Postnumre"); 1056 int postalCode = GetInteger("Ecom:Product:Field.xEjendomAdressePostnummer"); 1057 1058 isValidForGreenMobility = settingsGreenMobilityPostalCodes.Any(range => 1059 { 1060 int start = Convert.ToInt32(range.GetRawValue("Start")); 1061 int end = Convert.ToInt32(range.GetValue("Slut")); 1062 1063 return end > 0 ? postalCode >= start && postalCode <= end : postalCode == start; 1064 }); 1065 } 1066 1067 Dictionary<string, string> edhFiles = RealMaeglerne.Library.BoligManager.GetEDHFilesCompact(product); 1068 1069 var origin = $"{Context.Current.Session["DP"]}Boligvisning (sektion: galleri)"; 1070 1071 } 1072 1073 <script> 1074 // Set RMAPI (defined in master) values relevant for this page 1075 if(RMAPI) { 1076 RMAPI.ButikId = "@GetString("Ecom:Product:Field.xButikID")"; 1077 RMAPI.Boligvisning = true; 1078 RMAPI.SagsNr = "@productId"; 1079 RMAPI.MarkerColor = "#F06F18"; 1080 } 1081 </script> 1082 1083 <div propertypage-top role="main" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.PropertyMain", "Ejendomsvisning hovedindhold"))"> 1084 @*SECTION: Breadcrumbs*@ 1085 1086 <nav class="container breadcrumbs" role="navigation" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.Breadcrumb", "Brødkrumme navigation"))"> 1087 <div class="divider-blue d-none d-md-block" aria-hidden="true"></div> 1088 <div class="row py-md-3 py-2"> 1089 <div class="col-6"> 1090 @{ 1091 int searchPageId = GetPageSettingsPageId("Boligside"); 1092 if (searchPageId == 0) 1093 { 1094 searchPageId = GetWebsiteSettingsPageId("Boligside"); 1095 } 1096 } 1097 <a href="/Default.aspx?ID=@searchPageId" class="breadcrumb-item" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.BackToSearch", "Tilbage til boligsøgning"))"> 1098 @Translate("Custom:Propertypage.Breadcrumbs.Search", "Søg bolig") 1099 </a> 1100 @if (propBroker != null) 1101 { 1102 <a href="/Default.aspx?ID=@searchPageId&search=@propBroker.Broker.City" class="breadcrumb-item" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.SearchInCity", "Søg boliger i")) @propBroker.Broker.City"> 1103 @propBroker.Broker.City 1104 </a> 1105 } 1106 </div> 1107 <div class="col-6 text-right"> 1108 <a class="breadcrumb-link cursor-pointer" data-share-text="@Translate("Custom:Propertypage.Sharelink.ShareText", "Se denne bolig")" data-alert-text="@Translate("Custom:Propertypage.Sharelink.AlertText", "Link kopieret til udklipsholder!")" onclick="shareProperty(event, this)" role="button" tabindex="0" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.ShareProperty", "Del denne bolig"))" onkeypress="if(event.key === 'Enter' || event.key === ' ') shareProperty(event, this)"> 1109 <img class="d-md-none d-inline mr-1" src="@(iconPath + "icon-share.svg")" alt="" aria-hidden="true" /> 1110 <img class="d-none d-md-inline mr-1" src="@(iconPath + "icon-share-desktop.svg")" alt="" aria-hidden="true" /> 1111 @Translate("Custom:Propertypage.Breadcrumbs.Share", "Del bolig") 1112 </a> 1113 </div> 1114 </div> 1115 <div class="divider-blue d-none d-md-block" aria-hidden="true"></div> 1116 </nav> 1117 1118 @*SECTION: Images*@ 1119 @{ 1120 var boligManager = new RealMaeglerne.Library.BoligManager(Pageview); 1121 RealMaeglerne.Library.Models.Bolig bolig = boligManager.CreateBolig(product, true); 1122 1123 1124 bool useEsoftImages = settingsItem != null ? Converter.ToBoolean(settingsItem["SpUseEsoftImages"]) : false; 1125 bool hasVideos = bolig.Videos != null && bolig.Videos.Any(); 1126 bool hasSlideShow = bolig.EsoftAssets != null && bolig.EsoftAssets.HasSlideShows; 1127 bool hasBlueprints = bolig.Plantegninger != null && bolig.Plantegninger.Any(); 1128 var panoramas = bolig.EsoftAssets?.PanoramasHtml5? 1129 .Where(x => Converter.ToInt32(x.ListOrder) > 0 && x.EmbedAssets?.Count > 0) 1130 .ToList() ?? new List<Custom.Esoft.Models.EsoftAssetContainer>(); 1131 bool hasPanorama = panoramas.Any(); 1132 1133 string mapLng = GetString("Ecom:Product:Field.xEjendomGeoinfoWGS84Y.Value.Raw").Replace(",", "."); 1134 string mapLat = GetString("Ecom:Product:Field.xEjendomGeoinfoWGS84X.Value.Raw").Replace(",", "."); 1135 bool hasMapCoordinates = !string.IsNullOrEmpty(mapLng) && !string.IsNullOrEmpty(mapLat); 1136 1137 1138 List<Bolig.CaseAsset> images = bolig.ImagesOfProperty != null ? bolig.ImagesOfProperty : new List<Bolig.CaseAsset>(); 1139 1140 @*Make sure we have 3 images to display on frontpage*@ 1141 while (images.Count < 3) 1142 { 1143 images.Add(new Bolig.CaseAsset() { ImageXs = fallbackImage, ImageSm = fallbackImage, ImageMd = fallbackImage, ImageLg = fallbackImage, ImageXl = fallbackImage }); 1144 } 1145 1146 @*Swap first and second image in list for correct large primary image on desktop*@ 1147 1148 List<Bolig.CaseAsset> frontImages = images.Take(3).ToList(); 1149 1150 if (!hasVideos && Pageview.Device == Dynamicweb.Frontend.Devices.DeviceType.Desktop) 1151 { 1152 (frontImages[0], frontImages[1]) = (frontImages[1], frontImages[0]); 1153 } 1154 1155 var primaryImage = frontImages.First(); 1156 1157 1158 string primaryVideo = string.Empty; 1159 1160 if (hasVideos) 1161 { 1162 primaryVideo = bolig.Videos.First(); 1163 } 1164 } 1165 1166 <section class="container image-section pt-3 pb-3" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.ImageGallery", "Billedegalleri"))"> 1167 1168 <div class="image-wrapper position-relative h-100 w-100"> 1169 <div class="main-image position-relative"> 1170 @if (!string.IsNullOrEmpty(primaryVideo)) 1171 { 1172 <label for="video" class="cursor-pointer mb-0" data-toggle="modal" data-target="#assets-modal"> 1173 <video class="js-primary-video" width="100%" height="100%" autoplay muted loop playsinline preload="auto" poster="@HtmlEncoder.HtmlAttributeEncode(primaryImage.ImageMd)" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.PropertyVideo", "Ejendomsvideo for")) @HtmlEncoder.HtmlAttributeEncode(GetString("Ecom:Product:Field.xEjendomAdresseAdresseLinie"))"> 1174 <source src="@primaryVideo" type="video/mp4" /> 1175 @Translate("Custom:Accessibility.VideoNotSupported", "Din browser understøtter ikke HTML5 video.") 1176 </video> 1177 </label> 1178 } 1179 else 1180 { 1181 <img class="img-fluid w-100" src="@primaryImage.ImageLg" data-toggle="modal" data-target="#assets-modal" alt="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom.Propertypage.PrimaryImage.AltTag", "Image of realestate"))" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.OpenImageGallery", "Åbn billedegalleri"))" /> 1182 } 1183 </div> 1184 1185 @{ 1186 var imageCount = 0; 1187 int skip = !string.IsNullOrEmpty(primaryVideo) ? 0 : 1; 1188 } 1189 1190 @foreach (var image in frontImages.Skip(skip).Take(2)) 1191 { 1192 <div class="cursor-pointer secondary-image position-relative" data-toggle="modal" data-target="#assets-modal" role="button" tabindex="0" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.OpenImageGallery", "Åbn billedegalleri"))" onkeypress="if(event.key === 'Enter' || event.key === ' ') { $(this).click(); }"> 1193 <img class="img-fluid w-100 h-100" src="@image.ImageLg" alt="@Translate("Custom:Accessibility.PropertyImage", "Ejendomsbillede") @(imageCount + 2) @Translate("Custom:Accessibility.Of", "af") @(images.Count() + 1)" /> 1194 @if (imageCount == 1) 1195 { 1196 <button type="button" class="d-block d-lg-none btn btn-modal position-absolute" data-toggle="modal" data-target="#assets-modal" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.ViewAllImages", "Vis alle billeder"))"> 1197 @string.Format(Translate("Custom:Propertypage.AssetsModal.Button.Mobile.Open", "+ {0} billeder"), images.Count()) 1198 </button> 1199 1200 <button type="button" class="d-none d-md-block btn btn-modal position-absolute" data-toggle="modal" data-target="#assets-modal" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.ViewAllImages", "Vis alle billeder"))"> 1201 <img class="image-button" src="@(iconPath + "icon-images.svg")" alt="" aria-hidden="true" /> 1202 @string.Format(Translate("Custom:Propertypage.AssetsModal.Button.Desktop.Open", "Se alle {0} billeder"), images.Count()) 1203 </button> 1204 } 1205 @if (bolig.AabentHus && imageCount == 0) 1206 { 1207 var upcomingOpenHouses = boligManager.KommendeAabnehuse(bolig); 1208 1209 <div class="open-house position-absolute d-none d-md-flex" onclick="stopPropagation(event)" role="region" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.OpenHouseInfo", "Åbent hus information"))"> 1210 <div class="section-header semi-bold mb-0"> 1211 @Translate("Custom.Propertypage.OpenHouseSection.Header", "Åbent hus") 1212 </div> 1213 <div class="open-house-dates d-flex align-items-center"> 1214 @if (upcomingOpenHouses.Count() > 1) 1215 { 1216 <select id="openhouse-selector-desktop" class="open-house-selector js-aabenthus-liste-val" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.SelectOpenHouse", "Vælg åbent hus tidspunkt"))"> 1217 @foreach (var openHouse in upcomingOpenHouses) 1218 { 1219 var json = System.Text.Json.JsonSerializer.Serialize(openHouse); 1220 1221 <option class="open-house-selector__option" data-aabent-hus="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(json)"> 1222 @openHouse.Dato.ToString("d. MMM", Pageview.Area.CultureInfo) kl. @openHouse.FraKlokken.Substring(0, 5) 1223 </option> 1224 } 1225 </select> 1226 } 1227 else 1228 { 1229 var primaryOpenHouse = upcomingOpenHouses.First(); 1230 var json = System.Text.Json.JsonSerializer.Serialize(primaryOpenHouse); 1231 1232 <div class="open-house-text"> 1233 <span class="js-aabenthus-date-val">@primaryOpenHouse.Dato.ToString("d. MMM", Pageview.Area.CultureInfo)</span> 1234 1235 @if (!string.IsNullOrEmpty(primaryOpenHouse.TidspunktFormateret)) 1236 { 1237 <div class="d-inline-block js-aabenthus-time-val js-primary-open-house" data-aabent-hus="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(json)"> 1238 @Translate("Custom.Propertypage.OpenHouseSection.Kl", "kl.") @primaryOpenHouse.FraKlokken.Substring(0, 5)@(" - ")@primaryOpenHouse.TilKlokken.Substring(0, 5) 1239 </div> 1240 } 1241 </div> 1242 } 1243 @if (upcomingOpenHouses.Any(oh => oh.Tilmelding)) 1244 { 1245 <a class="btn btn-orange" href="javascript:panelAabenthus('@origin');"> 1246 @Translate("Custom.Propertypage.OpenHouseSection.SignupButton.Label", "Tilmeld") 1247 </a> 1248 } 1249 </div> 1250 </div> 1251 } 1252 @if (popularityMetrics.Any() && imageCount == 0) 1253 { 1254 <div class="popular position-absolute d-none d-md-flex" role="region" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.PopularityMetrics", "Popularitetsmålinger"))"> 1255 <div class="popular-header"> 1256 @Translate("Custom.Propertypage.PopularSection.Header", "Populær") 1257 </div> 1258 <div class="popular-metrics-wrapper js-popular-metrics-wrapper"> 1259 @foreach (var metric in popularityMetrics) 1260 { 1261 1262 <div class="popular-metric d-inline-flex align-items-center"> 1263 <div class="bold">@metric.Value</div> 1264 <div class="popular-metric-label">@Translate($"Custom.Propertypage.PopularSection.{metric.Key}.Label", "har interageret med denne bolig")</div> 1265 </div> 1266 } 1267 </div> 1268 </div> 1269 } 1270 </div> 1271 imageCount++; 1272 } 1273 1274 </div> 1275 <div class="image-wrapper__subtext d-md-block d-none"> 1276 @if (propBroker != null) 1277 { 1278 <div class="broker-card d-none d-md-flex align-items-center" role="complementary" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.BrokerInfo", "Mæglerinformation"))"> 1279 @if (employeeItem != null) 1280 { 1281 string image = Converter.ToString(employeeItem["BilledeUrl"]); 1282 <img src="@image" alt="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.BrokerImage", "Billede af mægler")) @HtmlEncoder.HtmlAttributeEncode(propBroker.Employee.Name))" /> 1283 } 1284 <div class="d-flex flex-column justify-content-around pl-2"> 1285 <div class="bold">@Translate("Custom:Propertypage.Images.Subtext.Broker.Text", "Har du nogle spørgsmål?")</div> 1286 @if (!string.IsNullOrEmpty(propBroker?.Employee?.PhoneMobile) && Converter.ToBoolean(employeeItem["VisMobilNrPaaSager"])) 1287 { 1288 <div class="regular"> 1289 @if (!string.IsNullOrEmpty(propBroker?.Employee?.Name)) 1290 { 1291 @Translate("Custom.Propertypage.Images.Subtext.Broker.CallName", "Ring til") 1292 <span>@propBroker.Employee.Name</span> 1293 @Translate("Custom.Propertypage.Images.Subtext.Broker.CallName.PostText", "på") 1294 } 1295 else 1296 { 1297 @Translate("Custom.Propertypage.Images.Subtext.Broker.Call", "Ring på") 1298 } 1299 <span>@RealMaeglerne.Library.Helper.FormatPhoneNumber(propBroker.Employee.PhoneMobile)</span> 1300 </div> 1301 } 1302 else if (!string.IsNullOrEmpty(propBroker?.Broker?.Telephone)) 1303 { 1304 <div class="regular"> 1305 @if (!string.IsNullOrEmpty(propBroker?.Employee?.Name)) 1306 { 1307 @Translate("Custom.Propertypage.Images.Subtext.Broker.CallName", "Ring til") 1308 <span>@propBroker.Employee.Name</span> 1309 @Translate("Custom.Propertypage.Images.Subtext.Broker.CallName.PostText", "på") 1310 } 1311 else 1312 { 1313 @Translate("Custom.Propertypage.Images.Subtext.Broker.Call", "Ring på") 1314 } 1315 <span>@RealMaeglerne.Library.Helper.FormatPhoneNumber(propBroker.Broker.Telephone)</span> 1316 </div> 1317 } 1318 </div> 1319 </div> 1320 } 1321 </div> 1322 1323 1324 <div class="modal fade images-modal" id="images-modal" tabindex="-1" aria-labelledby="images-modal-label" aria-hidden="true" aria-modal="true"> 1325 <div class="modal-dialog"> 1326 <div class="modal-content"> 1327 <div class="position-absolute d-flex flex-column images-navigation"> 1328 <button type="button" class="close-round mb-5" data-dismiss="modal" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.CloseModal", "Luk vindue"))"> 1329 <img src="@(iconPath + "icon-minimize.svg")" alt="" aria-hidden="true" /> 1330 </button> 1331 <div class="d-flex flex-column"> 1332 <button id="image-prev-images-modal" type="button" class="close-round mb-2" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.PreviousImage", "Forrige billede"))"> 1333 <img src="@(iconPath + "icon-arrow-narrow-up.svg")" alt="" aria-hidden="true" /> 1334 </button> 1335 <button id="image-next-images-modal" type="button" class="close-round" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.NextImage", "Næste billede"))"> 1336 <img src="@(iconPath + "icon-arrow-narrow-down.svg")" alt="" aria-hidden="true" /> 1337 </button> 1338 </div> 1339 </div> 1340 <div class="image-gallery large-images"> 1341 @{ 1342 int largeImageCounter = 0; 1343 } 1344 1345 @foreach (var image in images) 1346 { 1347 var largeImageId = "image_large_" + largeImageCounter; 1348 <img id="@largeImageId" class="img-fluid" src="@fallbackImage" data-src="@image.ImageXl" /> 1349 largeImageCounter++; 1350 } 1351 </div> 1352 </div> 1353 </div> 1354 </div> 1355 1356 <div class="modal fade" id="assets-modal" tabindex="-1" aria-labelledby="assets-modal-label" aria-hidden="true" aria-modal="true" role="dialog"> 1357 <div class="modal-dialog"> 1358 <div class="modal-content h-100 mh-100"> 1359 1360 @if (hasVideos || hasSlideShow) 1361 { 1362 <input type="radio" id="video" name="category" class="category-radio" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.SelectVideoCategory", "Vælg video kategori"))"> 1363 } 1364 1365 <input type="radio" id="images" name="category" class="category-radio" checked aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.SelectImagesCategory", "Vælg billeder kategori"))"> 1366 1367 @if (hasBlueprints) 1368 { 1369 <input type="radio" id="blueprint" name="category" class="category-radio" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.SelectBlueprintCategory", "Vælg plantegning kategori"))"> 1370 } 1371 1372 @if (hasMapCoordinates) 1373 { 1374 <input type="radio" id="mapradio" name="category" class="category-radio" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.SelectMapCategory", "Vælg kort kategori"))"> 1375 } 1376 1377 @if (hasPanorama) 1378 { 1379 <input type="radio" id="view360" name="category" class="category-radio" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.Select360Category", "Vælg 360 graders visning kategori"))"> 1380 } 1381 1382 <div class="modal-header"> 1383 1384 <div class="nav-wrapper"> 1385 <div class="category-scroll"> 1386 <div class="category-buttons"> 1387 @if (hasVideos || hasSlideShow) 1388 { 1389 <label for="video" class="category-btn" tabindex="0" role="button" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.ShowVideoContent", "Vis video indhold"))" onkeypress="if(event.key === 'Enter' || event.key === ' ') { document.getElementById('video').click(); }"> 1390 <span class="category-icon icon-video" aria-hidden="true"></span> 1391 <span>@Translate("Custom.Propertypage.AssetsModal.Category.Video", "Video")</span> 1392 </label> 1393 } 1394 1395 <label for="images" class="category-btn" tabindex="0" role="button" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.ShowImagesContent", "Vis billeder"))" onkeypress="if (event.key === 'Enter' || event.key === ' ') { document.getElementById('images').click(); }"> 1396 <span class="category-icon icon-image" aria-hidden="true"></span> 1397 <span>@Translate("Custom.Propertypage.AssetsModal.Category.Images", "Billeder")</span> 1398 </label> 1399 1400 @if (hasBlueprints) 1401 { 1402 <label for="blueprint" class="category-btn" tabindex="0" role="button" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.ShowBlueprintContent", "Vis plantegning"))" onkeypress="if(event.key === 'Enter' || event.key === ' ') { document.getElementById('blueprint').click(); }"> 1403 <span class="category-icon icon-plan" aria-hidden="true"></span> 1404 <span>@Translate("Custom.Propertypage.AssetsModal.Category.Plan", "Plantegning")</span> 1405 </label> 1406 } 1407 1408 @if (hasMapCoordinates) 1409 { 1410 <label for="mapradio" class="js-init-map category-btn" tabindex="0" role="button" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.ShowMapContent", "Vis kort"))" onkeypress="if(event.key === 'Enter' || event.key === ' ') { document.getElementById('mapradio').click(); }"> 1411 <span class="category-icon icon-map" aria-hidden="true"></span> 1412 <span>@Translate("Custom.Propertypage.AssetsModal.Category.Map", "Vis på kort")</span> 1413 </label> 1414 } 1415 1416 @if (hasPanorama) 1417 { 1418 <label for="view360" class="category-btn" tabindex="0" role="button" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.Show360Content", "Vis 360 graders visning"))" onkeypress="if(event.key === 'Enter' || event.key === ' ') { document.getElementById('view360').click(); }"> 1419 <span class="category-icon icon-360" aria-hidden="true"></span> 1420 <span>@Translate("Custom.Propertypage.AssetsModal.Category.Panorama", "360&deg;")</span> 1421 </label> 1422 } 1423 </div> 1424 @if (!bolig.Solgt && !bolig.PurchaseAgreementSigned) { 1425 <div class="d-none d-md-block"> 1426 <a class="btn btn-orange" href="javascript:panelFremvisning('@origin');" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.BookViewing", "Bestil fremvisning"))">@Translate("Custom.Propertypage.AssetsModal.Header.Showing.ButtonLabel", "Bestil fremvisning")</a> 1427 </div> 1428 } 1429 </div> 1430 </div> 1431 <button type="button" class="close" data-dismiss="modal" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.CloseAssetModal", "Luk medie vindue"))"> 1432 @*Mobile*@ 1433 <div class="d-md-none d-block" aria-hidden="true"> 1434 <img src="@(iconPath + "icon-modal-close.svg")" alt="" aria-hidden="true" /> 1435 </div> 1436 <div class="d-md-none d-block pb-2" aria-hidden="true">@Translate("Custom:Propertypage.AssetsModal.Button.Close.Mobile", "Luk")</div> 1437 @*Desktop*@ 1438 <div class="d-none d-md-block pb-2" aria-hidden="true">@Translate("Custom:Propertypage.AssetsModal.Button.Close.Desktop", "Luk vindue")</div> 1439 <div class="d-none d-md-block" aria-hidden="true"> 1440 <img src="@(iconPath + "icon-modal-close-small.svg")" alt="" aria-hidden="true" /> 1441 </div> 1442 </button> 1443 </div> 1444 <div class="modal-body"> 1445 <!-- Video Content --> 1446 @if (hasVideos || hasSlideShow) 1447 { 1448 <div class="content-section video-content"> 1449 <div class="image-gallery" tabindex="-1"> 1450 @if (hasVideos) 1451 { 1452 @foreach (var video in bolig.Videos) 1453 { 1454 <video height="100%" controls="controls" muted loop preload="auto"> 1455 <source src="@video" type="video/mp4" /> 1456 Your browser does not support HTML5 video. 1457 </video> 1458 } 1459 } 1460 @if (hasSlideShow) 1461 { 1462 @foreach (var slide in bolig.EsoftAssets.ActiveSlideShows) 1463 { 1464 <div class="slide-show">@slide.EmbedAssets[0].EmbedCode.Replace("http://", "https://")</div> 1465 } 1466 } 1467 </div> 1468 </div> 1469 } 1470 1471 <!-- Billeder (Images) Content --> 1472 <div class="content-section images-content"> 1473 <div class="image-gallery" tabindex="-1"> 1474 @{ 1475 int imageCounter = 0; 1476 } 1477 1478 @foreach (var image in images) 1479 { 1480 var imageId = "image_" + imageCounter; 1481 <img id="@imageId" class="img-fluid" src="@fallbackImage" data-src="@image.ImageLg" /> 1482 imageCounter++; 1483 } 1484 </div> 1485 <div class="d-md-flex d-none flex-column"> 1486 <button type="button" class="btn btn-modal btn-modal__clean" data-toggle="modal" data-target="#images-modal" onclick="initImageNavigation('.images-modal', { imageSelector: '.large-images img', buttonIdPostFix: '-images-modal' })"> 1487 <div class="pb-2" aria-hidden="true">@Translate("Custom:Propertypage.AssetsModal.Button.LargeImages", "Vis som store billeder")</div> 1488 <div aria-hidden="true"> 1489 <img src="@(iconPath + "icon-expand.svg")" alt="" aria-hidden="true" /> 1490 </div> 1491 </button> 1492 <div class="image-thumbnails js-image-thumbnails"> 1493 @{ 1494 int imageThumbnailCounter = 0; 1495 } 1496 1497 @foreach (var image in images) 1498 { 1499 var imageId = "image_" + imageThumbnailCounter; 1500 <label class="thumbnail-radio js-thumbnail-radio" 1501 tabindex="0" 1502 role="button" 1503 aria-label="@Translate("Custom:Accessibility.ThumbnailImage", "Billede") @(imageThumbnailCounter + 1)" 1504 data-index="@imageThumbnailCounter" 1505 onclick="scrollGalleryToImage('@imageId');"> 1506 <input type="radio" id="@(imageId)_thumbnail" name="thumbnailradio" class="d-none" checked="@(imageThumbnailCounter == 0)" /> 1507 <img class="img-fluid" src="@fallbackImage" data-src="@image.ImageSm" alt="" /> 1508 </label> 1509 1510 imageThumbnailCounter++; 1511 } 1512 </div> 1513 </div> 1514 </div> 1515 1516 <!-- Plantegning (Floor Plan) Content --> 1517 @if (hasBlueprints) 1518 { 1519 <div class="content-section blueprint-content"> 1520 <div class="image-gallery" tabindex="-1"> 1521 @foreach (var plan in bolig.Plantegninger) 1522 { 1523 <img class="img-fluid" src="@fallbackImage" data-src="@plan.ImageXl" /> 1524 } 1525 </div> 1526 </div> 1527 } 1528 1529 <!-- Kort (Map) Content --> 1530 @if (hasMapCoordinates) 1531 { 1532 var mapFeedPageId = Converter.ToString(GetPageIdByNavigationTag("MapFeed")); 1533 string mapMarkerUrl = "Files/Templates/Designs/rm/assets/images/map-pin-real-maeglerne.svg"; 1534 int mapMarkerHeight = 32; 1535 int mapMarkerWidth = 32; 1536 1537 <div class="content-section map-content"> 1538 <div class="image-gallery" tabindex="-1"> 1539 <div class="map js-map" data-map-feed="@mapFeedPageId"> 1540 <div class="renderMap" id="map"></div> 1541 </div> 1542 </div> 1543 </div> 1544 1545 <input type="hidden" class="js-hasmapcoordinates" value="true" /> 1546 <input type="hidden" class="js-mapLng" value="@mapLng" /> 1547 <input type="hidden" class="js-mapLat" value="@mapLat" /> 1548 <input type="hidden" class="js-mapMarkerWidth" value="@mapMarkerWidth" /> 1549 <input type="hidden" class="js-mapMarkerHeight" value="@mapMarkerHeight" /> 1550 <input type="hidden" class="js-mapMarkerUrl" value="@mapMarkerUrl" /> 1551 1552 <link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.4/dist/leaflet.css" integrity="sha512-puBpdR0798OZvTTbP4A8Ix/l+A4dHDD0DGqYW6RQ+9jxkRFclaxxQb/SJAWZfWAkuyeQUytO7+7N4QKrDh+drA==" crossorigin="" /> 1553 <script src="https://unpkg.com/leaflet@1.3.4/dist/leaflet.js" integrity="sha512-nMMmRyTVoLYqjP9hrbed9S+FzjZHW5gY1TWCHA5ckwXZBadntCNs8kEqAWdrb9O7rxbCaA4lKTIWjDXZxflOcA==" crossorigin=""> 1554 </script> 1555 1556 } 1557 1558 <!-- 360 View Content --> 1559 @if (hasPanorama) 1560 { 1561 <div class="content-section view360-content"> 1562 <div class="image-gallery" tabindex="-1"> 1563 @{ 1564 string largeThumbnail = string.Empty; 1565 1566 foreach (var thumbnail in panoramas.First().Assets) 1567 { 1568 if (thumbnail.Width == "1920") 1569 { 1570 largeThumbnail = thumbnail.SecureUrl; 1571 } 1572 } 1573 <div class="panorama"> 1574 <div class="renderMap position-relative"> 1575 <img class="panorama-thumbnail" src="@largeThumbnail" /> 1576 <div class="js-clickme clickme"> 1577 <img src="@(iconPath + "icon-360.svg")" /> 1578 <span>@Translate("Custom.Propertypage.AssetsModal.ShowPanorama", "Vis 360&deg;")</span> 1579 </div> 1580 <span class="js-panorama-encoded" style="display:none">@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlEncode(panoramas.First().EmbedAssets[0].EmbedCode.Replace("http://", "https://"))</span> 1581 </div> 1582 </div> 1583 } 1584 </div> 1585 </div> 1586 } 1587 </div> 1588 </div> 1589 </div> 1590 </div> 1591 </section> 1592 </div> 1593 1594 <div propertypage-anchor> 1595 @*SECTION: Subpage Navigation*@ 1596 @{ 1597 bool homePresentationOn = Converter.ToBoolean(GetString("Ecom:Product:Field.SpHomePresentationOn")); 1598 bool inspiireON = Converter.ToBoolean(GetString("Ecom:Product:Field.SPInspiireON")); 1599 bool climateFriendly = GetBoolean("Ecom:Product:Field.SpClimateFriendly"); 1600 } 1601 <section class="container subpage-navigation pb-0" role="navigation" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.PropertyNavigation", "Ejendomsnavigation"))"> 1602 <div class="subpage-links"> 1603 @if (hasVideos || hasSlideShow) 1604 { 1605 <label for="video" role="button" class="subpage-link cursor-pointer d-none d-md-flex order-md-0 order-8" data-toggle="modal" data-target="#assets-modal" tabindex="0" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.ViewVideo", "Se video"))" onkeypress="if(event.key === 'Enter' || event.key === ' ') { $(this).click(); }"> 1606 <img src="@(iconPath + "icon-video.svg")" alt="" aria-hidden="true" /> 1607 <span>@Translate("Custom.Propertypage.SubpageLink.Video", "Video")</span> 1608 </label> 1609 } 1610 1611 @if (images.Any()) 1612 { 1613 <label for="images" role="button" class="subpage-link cursor-pointer d-none d-md-flex order-md-1 order-9" data-toggle="modal" data-target="#assets-modal" tabindex="0" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.ViewImages", "Se billeder"))" onkeypress="if(event.key === 'Enter' || event.key === ' ') { $(this).click(); }"> 1614 <img src="@(iconPath + "icon-images.svg")" alt="" aria-hidden="true" /> 1615 <span>@Translate("Custom.Propertypage.SubpageLink.Images", "Billeder")</span> 1616 </label> 1617 } 1618 1619 <a class="subpage-link d-flex d-md-none order-2 order-md-2" onclick="scrollToElementById('information-section')" role="button" tabindex="0" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.ViewPropertyFacts", "Se boligfakta"))" onkeypress="if(event.key === 'Enter' || event.key === ' ') scrollToElementById('information-section')"> 1620 <img src="@(iconPath + "icon-house.svg")" alt="" aria-hidden="true" /> 1621 <span>@Translate("Custom.Propertypage.SubpageLink.Information", "Boligfakta")</span> 1622 </a> 1623 1624 @if (hasBlueprints) 1625 { 1626 <label for="blueprint" role="button" class="subpage-link cursor-pointer order-md-3 order-0" data-toggle="modal" data-target="#assets-modal" tabindex="0" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.ViewBlueprint", "Se plantegning"))" onkeypress="if(event.key === 'Enter' || event.key === ' ') { $(this).click(); }"> 1627 <img src="@(iconPath + "icon-blueprint.svg")" alt="" aria-hidden="true" /> 1628 <span>@Translate("Custom.Propertypage.SubpageLink.Blueprint", "Plantegning")</span> 1629 </label> 1630 } 1631 1632 @if (hasMapCoordinates) 1633 { 1634 <label for="mapradio" role="button" class="subpage-link cursor-pointer js-init-map order-1 order-md-4" data-toggle="modal" data-target="#assets-modal" tabindex="0" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.ViewMap", "Se kort"))" onkeypress="if(event.key === 'Enter' || event.key === ' ') { $(this).click(); }"> 1635 <img src="@(iconPath + "icon-map.svg")" alt="" aria-hidden="true" /> 1636 <span>@Translate("Custom.Propertypage.SubpageLink.Map", "Kort")</span> 1637 </label> 1638 } 1639 1640 @if (hasPanorama) 1641 { 1642 <label for="view360" role="button" class="subpage-link cursor-pointer order-3 order-md-5" data-toggle="modal" data-target="#assets-modal" tabindex="0" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.View360", "Se 360 graders visning"))" onkeypress="if(event.key === 'Enter' || event.key === ' ') { $(this).click(); }"> 1643 <img src="@(iconPath + "icon-360.svg")" alt="" aria-hidden="true" /> 1644 <span>@Translate("Custom.Propertypage.SubpageLink.360view", "360&deg;")</span> 1645 </label> 1646 } 1647 1648 @if (climateFriendly) 1649 { 1650 var climatePageID = GetPageIdByNavigationTag("ClimateFriendlyPage"); 1651 1652 if (climatePageID > 0) 1653 { 1654 <a class="subpage-link alt-color order-4 order-md-6" href="Default.aspx?ID=@climatePageID" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.ClimateFriendly", "Se klimavenlig bolighandel"))"> 1655 <img src="@(iconPngPath + "climate-friendly.png")" alt="" aria-hidden="true" /> 1656 <span>@Translate("Custom.Propertypage.SubpageLink.ClimateFriendly", "Grøn Bolighandel")</span> 1657 </a> 1658 } 1659 } 1660 else if (homePresentationOn) 1661 { 1662 string homePresentationLink = GetString("Ecom:Product:Field.SpHomePresentationLink"); 1663 1664 @if (!string.IsNullOrEmpty(homePresentationLink)) 1665 { 1666 <a class="subpage-link order-4 order-md-6" href="@homePresentationLink" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.ViewPresentation", "Se boligpræsentation"))"> 1667 <img src="@(iconPath + "icon-presentation.svg")" alt="" aria-hidden="true" /> 1668 <span>@Translate("Custom.Propertypage.SubpageLink.Presentation", "Boligpræsentation")</span> 1669 </a> 1670 } 1671 } 1672 else if (inspiireON) 1673 { 1674 string inspiireLink = GetString("Ecom:Product:Field.SPInspiireLink"); 1675 1676 @if (!string.IsNullOrEmpty(inspiireLink)) 1677 { 1678 <a class="subpage-link order-4 order-md-6" href="@inspiireLink" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.ViewInspiire", "Se Inspiire præsentation"))"> 1679 <img src="@(iconPath + "icon-presentation.svg")" alt="" aria-hidden="true" /> 1680 <span>@Translate("Custom.Propertypage.SubpageLink.Inspiire", "Inspiire")</span> 1681 </a> 1682 } 1683 } 1684 </div> 1685 <div class="broker-card d-none d-md-flex align-items-center" role="complementary" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.BrokerInfo", "Mæglerinformation"))"> 1686 @if (employeeItem != null) 1687 { 1688 string image = Converter.ToString(employeeItem["BilledeUrl"]); 1689 <img src="@image" alt="@Translate("Custom:Accessibility.BrokerImage", "Billede af mægler") @propBroker.Employee.Name" /> 1690 } 1691 <div class="d-flex flex-column justify-content-around"> 1692 @if (!string.IsNullOrEmpty(propBroker?.Employee?.Name)) 1693 { 1694 <div class="bold">@propBroker.Employee.Name</div> 1695 } 1696 else if (!string.IsNullOrEmpty(propBroker?.Broker?.Name)) 1697 { 1698 <div class="bold">@propBroker.Broker.Name</div> 1699 } 1700 @if (!string.IsNullOrEmpty(propBroker?.Employee?.JobTitle)) 1701 { 1702 <div class="regular">@propBroker.Employee.JobTitle</div> 1703 } 1704 else if (!string.IsNullOrEmpty(propBroker?.Broker?.JobTitle)) 1705 { 1706 <div class="regular">@propBroker.Broker.JobTitle</div> 1707 } 1708 @if (!string.IsNullOrEmpty(propBroker?.Employee?.PhoneMobile) && Converter.ToBoolean(employeeItem["VisMobilNrPaaSager"])) 1709 { 1710 <div class="regular">@Translate("Custom.Propertypage.BrokerCard.Call", "Ring på")<span class="pl-1">@RealMaeglerne.Library.Helper.FormatPhoneNumber(propBroker.Employee.PhoneMobile)</span></div> 1711 } 1712 else if (!string.IsNullOrEmpty(propBroker?.Broker?.Telephone)) 1713 { 1714 <div class="regular">@Translate("Custom.Propertypage.BrokerCard.Call", "Ring på")<span class="pl-1">@RealMaeglerne.Library.Helper.FormatPhoneNumber(propBroker.Broker.Telephone)</span></div> 1715 } 1716 </div> 1717 <div class="divider-blue__vertical mx-4" aria-hidden="true"></div> 1718 <div class="broker-interactions" aria-hidden="true"> 1719 <a class="btn btn-blue" aia-hidden="true" href="javascript:panelSalgsvurdering('@origin');">@Translate("Custom.Propertypage.BrokerCard.SalesAssessment.ButtonLabel", "Få vurdering")</a> 1720 @if (!bolig.Solgt && !bolig.PurchaseAgreementSigned) { 1721 <a class="btn btn-orange" aria-hidden="true" href="javascript:panelFremvisning('@origin');">@Translate("Custom.Propertypage.AssetsModal.Header.Showing.ButtonLabel", "Bestil fremvisning")</a> 1722 } 1723 </div> 1724 </div> 1725 @*SECTION: Open house/Popular section*@ 1726 @if (bolig.AabentHus || popularityMetrics.Any()) 1727 { 1728 <section class="container open-house-popular-section p-0 pt-3 d-block d-md-none"> 1729 <div class="open-house-popular-wrapper"> 1730 @if (bolig.AabentHus) 1731 { 1732 var upcomingOpenHouses = boligManager.KommendeAabnehuse(bolig); 1733 1734 <div class="open-house w-50 @(!popularityMetrics.Any() ? "w-100" : "has-metrics")"> 1735 <h2 class="section-header section-header-md semi-bold mb-0"> 1736 @Translate("Custom.Propertypage.OpenHouseSection.Header", "Åbent hus") 1737 </h2> 1738 <div class="open-house-dates"> 1739 @if (upcomingOpenHouses.Count() > 1) 1740 { 1741 <select id="openhouse-selector-mobile" class="open-house-selector js-aabenthus-liste-val"> 1742 @foreach (var openHouse in upcomingOpenHouses) 1743 { 1744 var json = System.Text.Json.JsonSerializer.Serialize(openHouse); 1745 1746 <option class="open-house-selector__option" data-aabent-hus="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(json)"> 1747 @openHouse.Dato.ToString("d. MMM", Pageview.Area.CultureInfo) kl. @openHouse.FraKlokken.Substring(0, 5) 1748 </option> 1749 } 1750 </select> 1751 } 1752 else 1753 { 1754 var primaryOpenHouse = upcomingOpenHouses.First(); 1755 var json = System.Text.Json.JsonSerializer.Serialize(primaryOpenHouse); 1756 1757 <div class="open-house-text"> 1758 <span class="js-aabenthus-date-val">@primaryOpenHouse.Dato.ToString("d. MMM", Pageview.Area.CultureInfo)</span> 1759 1760 @if (!string.IsNullOrEmpty(primaryOpenHouse.TidspunktFormateret)) 1761 { 1762 <div class="d-inline-block js-aabenthus-time-val js-primary-open-house" data-aabent-hus="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(json)"> 1763 @Translate("Custom.Propertypage.OpenHouseSection.Kl", "kl.") @primaryOpenHouse.FraKlokken.Substring(0, 5)@(" - ")@primaryOpenHouse.TilKlokken.Substring(0, 5) 1764 </div> 1765 } 1766 </div> 1767 } 1768 </div> 1769 @if (upcomingOpenHouses.Any(oh => oh.Tilmelding)) 1770 { 1771 <a class="btn btn-orange" href="javascript:panelAabenthus('@origin');" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.SignUpOpenHouse", "Tilmeld til åbent hus"))"> 1772 @Translate("Custom.Propertypage.OpenHouseSection.SignupButton.Label", "Tilmeld") 1773 </a> 1774 } 1775 </div> 1776 } 1777 @if (popularityMetrics.Any()) 1778 { 1779 <div class="popular w-50 @(!bolig.AabentHus ? "w-100" : "")"> 1780 <div class="section-header section-header-md semi-bold mb-0"> 1781 @Translate("Custom.Propertypage.PopularSection.Header", "Populær") 1782 </div> 1783 <div class="divider-orange ml-auto mr-auto"></div> 1784 <div class="popular-metrics-wrapper"> 1785 @foreach (var metric in popularityMetrics) 1786 { 1787 <div class="popular-metric d-flex flex-column align-items-center justify-content-between"> 1788 <div class="bold">@metric.Value</div> 1789 <div class="text-center">@Translate($"Custom.Propertypage.PopularSection.{metric.Key}.Label", "har interageret med denne bolig")</div> 1790 </div> 1791 } 1792 </div> 1793 </div> 1794 } 1795 </div> 1796 </section> 1797 } 1798 1799 @*SECTION: ADDRESS SECTION*@ 1800 <section id="address-section" class="container address-section p-0 pt-3 pb-3" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.AddressSection", "Adresse og pris information"))"> 1801 <div class="address-wrapper"> 1802 <h2 class="address-header d-flex align-items-center justify-content-between w-100 order-0"> 1803 <div class="d-flex flex-column"> 1804 <div class="js-aabenthus-address-val">@GetString("Ecom:Product:Field.xEjendomAdresseAdresseLinie")</div> 1805 <div class="js-aabenthus-zip-city-val">@GetString("Ecom:Product:Field.xEjendomAdressePostAdresseLinie")</div> 1806 </div> 1807 @{ 1808 var (cssColor, translationKey, defaultText) = bolig switch 1809 { 1810 { Solgt: true, UdbudsForm: "Leje" } => ("red", "Custom.Propertypage.Leased", "Udlejet"), 1811 { Solgt: true } => ("red", "Custom.Propertypage.Sold", "Solgt"), 1812 { PurchaseAgreementSigned: true } => ("blue", "Custom.Propertypage.PurchaseAgreementSigned", "Købsaftale underskrevet"), 1813 { Nyhed: true } => ("orange", "Custom.Propertypage.New", "Nyhed"), 1814 { NyPris: true } => ("orange", "Custom.Propertypage.NewPrice", "Ny pris"), 1815 _ => (null, null, null) 1816 }; 1817 1818 if (translationKey != null) 1819 { 1820 <div class="label" role="status" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.PropertyStatus", "Ejendomsstatus"))"><div class="label-icon @cssColor" aria-hidden="true"></div>@Translate(translationKey, defaultText)</div> 1821 } 1822 } 1823 </h2> 1824 <div class="divider-orange d-none d-md-block" aria-hidden="true"></div> 1825 <div class="address-price d-none d-md-flex flex-column w-100"> 1826 @if (bolig.Solgt || bolig.PurchaseAgreementSigned) 1827 { 1828 //Do Nothing 1829 } 1830 else 1831 { 1832 @if (isRental) 1833 { 1834 <div class="d-flex align-items-center justify-content-between"> 1835 <div>@Translate("Custom.Propertypage.Financing.RentPerMonth", "Leje pr. måned")</div> 1836 <div>@FormatPrice(GetInteger("Ecom:Product:Field.xEjendomBoligUdlejningLejeMaaned.Value.Clean"))</div> 1837 </div> 1838 1839 int usagePerMonth = GetInteger("Ecom:Product:Field.xEjendomBoligUdlejningAcVarmeMaaned.Value.Clean") + GetInteger("Ecom:Product:Field.xEjendomBoligUdlejningAcVandMaaned.Value.Clean") + GetInteger("Ecom:Product:Field.xEjendomBoligUdlejningAcontoForbrugFri01Beloeb.Value.Clean"); 1840 1841 if (usagePerMonth > 0) 1842 { 1843 <div class="d-flex align-items-center justify-content-between address-price-small"> 1844 <div>@Translate("Custom.Propertypage.Financing.UsagePerMonth", "Forbrugsudgift pr. md.")</div> 1845 <div>@FormatPrice(usagePerMonth)</div> 1846 </div> 1847 } 1848 } 1849 else 1850 { 1851 <div class="d-flex align-items-center justify-content-between"> 1852 @if (propCategory == "Andelsbolig") 1853 { 1854 <div>@Translate("Custom.Propertypage.Financing.Table.Deposit", "Indskud")</div> 1855 } 1856 else 1857 { 1858 <div>@Translate("Custom.Propertypage.Financing.Table.Price", "Kontantpris")</div> 1859 } 1860 <div>@FormatPrice(GetInteger("Ecom:Product.DBPrice"))</div> 1861 </div> 1862 <div class="d-flex align-items-center justify-content-between address-price-small"> 1863 <div>@Translate("Custom.Propertypage.Financing.Table.OwnerCost", "Ejerudgift")</div> 1864 <div>@FormatPrice(GetInteger("Ecom:Product:Field.xEjendomEjerudgifterMaanedSum"))</div> 1865 </div> 1866 } 1867 } 1868 </div> 1869 <div class="address-info d-flex flex-wrap d-md-none align-items-center order-1"> 1870 @if (!string.IsNullOrEmpty(propTypeDisplay)) 1871 { 1872 <div class="address-info-item"> 1873 @propTypeDisplay 1874 </div> 1875 } 1876 @if (GetInteger("Ecom:Product:Field.xEjendomArealerBoligAreal") > 0) 1877 { 1878 <div class="address-info-item"> 1879 @GetString("Ecom:Product:Field.xEjendomArealerBoligAreal") @Translate("Custom.Propertypage.Units.SquareMeters", "m&sup2") 1880 </div> 1881 } 1882 @if (bolig.Solgt || bolig.PurchaseAgreementSigned) 1883 { 1884 //Do Nothing 1885 } 1886 else 1887 { 1888 <div class="address-info-item"> 1889 @if (isRental) 1890 { 1891 @GetInteger("Ecom:Product:Field.xEjendomBoligUdlejningLejeMaaned.Value.Clean").ToString("#,##0") @Translate("Custom.Propertypage.RentPerMonth", "pr. md.") 1892 } 1893 else 1894 { 1895 @FormatPrice(GetInteger("Ecom:Product.DBPrice"), true) 1896 } 1897 </div> 1898 } 1899 @if (!string.IsNullOrEmpty(GetString("Ecom:Product:Field.xEjendomEnergiklassifikation")) || !isRental) 1900 { 1901 <div class="address-info-item d-flex align-items-center"> 1902 1903 @{ 1904 var scenarioNumber = GetString("Ecom:Product:Field.EnergyLabelScenarioNumber"); 1905 var savings = GetInteger("Ecom:Product:Field.EnergyLabelSavings"); 1906 var energyLink = GetString("Ecom:Product:Field.EnergyLabelLink"); 1907 } 1908 1909 <div @(scenarioNumber == "3" ? "id='energi-kontrol-address-mobile'" : "")> 1910 @Translate("Custom.Propertypage.Information.Energy", "Energimærke") 1911 </div> 1912 1913 <div class="energylabel @(scenarioNumber == "2" ? "energy__hover" : "")" 1914 data-energylabel="@HtmlEncoder.HtmlAttributeEncode(GetString("Ecom:Product:Field.xEjendomEnergiklassifikation"))"> 1915 @if (scenarioNumber == "2") 1916 { 1917 <span id="energi-testgruppe-address-mobile" class="tooltiptext"> 1918 @if (savings > 0) 1919 { 1920 @string.Format(Translate("Smartpage:Boligvisning.Energimærketekst1-1", "OBS: du kan spare {0} årligt ved at renovere denne bolig - {1}"), savings.ToString("#,##0"), "") 1921 <a target="_blank" href="@(energyLink)&utm_source=realmaeglerne&utm_medium=energimaerke&utm_campaign=testgruppe1">@Translate("Custom.Propertypage.EnergyLabel.Tooltip.Linktext", "klik her")</a> 1922 } 1923 else 1924 { 1925 @string.Format(Translate("Smartpage:Boligvisning.Energimærketekst1-2", "OBS: du kan energi renovere denne bolig {0}"), "") 1926 <a target="_blank" href="@(energyLink)&utm_source=realmaeglerne&utm_medium=energimaerke&utm_campaign=testgruppe1">@Translate("Custom.Propertypage.EnergyLabel.Tooltip.Linktext", "klik her")</a> 1927 } 1928 </span> 1929 } 1930 </div> 1931 </div> 1932 } 1933 </div> 1934 @if (bolig.BudOenskes) 1935 { 1936 <div class="divider-blue order-2" aria-hidden="true"></div> 1937 <div class="address-offer d-flex align-items-center order-3"> 1938 <div> 1939 @Translate("Custom.Propertypage.Address.Offerlink.label", "Har du et bud i tankerne?") 1940 </div> 1941 <a class="btn-link" onclick="scrollToElementById('offer-section', 'center')" role="button" tabindex="0" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.MakeOffer", "Gå til bud sektion"))" onkeypress="if(event.key === 'Enter' || event.key === ' ') scrollToElementById('offer-section', 'center')">@Translate("Custom.Propertypage.Address.Offerlink.linktext", "Giv et bud")</a> 1942 <img height="12px" width="12px" src="@(iconPath + "icon-arrow-narrow-down-white.svg")" alt="" aria-hidden="true" /> 1943 </div> 1944 <div class="divider-blue order-4" aria-hidden="true"></div> 1945 } 1946 1947 @if (bolig.Solgt || bolig.PurchaseAgreementSigned) 1948 { 1949 <div class="w-100 btn btn-light order-5 cursor-default"> 1950 @Translate(translationKey, defaultText) 1951 </div> 1952 } 1953 else 1954 { 1955 <a class="btn btn-orange w-100 order-6" href="javascript:panelFremvisning('@origin');" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.BookViewing", "Bestil fremvisning"))"> 1956 @Translate("Custom.Propertypage.AssetsModal.Header.Showing.ButtonLabel", "Bestil fremvisning") 1957 </a> 1958 1959 <div class="d-flex align-items-center justify-content-between flex-wrap order-7"> 1960 @if (edhFiles.Any() && !bolig.Solgt && !bolig.PurchaseAgreementSigned) 1961 { 1962 <a class="btn btn-link text-left d-flex align-items-center" href="javascript:panelSalgsopstilling('@origin');" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.DownloadDocuments", "Hent salgsdokumenter"))">@Translate("form-salgsopstilling-downloadbtn", "Hent salgsdokumenter") <img class="pl-1" src="@(iconPath + "icon-download-white.svg")" alt="" aria-hidden="true" /></a> 1963 } 1964 1965 <a class="btn btn-link text-left d-flex align-items-center" onclick="scrollToElementById('finance-section', 'center')" role="button" tabindex="0" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.ViewFinance", "Se økonomi og lån"))" onkeypress="if(event.key === 'Enter' || event.key === ' ') scrollToElementById('finance-section', 'center')">@Translate("Custom.Propertypage.Address.Financelink.linktext", "Økonomi & lån")<img height="12px" width="12px" src="@(iconPath + "icon-arrow-narrow-down-white.svg")" alt="" aria-hidden="true" /></a> 1966 </div> 1967 } 1968 </div> 1969 <div class="address-info d-none d-md-flex"> 1970 @if (!string.IsNullOrEmpty(propTypeDisplay)) 1971 { 1972 <div class="address-info-item d-flex align-items-center justify-content-between"> 1973 <div> 1974 @Translate("Custom.Propertypage.Address.PropertyType", "Type") 1975 </div> 1976 <div> 1977 @propTypeDisplay 1978 </div> 1979 </div> 1980 } 1981 @if (GetInteger("Ecom:Product:Field.xEjendomArealerBoligAreal") > 0) 1982 { 1983 <div class="address-info-item d-flex align-items-center justify-content-between"> 1984 <div> 1985 @Translate("Custom.Propertypage.Address.PropertyArea", "Boligareal") 1986 </div> 1987 <div> 1988 @GetString("Ecom:Product:Field.xEjendomArealerBoligAreal") @Translate("Custom.Propertypage.Units.SquareMeters", "m&sup2") 1989 </div> 1990 </div> 1991 } 1992 @if (GetInteger("Ecom:Product:Field.xEjendomArealerVaerelser") != 0) 1993 { 1994 <div class="address-info-item d-md-flex justify-content-between"> 1995 <div>@Translate("Custom.Propertypage.Address.Rooms", "Rum")</div> 1996 <div>@GetString("Ecom:Product:Field.xEjendomArealerVaerelser")</div> 1997 </div> 1998 } 1999 @if (!string.IsNullOrEmpty(GetString("Ecom:Product:Field.xEjendomEnergiklassifikation")) || !isRental) 2000 { 2001 <div class="address-info-item d-flex justify-content-between align-items-center"> 2002 @{ 2003 var scenarioNumber = GetString("Ecom:Product:Field.EnergyLabelScenarioNumber"); 2004 var savings = GetInteger("Ecom:Product:Field.EnergyLabelSavings"); 2005 var energyLink = GetString("Ecom:Product:Field.EnergyLabelLink"); 2006 } 2007 2008 <div @(scenarioNumber == "3" ? "id='energi-kontrol-address-desktop'" : "") class="d-flex flex-column"> 2009 @Translate("Custom.Propertypage.Information.Energy", "Energimærke") 2010 @if (bolig.ShowClimateCalculator) 2011 { 2012 <a class="btn-link cursor-pointer" onclick="scrollToElementById('climate-calculator-section', 'center')" role="button" tabindex="0" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.ViewClimateCalcultor", "Prøv klimaberegner og spar penge"))" onkeypress="if(event.key === 'Enter' || event.key === ' ') scrollToElementById('climate-calculator-section', 'center')">@Translate("Custom.Propertypage.Address.ClimateLink.linktext", "Prøv klimaberegner og spar penge")</a> 2013 } 2014 </div> 2015 2016 <div class="energylabel @(scenarioNumber == "2" ? "energy__hover" : "")" 2017 data-energylabel="@HtmlEncoder.HtmlAttributeEncode(GetString("Ecom:Product:Field.xEjendomEnergiklassifikation"))"> 2018 @if (scenarioNumber == "2") 2019 { 2020 <span id="energi-testgruppe-address-desktop" class="tooltiptext"> 2021 @if (savings > 0) 2022 { 2023 @string.Format(Translate("Smartpage:Boligvisning.Energimærketekst1-1", "OBS: du kan spare {0} årligt ved at renovere denne bolig - {1}"), savings.ToString("#,##0"), "") 2024 <a target="_blank" href="@(energyLink)&utm_source=realmaeglerne&utm_medium=energimaerke&utm_campaign=testgruppe1">@Translate("Custom.Propertypage.EnergyLabel.Tooltip.Linktext", "klik her")</a> 2025 } 2026 else 2027 { 2028 @string.Format(Translate("Smartpage:Boligvisning.Energimærketekst1-2", "OBS: du kan energi renovere denne bolig {0}"), "") 2029 <a target="_blank" href="@(energyLink)&utm_source=realmaeglerne&utm_medium=energimaerke&utm_campaign=testgruppe1">@Translate("Custom.Propertypage.EnergyLabel.Tooltip.Linktext", "klik her")</a> 2030 } 2031 </span> 2032 } 2033 </div> 2034 </div> 2035 } 2036 <div class="d-flex align-items-center"> 2037 <a class="btn-link cursor-pointer" onclick="scrollToElementById('information-section', 'center')" role="button" tabindex="0" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.ViewAllFacts", "Vis alle fakta om boligen"))" onkeypress="if(event.key === 'Enter' || event.key === ' ') scrollToElementById('information-section', 'center')">@Translate("Custom.Propertypage.Address.InfoLink.linktext", "Vis alle fakta om boligen")</a> 2038 <img class="ml-1" height="12px" width="12px" src="@(iconPath + "icon-arrow-narrow-down.svg")" alt="" aria-hidden="true" /> 2039 </div> 2040 </div> 2041 </section> 2042 </section> 2043 </div> 2044 2045 <div propertypage-light> 2046 2047 @*SECTION: Broker mobile*@ 2048 <section class="container broker-mobile d-block d-md-none"> 2049 <div class="broker-card d-flex align-items-center"> 2050 <div class="broker-info"> 2051 @if (employeeItem != null) 2052 { 2053 string image = Converter.ToString(employeeItem["BilledeUrl"]); 2054 <img src="@image" /> 2055 } 2056 <div class="d-flex flex-column justify-content-around"> 2057 @if (!string.IsNullOrEmpty(propBroker?.Employee?.Name)) 2058 { 2059 <div class="bold">@propBroker.Employee.Name</div> 2060 } 2061 else if (!string.IsNullOrEmpty(propBroker?.Broker?.Name)) 2062 { 2063 <div class="bold">@propBroker.Broker.Name</div> 2064 } 2065 @if (!string.IsNullOrEmpty(propBroker?.Employee?.JobTitle)) 2066 { 2067 <div class="regular">@propBroker.Employee.JobTitle</div> 2068 } 2069 else if (!string.IsNullOrEmpty(propBroker?.Broker?.JobTitle)) 2070 { 2071 <div class="regular">@propBroker.Broker.JobTitle</div> 2072 } 2073 </div> 2074 </div> 2075 <div class="broker-interactions"> 2076 @if (!bolig.Solgt && !bolig.PurchaseAgreementSigned) 2077 { 2078 <a class="btn btn-orange" href="javascript:panelFremvisning('@origin');">@Translate("Custom.Propertypage.AssetsModal.Header.Showing.ButtonLabel", "Bestil fremvisning")</a> 2079 } 2080 @if (!string.IsNullOrEmpty(propBroker?.Employee?.PhoneMobile) && Converter.ToBoolean(employeeItem["VisMobilNrPaaSager"])) 2081 { 2082 <div class="regular">@Translate("Custom.Propertypage.BrokerCard.Call", "Ring på")<a href="tel:@RealMaeglerne.Library.Helper.FormatPhoneNumber(propBroker.Employee.PhoneMobile)" class="phone-link pl-1">@RealMaeglerne.Library.Helper.FormatPhoneNumber(propBroker.Employee.PhoneMobile)</a></div> 2083 } 2084 else if (!string.IsNullOrEmpty(propBroker?.Broker?.Telephone)) 2085 { 2086 <div class="regular">@Translate("Custom.Propertypage.BrokerCard.Call", "Ring på")<a href="tel:@RealMaeglerne.Library.Helper.FormatPhoneNumber(propBroker.Broker.Telephone)" class="phone-link pl-1">@RealMaeglerne.Library.Helper.FormatPhoneNumber(propBroker.Broker.Telephone)</a></div> 2087 } 2088 </div> 2089 </div> 2090 </section> 2091 2092 2093 @*SECTION USPs TODO*@ 2094 @{ 2095 bool hasUSPs = false; 2096 } 2097 @if (hasUSPs) 2098 { 2099 <section class="container usp-section"> 2100 <div class="usps d-flex position-relative"> 2101 <button id="image-prev-usps" type="button" class="prev-button btn-round d-none d-md-flex" aria-label="@HtmlEncoder.HtmlAttributeEncode(@Translate("Custom:Accessiblity.UpsBtn.Previous","Forrige"))"> 2102 </button> 2103 <button id="image-next-usps" type="button" class="next-button btn-round d-none d-md-flex" aria-label="@HtmlEncoder.HtmlAttributeEncode(@Translate("Custom:Accessiblity.UpsBtn.Next","Næste"))"> 2104 </button> 2105 <h2 class="usps-header d-flex flex-column align-items-start justify-content-center"> 2106 <div class="usps-header-number"> 2107 6 2108 </div> 2109 <div class="usps-header-text d-block d-md-none"> 2110 @Translate("Custom.Propertypage.USPSection.Header.Mobile", "gode grunde til at købe") 2111 </div> 2112 <div class="usps-header-text d-none d-md-block"> 2113 @Translate("Custom.Propertypage.USPSection.Header.Desktop", "gode grunde til at købe denne bolig") 2114 </div> 2115 <div class="divider-orange d-none d-md-block"></div> 2116 </h2> 2117 <div class="usps-wrapper d-flex"> 2118 <div class="usps-items d-flex"> 2119 <div class="usp-item d-flex flex-column"> 2120 <div class="circle-orange"> 2121 <img src="@(iconPath + "icon-check-small.svg")" /> 2122 </div> 2123 <div class="usp-text"> 2124 Her får du et trygt fundament for familien med både god plads og et roligt nabolag. 2125 </div> 2126 </div> 2127 <div class="divider-blue__vertical"></div> 2128 <div class="usp-item d-flex flex-column"> 2129 <div class="circle-orange"> 2130 <img src="@(iconPath + "icon-check-small.svg")" /> 2131 </div> 2132 <div class="usp-text"> 2133 Du får en bolig med lavt energiforbrug, hvilket både gavner økonomien og miljøet. Lorem ipsum dolor est. 2134 </div> 2135 </div> 2136 <div class="divider-blue__vertical"></div> 2137 <div class="usp-item d-flex flex-column"> 2138 <div class="circle-orange"> 2139 <img src="@(iconPath + "icon-check-small.svg")" /> 2140 </div> 2141 <div class="usp-text"> 2142 Dette hjem har de detaljer, som mange købere efterspørger – lys og luft. 2143 </div> 2144 </div> 2145 <div class="divider-blue__vertical"></div> 2146 <div class="usp-item d-flex flex-column"> 2147 <div class="circle-orange"> 2148 <img src="@(iconPath + "icon-check-small.svg")" /> 2149 </div> 2150 <div class="usp-text"> 2151 Her får du et trygt fundament for familien med både god plads og et roligt nabolag. 2152 </div> 2153 </div> 2154 <div class="divider-blue__vertical"></div> 2155 <div class="usp-item d-flex flex-column"> 2156 <div class="circle-orange"> 2157 <img src="@(iconPath + "icon-check-small.svg")" /> 2158 </div> 2159 <div class="usp-text"> 2160 Du får en bolig med lavt energiforbrug, hvilket både gavner økonomien og miljøet. Lorem ipsum dolor est. 2161 </div> 2162 </div> 2163 <div class="divider-blue__vertical"></div> 2164 <div class="usp-item d-flex flex-column"> 2165 <div class="circle-orange"> 2166 <img src="@(iconPath + "icon-check-small.svg")" /> 2167 </div> 2168 <div class="usp-text"> 2169 Dette hjem har de detaljer, som mange købere efterspørger – lys og luft. 2170 </div> 2171 </div> 2172 </div> 2173 </div> 2174 </div> 2175 </section> 2176 } 2177 @*SECTION: Description*@ 2178 <section id="description-section" class="container description-section" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.PropertyDescription", "Ejendomsbeskrivelse"))"> 2179 <div class="description js-description"> 2180 @{ 2181 string shortDesc = GetString("Ecom:Product.ShortDescription.Raw"); 2182 string longDesc = GetString("Ecom:Product.LongDescription"); 2183 2184 // Replace uplifted numbers with markup (the characters doesn't exist in the current font) 2185 shortDesc = shortDesc.Replace("²", "<sup>2</sup>").Replace("³", "<sup>3</sup>"); 2186 longDesc = longDesc.Replace("²", "<sup>2</sup>").Replace("³", "<sup>3</sup>"); 2187 } 2188 2189 <h2 class="display-sm semi-bold m-0">@shortDesc</h2> 2190 2191 @if (longDesc.Length > 300) 2192 { 2193 <div class="text-wrapper"> 2194 <div class="text-full @(hasUSPs ? "has-buying-reasons" : "")"> 2195 @longDesc 2196 </div> 2197 <button class="read-more btn--clean" type="button" role="button" tabindex="0" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.ReadMoreText", "Læs hele beskrivelsen"))" aria-expanded="false">@Translate("product-read-more", "Læs hele teksten")<img src="@(iconPath + "plus.svg")" alt="" aria-hidden="true" /></button> 2198 <button class="read-less d-none" type="button" role="button" tabindex="0" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.ReadLessText", "Skjul noget af beskrivelsen"))" aria-expanded="true">@Translate("product-read-less", "Læs mindre")<img src="@(iconPath + "minus.svg")" alt="" aria-hidden="true" /></button> 2199 </div> 2200 } 2201 else 2202 { 2203 <div>@longDesc</div> 2204 } 2205 </div> 2206 2207 </section> 2208 @*SECTION: BLueprints*@ 2209 @if (hasBlueprints) 2210 { 2211 <section class="container blueprint-section"> 2212 <div class="blueprints position-relative"> 2213 <h2 class="section-header semi-bold">@Translate("Custom.Propertypage.Blueprints.Header", "Plantegning")</h2> 2214 <div class="divider-orange mb-3 mb-md-5"></div> 2215 <div class="blueprints-wrapper js-blueprints-wrapper"> 2216 @foreach (var blueprint in bolig.Plantegninger) 2217 { 2218 <label for="blueprint" class="blueprint cursor-pointer mb-0" data-toggle="modal" data-target="#assets-modal"> 2219 <img class="blueprint img-fluid" src="@blueprint.ImageLg" /> 2220 </label> 2221 } 2222 </div> 2223 <button id="image-prev-blueprints" type="button" class="prev-button btn-round mb-2 d-none d-md-flex" aria-label="@HtmlEncoder.HtmlAttributeEncode(@Translate("Custom:Accessiblity.BlueprintsBtn.Previous","Forrige"))"> 2224 </button> 2225 <button id="image-next-blueprints" type="button" class="next-button btn-round d-none d-md-flex" aria-label="@HtmlEncoder.HtmlAttributeEncode(@Translate("Custom:Accessiblity.BlueprintsBtn.Next","Næste"))"> 2226 </button> 2227 </div> 2228 </section> 2229 } 2230 2231 @if (hasMapCoordinates) 2232 { 2233 <section class="container map-mobile-section d-md-none d-block js-init-map-onload" data-map-container="map-mobile" data-map-pois="false"> 2234 <h2 class="section-header semi-bold">@Translate("Custom.Propertypage.MobileMap.Header", "Kort")</h2> 2235 <div class="divider-orange mb-3" aria-hidden="true"></div> 2236 <div id="map-mobile" class="map-mobile"> 2237 <button type="button" class="btn btn-link" onclick="fullScreen('map-mobile', this)" data-text-open="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Propertypage.MobileMap.Button.FullScreen", "Fuld skærm"))" data-text-close="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Propertypage.MobileMap.Button.NormalScreen", "Luk"))" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.ToggleFullscreen", "Skift til fuldskærm"))" tabindex="0" onkeypress="if(event.key === 'Enter' || event.key === ' ') fullScreen('map-mobile')"> 2238 <div class="js-button-label pb-2">@Translate("Custom:Propertypage.MobileMap.Button.FullScreen", "Fuld skærm")</div> 2239 <div> 2240 <img src="@(iconPath + "icon-expand.svg")" alt="" aria-hidden="true" /> 2241 </div> 2242 </button> 2243 <div class="map h-100 w-100 js-map" data-map-feed="@Converter.ToString(GetPageIdByNavigationTag("MapFeed"))" role="application" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.InteractiveMap", "Interaktivt kort"))"> 2244 <div class="renderMap" id="map-mobile"></div> 2245 </div> 2246 </div> 2247 </section> 2248 } 2249 2250 @*SECTION: Information*@ 2251 <section id="information-section" class="container information-section" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.PropertyFactsSection", "Fakta om boligen"))"> 2252 @{ 2253 int garageArea = GetInteger("Ecom:Product:Field.xEjendomArealerHovedbygningIntegreredeArealerGarage"); 2254 int carportArea = GetInteger("Ecom:Product:Field.xEjendomArealerHovedbygningIntegreredeArealerCarport.Value"); 2255 bool altan = GetBoolean("Ecom:Product:Field.xEjendomFaciliteterAltan"); 2256 } 2257 <div class="information"> 2258 <h2 class="information-header semi-bold">@Translate("Custom.Propertypage.Information.Header", "Fakta om boligen")</h2> 2259 <div class="d-none d-md-block divider-orange mb-4" aria-hidden="true"></div> 2260 <div class="table-wrapper" role="table" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.PropertyFactsTable", "Boligfakta tabel"))"> 2261 <div class="table-item d-flex justify-content-between" role="row"> 2262 <div role="cell">@Translate("Custom.Propertypage.Information.Case", "Sagsnummer")</div> 2263 <div role="cell" class="js-sagsnr-val" tabindex="0" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.CaseNumber", "Sagsnummer")) @productId">@productId</div> 2264 </div> 2265 @if (!string.IsNullOrEmpty(propTypeDisplay)) 2266 { 2267 <div class="table-item d-flex justify-content-between" role="row"> 2268 <div role="cell">@Translate("Custom.Propertypage.Information.PropertyType", "Boligtype")</div> 2269 <div role="cell" tabindex="0" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.PropertyType", "Boligtype")) @propTypeDisplay">@propTypeDisplay</div> 2270 </div> 2271 } 2272 @if (GetInteger("Ecom:Product:Field.xEjendomArealerBoligAreal") > 0) 2273 { 2274 <div class="table-item d-flex justify-content-between" role="row"> 2275 <div role="cell">@Translate("Custom.Propertypage.Information.Residentialrea", "Boligareal")</div> 2276 <div role="cell" tabindex="0" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.ResidentialArea", "Boligareal")) @GetString("Ecom:Product:Field.xEjendomArealerBoligAreal") @HtmlEncoder.HtmlAttributeEncode(Translate("Custom.Propertypage.Units.SquareMeters", "kvadratmeter"))">@GetString("Ecom:Product:Field.xEjendomArealerBoligAreal") @Translate("Custom.Propertypage.Units.SquareMeters", "m&sup2")</div> 2277 </div> 2278 } 2279 @if (GetInteger("Ecom:Product:Field.xEjendomArealerGrundAreal") > 0) 2280 { 2281 <div class="table-item d-flex justify-content-between" role="row"> 2282 <div role="cell">@Translate("Custom.Propertypage.Information.Landarea", "Grundareal")</div> 2283 <div role="cell" tabindex="0" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.LandArea", "Grundareal")) @GetString("Ecom:Product:Field.xEjendomArealerGrundAreal") @HtmlEncoder.HtmlAttributeEncode(Translate("Custom.Propertypage.Units.SquareMeters", "kvadratmeter"))">@GetString("Ecom:Product:Field.xEjendomArealerGrundAreal") @Translate("Custom.Propertypage.Units.SquareMeters", "m&sup2")</div> 2284 </div> 2285 } 2286 else if (GetInteger("Ecom:Product:Field.xEjendomArealerGrundArealHA") > 0) 2287 { 2288 <div class="table-item d-flex justify-content-between" role="row"> 2289 <div role="cell">@Translate("Custom.Propertypage.Information.Landarea", "Grundareal")</div> 2290 <div role="cell" tabindex="0" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.LandArea", "Grundareal")) @GetString("Ecom:Product:Field.xEjendomArealerGrundArealHA") @HtmlEncoder.HtmlAttributeEncode(Translate("Custom.Propertypage.Units.Acres", "hektar"))">@GetString("Ecom:Product:Field.xEjendomArealerGrundArealHA") @Translate("Custom.Propertypage.Units.Acres", "hektar")</div> 2291 </div> 2292 } 2293 2294 2295 @if (garageArea > 0 || carportArea > 0) 2296 { 2297 if (garageArea > 0 && carportArea > 0) 2298 { 2299 <div class="table-item d-flex justify-content-between"> 2300 <div>@Translate("Custom.Propertypage.Information.GarageCarport", "Garage/Carport")</div> 2301 <div>@garageArea/@carportArea @Translate("Custom.Propertypage.Units.SquareMeters", "m&sup2")</div> 2302 </div> 2303 } 2304 else if (garageArea > 0 && carportArea <= 0) 2305 { 2306 <div class="table-item d-flex justify-content-between"> 2307 <div>@Translate("Custom.Propertypage.Information.Garage", "Garage")</div> 2308 <div>@garageArea @Translate("Custom.Propertypage.Units.SquareMeters", "m&sup2")</div> 2309 </div> 2310 } 2311 else 2312 { 2313 <div class="table-item d-flex justify-content-between"> 2314 <div>@Translate("Custom.Propertypage.Information.Carport", "Carport")</div> 2315 <div>@carportArea @Translate("Custom.Propertypage.Units.SquareMeters", "m&sup2")</div> 2316 </div> 2317 } 2318 } 2319 @if (altan) 2320 { 2321 <div class="table-item d-flex justify-content-between" role="row"> 2322 <div role="cell">@Translate("Custom.Propertypage.Information.Balkony", "Altan")</div> 2323 <div role="cell" tabindex="0" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.Balcony", "Altan")) @HtmlEncoder.HtmlAttributeEncode(Translate("Custom.Propertypage.Information.Yes", "Ja"))">@Translate("Custom.Propertypage.Information.Yes", "Ja")</div> 2324 </div> 2325 } 2326 @if (GetInteger("Ecom:Product:Field.xEjendomOpfoertAar") != 0) 2327 { 2328 <div class="table-item d-flex justify-content-between" role="row"> 2329 <div role="cell">@Translate("Custom.Propertypage.Information.BuildRebuild", "Bygget/ombygget")</div> 2330 <div role="cell" tabindex="0" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.BuildYear", "Byggeår")) @GetInteger("Ecom:Product:Field.xEjendomOpfoertAar") @(GetInteger("Ecom:Product:Field.xEjendomOmbyggetAar") != 0 ? HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.RebuildYear", "Ombygget")) + " " + GetString("Ecom:Product:Field.xEjendomOmbyggetAar") : "")">@GetInteger("Ecom:Product:Field.xEjendomOpfoertAar") @(GetInteger("Ecom:Product:Field.xEjendomOmbyggetAar") != 0 ? "/ " + GetString("Ecom:Product:Field.xEjendomOmbyggetAar") : "")</div> 2331 </div> 2332 } 2333 @if (GetInteger("Ecom:Product:Field.xEjendomArealerVaerelser") != 0) 2334 { 2335 <div class="table-item d-flex justify-content-between" role="row"> 2336 <div role="cell">@Translate("Custom.Propertypage.Information.Rooms", "Antal rum")</div> 2337 <div role="cell" tabindex="0" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.NumberOfRooms", "Antal rum")) @GetString("Ecom:Product:Field.xEjendomArealerVaerelser")">@GetString("Ecom:Product:Field.xEjendomArealerVaerelser")</div> 2338 </div> 2339 } 2340 @if (GetInteger("Ecom:Product:Field.xEjendomArealerEtager") != 0 && (propType != "Ejerlejlighed" && propType != "Andelsbolig")) 2341 { 2342 <div class="table-item d-flex justify-content-between" role="row"> 2343 <div role="cell">@Translate("Custom.Propertypage.Information.Stories", "Etager")</div> 2344 <div role="cell" tabindex="0" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.NumberOfFloors", "Antal etager")) @GetString("Ecom:Product:Field.xEjendomArealerEtager")">@GetString("Ecom:Product:Field.xEjendomArealerEtager")</div> 2345 </div> 2346 } 2347 @if (!string.IsNullOrEmpty(GetString("Ecom:Product:Field.xEjendomEnergiklassifikation"))) 2348 { 2349 <div class="table-item d-flex justify-content-between align-items-center"> 2350 @{ 2351 var scenarioNumber = GetString("Ecom:Product:Field.EnergyLabelScenarioNumber"); 2352 var savings = GetInteger("Ecom:Product:Field.EnergyLabelSavings"); 2353 var energyLink = GetString("Ecom:Product:Field.EnergyLabelLink"); 2354 } 2355 2356 <div @(scenarioNumber == "3" ? "id='energi-kontrol-information'" : "")> 2357 @Translate("Custom.Propertypage.Information.Energy", "Energimærke") 2358 </div> 2359 2360 <div class="energylabel @(scenarioNumber == "2" ? "energy__hover" : "")" 2361 data-energylabel="@HtmlEncoder.HtmlAttributeEncode(GetString("Ecom:Product:Field.xEjendomEnergiklassifikation"))"> 2362 @if (scenarioNumber == "2") 2363 { 2364 <span id="energi-testgruppe-information" class="tooltiptext"> 2365 @if (savings > 0) 2366 { 2367 @string.Format(Translate("Smartpage:Boligvisning.Energimærketekst1-1", "OBS: du kan spare {0} årligt ved at renovere denne bolig - {1}"), savings.ToString("#,##0"), "") 2368 <a target="_blank" href="@(energyLink)&utm_source=realmaeglerne&utm_medium=energimaerke&utm_campaign=testgruppe1">@Translate("Custom.Propertypage.EnergyLabel.Tooltip.Linktext", "klik her")</a> 2369 } 2370 else 2371 { 2372 @string.Format(Translate("Smartpage:Boligvisning.Energimærketekst1-2", "OBS: du kan energi renovere denne bolig {0}"), "") 2373 <a target="_blank" href="@(energyLink)&utm_source=realmaeglerne&utm_medium=energimaerke&utm_campaign=testgruppe1">@Translate("Custom.Propertypage.EnergyLabel.Tooltip.Linktext", "klik her")</a> 2374 } 2375 </span> 2376 } 2377 </div> 2378 </div> 2379 } 2380 </div> 2381 @if (edhFiles.Any() && !bolig.Solgt && !bolig.PurchaseAgreementSigned) 2382 { 2383 <div class="table-item"> 2384 <a class="btn btn-link text-left d-flex align-items-center" href="javascript:panelSalgsopstilling('@origin');" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.DownloadSalesDocuments", "Hent salgsdokumenter"))" tabindex="0">@Translate("form-salgsopstilling-downloadbtn", "Hent salgsdokumenter") <img class="pl-1" src="@(iconPath + "icon-download.svg")" alt="" aria-hidden="true" /></a> 2385 </div> 2386 } 2387 </div> 2388 </section> 2389 @*SECTION: Finance*@ 2390 @if (!bolig.Solgt && !bolig.PurchaseAgreementSigned) 2391 { 2392 string brfQuery = $"price={GetInteger("Ecom:Product.DBPrice")}"; 2393 2394 if (propCategory != null) 2395 { 2396 if (propCategory.Contains("Ejerlejlighed", StringComparison.InvariantCultureIgnoreCase)) 2397 { 2398 brfQuery += "&housingType=ejerlejlighed"; 2399 } 2400 else if (propCategory.Contains("Villa", StringComparison.InvariantCultureIgnoreCase) || 2401 propCategory.Contains("Boliglandbrug", StringComparison.InvariantCultureIgnoreCase)) 2402 { 2403 brfQuery += "&housingType=parcelhus"; 2404 } 2405 } 2406 2407 brfQuery += "&partnerID=REM100"; 2408 2409 2410 <section id="finance-section" class="container financing-section"> 2411 <div class="financing d-flex flex-column flex-md-row"> 2412 <div class="financing-bank d-flex flex-column justify-content-center"> 2413 <img src="@(imagePath + "Jyske_Bank_logo1.png")" class="img-fluid logo" /> 2414 <h2 class="section-header mb-0"> 2415 @Translate("Custom.Propertypage.Financing.Bank.Header", "Find den finansiering, der passer dig. Få din drømmebolig til at blive virkelighed") 2416 </h2> 2417 <div class="d-none d-md-block divider-orange mb-4"></div> 2418 <div> 2419 @Translate("Custom.Propertypage.Financing.Bank.SubHeader", "Med en hurtig online vurdering kender du bedre dine muligheder") 2420 </div> 2421 @if (propCategory == "Andelsbolig") 2422 { 2423 <a href="https://www.jyskebank.dk/bolig/boliglaan/andelsbolig" target="_blank" id="gtm-brf" class="btn btn-light">@Translate("Smartpage:Boligvisning.CalculatorContact", "Kontakt Jyske Bank")</a> 2424 } 2425 else 2426 { 2427 <a href="https://www.jyskebank.dk/bolig/regn-paa-bolig/beregn-laan-til-ny-bolig?@(brfQuery)" target="_blank" id="gtm-brf" class="btn btn-light w-100">@Translate("Smartpage:Boligvisning.CalculatorLink", "Hvor meget kan jeg købe for?")<img src="@(iconPath + "icon-link-external.svg")" /></a> 2428 } 2429 </div> 2430 <div class="financing-table d-flex flex-column"> 2431 <div class="section-header semi-bold mb-0"> 2432 @Translate("Custom.Propertypage.Financing.Table.Header", "Økonomi og boliglån") 2433 </div> 2434 <div class="d-none d-md-block divider-orange mb-4"></div> 2435 <div class="table-wrapper w-100"> 2436 @if (isRental) 2437 { 2438 <div class="table-item d-flex justify-content-between"> 2439 <div>@Translate("Custom.Propertypage.Financing.RentPerMonth", "Leje pr. måned")</div> 2440 <div>@FormatPrice(GetInteger("Ecom:Product:Field.xEjendomBoligUdlejningLejeMaaned.Value.Clean"))</div> 2441 </div> 2442 2443 int usagePerMonth = GetInteger("Ecom:Product:Field.xEjendomBoligUdlejningAcVarmeMaaned.Value.Clean") + GetInteger("Ecom:Product:Field.xEjendomBoligUdlejningAcVandMaaned.Value.Clean") + GetInteger("Ecom:Product:Field.xEjendomBoligUdlejningAcontoForbrugFri01Beloeb.Value.Clean"); 2444 2445 if (usagePerMonth > 0) 2446 { 2447 <div class="table-item d-flex justify-content-between"> 2448 <div>@Translate("Custom.Propertypage.Financing.UsagePerMonth", "Forbrugsudgift pr. md.")</div> 2449 <div>@FormatPrice(usagePerMonth)</div> 2450 </div> 2451 } 2452 2453 if (GetInteger("Ecom:Product:Field.xEjendomBoligUdlejningAcVarmeMaaned.Value.Clean") > 0) 2454 { 2455 <div class="table-item d-flex justify-content-between"> 2456 <div>@Translate("Custom.Propertypage.Financing.AcontoHeat", "Aconto varme pr. md.")</div> 2457 <div>@FormatPrice(GetInteger("Ecom:Product:Field.xEjendomBoligUdlejningAcVarmeMaaned.Value.Clean"))</div> 2458 </div> 2459 } 2460 2461 if (GetInteger("Ecom:Product:Field.xEjendomBoligUdlejningAcVandMaaned.Value.Clean") > 0) 2462 { 2463 <div class="table-item d-flex justify-content-between"> 2464 <div>@Translate("Custom.Propertypage.Financing.AcontoWater", "Aconto vand pr. md.")</div> 2465 <div>@FormatPrice(GetInteger("Ecom:Product:Field.xEjendomBoligUdlejningAcVandMaaned.Value.Clean"))</div> 2466 </div> 2467 } 2468 2469 if (GetInteger("Ecom:Product:Field.xEjendomBoligUdlejningDepositum") > 0) 2470 { 2471 <div class="table-item d-flex justify-content-between"> 2472 <div>@Translate("Custom.Propertypage.Financing.Deposit", "Depositum")</div> 2473 <div>@FormatPrice(GetInteger("Ecom:Product:Field.xEjendomBoligUdlejningDepositum"))</div> 2474 </div> 2475 } 2476 2477 if (GetInteger("Ecom:Product:Field.xEjendomBoligUdlejningForudbetaltLeje") > 0) 2478 { 2479 <div class="table-item d-flex justify-content-between"> 2480 <div>@Translate("Custom.Propertypage.Financing.Prepayment", "Forudbetalt leje")</div> 2481 <div>@FormatPrice(GetInteger("Ecom:Product:Field.xEjendomBoligUdlejningForudbetaltLeje"))</div> 2482 </div> 2483 } 2484 } 2485 else 2486 { 2487 <div class="table-item d-flex justify-content-between"> 2488 @if (propCategory == "Andelsbolig") 2489 { 2490 <div>@Translate("Custom.Propertypage.Financing.Table.Deposit", "Indskud")</div> 2491 } 2492 else 2493 { 2494 <div>@Translate("Custom.Propertypage.Financing.Table.Price", "Kontantpris")</div> 2495 } 2496 <div>@FormatPrice(GetInteger("Ecom:Product.DBPrice"))</div> 2497 </div> 2498 @if (propCategory != "Andelsbolig") 2499 { 2500 <div class="table-item d-flex justify-content-between"> 2501 <div>@Translate("Custom.Propertypage.Financing.Table.Payout", "Udbetaling")</div> 2502 <div>@FormatPrice(GetInteger("Ecom:Product:Field.xFinansieringUdbetaling"))</div> 2503 </div> 2504 } 2505 <div class="table-item d-flex justify-content-between"> 2506 <div>@Translate("Custom.Propertypage.Financing.Table.Brutto", "Brutto ekskl. ejerudgift")</div> 2507 <div>@FormatPrice(GetInteger("Ecom:Product:Field.xFinansieringBruttoMaaned"))</div> 2508 </div> 2509 <div class="table-item d-flex justify-content-between"> 2510 <div>@Translate("Custom.Propertypage.Financing.Table.Netto", "Netto ekskl. ejerudgift")</div> 2511 <div>@FormatPrice(GetInteger("Ecom:Product:Field.xFinansieringNettoMaaned"))</div> 2512 </div> 2513 <div class="table-item d-flex justify-content-between"> 2514 <div>@Translate("Custom.Propertypage.Financing.Table.OwnerCost", "Ejerudgift")</div> 2515 <div>@FormatPrice(GetInteger("Ecom:Product:Field.xEjendomEjerudgifterMaanedSum"))</div> 2516 </div> 2517 } 2518 </div> 2519 </div> 2520 </div> 2521 </section> 2522 } 2523 2524 @*SECTION: Offer*@ 2525 @if (bolig.BudOenskes) 2526 { 2527 <section id="offer-section" class="container offer-section"> 2528 <div class="offer"> 2529 <div class="offer-wrapper d-flex flex-column text-center"> 2530 <h2 class="section-header semi-bold"> 2531 @Translate("Custom.Propertypage.OfferSection.Header", "Har du et bud i tankerne?") 2532 </h2> 2533 <div class="divider-orange d-none d-md-block mx-auto mb-4"></div> 2534 <div class="offer-text d-block d-md-none"> 2535 @Translate("Custom.Propertypage.OfferSection.Text.Mobile", "Jeg vil gerne byde:") 2536 </div> 2537 <div class="offer-container"> 2538 <div class="offer-text d-none d-md-block"> 2539 @Translate("Custom.Propertypage.OfferSection.Text.Desktop", "Jeg byder") 2540 </div> 2541 <input class="form-control js-input-offer text-right" id="offer-input" type="text" /> 2542 <a class="btn btn-orange js-send-offer-to-form" href="javascript:panelMakeAnOffer('@origin');"> 2543 @Translate("Custom.Propertypage.OfferSection.Button.Send", "Send bud") 2544 <img height="20px" width="20px" src="@(iconPath + "icon-arrow-right.svg")" /> 2545 </a> 2546 </div> 2547 <div class="offer-subtext"> 2548 @Translate("Custom.Propertypage.OfferSection.Subtext", "Dit bud er helt uforpligtende") 2549 </div> 2550 </div> 2551 <img class="img-fluid d-none d-md-block" src="@(imagePath + "skriv_din_pris.jpg")" data-fallback="@fallbackImage" onerror="handleError(this)" /> 2552 </div> 2553 </section> 2554 } 2555 2556 @*SECTION: Map with filter*@ 2557 @if (hasMapCoordinates) 2558 { 2559 <section class="container map-filter-section js-init-map-onload" data-map-container="map-filter" data-map-pois="true"> 2560 <div id="map-filter-wrapper" class="map-filter-wrapper"> 2561 <h2 class="section-header semi-bold">@Translate("Custom.Propertypage.FilterMap.Header", "Hvor finder jeg?")</h2> 2562 <div class="divider-orange mb-3 d-none d-md-block"></div> 2563 <div class="map-filters d-flex flex-wrap"> 2564 <label class="mapfilter-btn"> 2565 <input type="checkbox" id="shopping" name="mapfilter" class="mapfilter-checkbox" onchange="toggleMapCategory(this.id, this)" checked> 2566 <span>@Translate("Custom.Propertypage.MapFilter.Filter.Shopping", "Indkøb")</span> 2567 </label> 2568 <label class="mapfilter-btn"> 2569 <input type="checkbox" id="schools" name="mapfilter" class="mapfilter-checkbox" onchange="toggleMapCategory(this.id, this)" checked> 2570 <span>@Translate("Custom.Propertypage.MapFilter.Filter.Schools", "Dagtilbud")</span> 2571 </label> 2572 <label class="mapfilter-btn"> 2573 <input type="checkbox" id="health" name="mapfilter" class="mapfilter-checkbox" onchange="toggleMapCategory(this.id, this)" checked> 2574 <span>@Translate("Custom.Propertypage.MapFilter.Filter.Health", "Helbred")</span> 2575 </label> 2576 <label class="mapfilter-btn"> 2577 <input type="checkbox" id="nature" name="mapfilter" class="mapfilter-checkbox" onchange="toggleMapCategory(this.id, this)" checked> 2578 <span>@Translate("Custom.Propertypage.MapFilter.Filter.Nature", "Natur")</span> 2579 </label> 2580 <label class="mapfilter-btn"> 2581 <input type="checkbox" id="transportation" name="mapfilter" class="mapfilter-checkbox" onchange="toggleMapCategory(this.id, this)" checked> 2582 <span>@Translate("Custom.Propertypage.MapFilter.Filter.Transportation", "Transport")</span> 2583 </label> 2584 </div> 2585 </div> 2586 <div id="map-filter-container" class="map-filter"> 2587 <button type="button" class="btn btn-link" onclick="fullScreen('map-filter-container', this)" data-text-open="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Propertypage.MobileMap.Button.FullScreen", "Fuld skærm"))" data-text-close="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Propertypage.MobileMap.Button.NormalScreen", "Luk"))"> 2588 <div class="js-button-label pb-2">@Translate("Custom:Propertypage.MobileMap.Button.FullScreen", "Fuld skærm")</div> 2589 <div> 2590 <img src="@(iconPath + "icon-expand.svg")" /> 2591 </div> 2592 </button> 2593 <div class="map h-100 w-100 js-map" data-map-feed="@Converter.ToString(GetPageIdByNavigationTag("MapFeed"))"> 2594 <div class="renderMap" id="map-filter"></div> 2595 </div> 2596 </div> 2597 </section> 2598 } 2599 2600 @*SECTION: Broker*@ 2601 @{ 2602 string brokerUrl = brokerItem?["CBMedlemsnummer"] != null && !string.IsNullOrEmpty(Converter.ToString(brokerItem?["CBMedlemsnummer"])) ? Converter.ToString(brokerItem?["CBMedlemsnummer"]).Substring(1) : string.Empty; 2603 string brokerAddress = GetFullAddress(propBroker?.Broker); 2604 } 2605 2606 @if (employeeItem != null) 2607 { 2608 <input type="hidden" class="js-hasEmployee" value="true" /> 2609 <section class="container broker-section"> 2610 <div class="broker d-flex flex-column flex-md-row"> 2611 <div class="broker-wrapper d-flex flex-column"> 2612 <h2 class="section-header semi-bold mb-md-0"> 2613 @string.Format(Translate("Custom.Propertypage.BrokerSection.Header", "Har du spørgsmål? Spørg {0}"), propBroker?.Employee?.FirstName) 2614 </h2> 2615 <div class="divider-orange d-none d-md-block"></div> 2616 <img class="img-fluid d-block d-md-none js-broker-image" src="@employeeItem["BilledeUrl"]" data-fallback="@fallbackImage" onerror="handleError(this)" /> 2617 <div class="employee-info d-flex flex-column"> 2618 @if (!string.IsNullOrEmpty(propBroker?.Employee?.Name)) 2619 { 2620 <div class="bold js-maegler-employee-name-val">@propBroker.Employee.Name</div> 2621 } 2622 @if (!string.IsNullOrEmpty(propBroker?.Employee?.JobTitle)) 2623 { 2624 <input type="hidden" class="js-maegler-employee-title-val" value="@HtmlEncoder.HtmlAttributeEncode(propBroker.Employee.JobTitle)" /> 2625 <div class="regular">@propBroker.Employee.JobTitle</div> 2626 } 2627 @if (!string.IsNullOrEmpty(propBroker?.Employee?.Email) && Converter.ToBoolean(employeeItem["VisEmailPaaSager"])) 2628 { 2629 <div class="regular">@Translate("Custom.Propertypage.BrokerSection.EmplyeeInfo.Emailprefix", "Mail:") <a class="btn-link regular" href="mailto:@propBroker.Employee.Email">@propBroker.Employee.Email</a></div> 2630 2631 @if (string.IsNullOrEmpty(Converter.ToString(brokerItem?["Email"]))) 2632 { 2633 <span class="js-maegler-mail-val d-none">@RealMaeglerne.Library.Helper.ExtractMaskedEmail(propBroker.Employee.Email)</span> 2634 } 2635 else 2636 { 2637 <span class="js-maegler-mail-val d-none">@RealMaeglerne.Library.Helper.ExtractMaskedEmail(Converter.ToString(brokerItem?["Email"]))</span> 2638 } 2639 2640 } 2641 @if (!string.IsNullOrEmpty(propBroker?.Employee?.PhoneMobile) && Converter.ToBoolean(employeeItem["VisMobilNrPaaSager"])) 2642 { 2643 <div class="regular">@Translate("Custom.Propertypage.BrokerSection.EmplyeeInfo.Phoneprefix", "Tlf:") <a class="btn-link regular js-maegler-mobile-val" href="tel:@propBroker.Employee.PhoneMobile">@RealMaeglerne.Library.Helper.FormatPhoneNumber(propBroker.Employee.PhoneMobile)</a></div> 2644 } 2645 </div> 2646 <div class="divider-grey"></div> 2647 2648 @if (brokerItem != null) 2649 { 2650 var brokerEmail = Converter.ToString(brokerItem["Email"]); 2651 2652 <div class="broker-info"> 2653 @if (!string.IsNullOrEmpty(propBroker?.Broker?.CompanyName)) 2654 { 2655 <div class="bold js-maegler-name-val">@propBroker.Broker.CompanyName</div> 2656 } 2657 else if (!string.IsNullOrEmpty(propBroker?.Broker?.Name)) 2658 { 2659 <div class="bold js-maegler-name-val">@propBroker.Broker.Name</div> 2660 } 2661 @if (!string.IsNullOrEmpty(brokerAddress)) 2662 { 2663 <div class="regular">@brokerAddress</div> 2664 } 2665 @if (!string.IsNullOrEmpty(brokerEmail)) 2666 { 2667 <div class="regular">@Translate("Custom.Propertypage.BrokerSection.EmployeeInfo.Emailprefix", "Mail:") <a class="btn-link regular" href="mailto:@brokerEmail">@brokerEmail</a></div> 2668 } 2669 @if (!string.IsNullOrEmpty(propBroker?.Broker?.Telephone)) 2670 { 2671 <div class="regular">@Translate("Custom.Propertypage.BrokerSection.EmployeeInfo.Phoneprefix", "Tlf:") <a class="btn-link regular js-maegler-phone-val" href="tel:@propBroker.Broker.Telephone">@RealMaeglerne.Library.Helper.FormatPhoneNumber(propBroker.Broker.Telephone)</a></div> 2672 } 2673 </div> 2674 <span class="js-butikId d-none">@Converter.ToString(brokerItem["CBMedlemsnummer"])</span> 2675 <span class="js-maegler-address-val d-none">@propBroker?.Broker?.Address</span> 2676 <span class="js-maegler-zip-city-val d-none">@propBroker?.Broker?.ZipCode @propBroker?.Broker?.City</span> 2677 } 2678 2679 <div class="broker-buttons d-flex flex-column flex-md-row"> 2680 @if (!string.IsNullOrEmpty(brokerUrl)) 2681 { 2682 brokerUrl = "/" + brokerUrl; 2683 <a href="@brokerUrl" class="btn btn-blue w-100"> 2684 @Translate("Custom.Propertypage.BrokerSection.BrokerLink.Label", "Vis mæglerens side") 2685 <img height="20px" width="20px" src="@(iconPath + "icon-arrow-right.svg")" /> 2686 </a> 2687 } 2688 @if (!bolig.Solgt && !bolig.PurchaseAgreementSigned) 2689 { 2690 <a class="btn btn-orange w-100" href="javascript:panelFremvisning('@origin');"> 2691 @Translate("Custom.Propertypage.AssetsModal.Header.Showing.ButtonLabel", "Bestil fremvisning") 2692 <img height="20px" width="20px" src="@(iconPath + "icon-arrow-right.svg")" /> 2693 </a> 2694 } 2695 </div> 2696 </div> 2697 <img class="img-fluid d-none d-md-block" src="@Converter.ToString(employeeItem["BilledeUrl"])" data-fallback="@fallbackImage" onerror="handleError(this)" /> 2698 </div> 2699 </section> 2700 } 2701 2702 @*SECTION: Silmilar properties*@ 2703 @{ 2704 int sliderFeedPageId = GetPageIdByNavigationTag("PropertySlider"); 2705 } 2706 @if (sliderFeedPageId > 0) 2707 { 2708 <section class="container property-slider-section"> 2709 <div class="d-flex flex-column justify-content-center align-content-center"> 2710 <h2 class="property-slider-header">@Translate("Custom.PropertySlider.Header", "Se lignende boliger")</h2> 2711 <div class="property-slider-subheader">@Translate("Custom.PropertySlider.Subheader", "- måske gemmer din drømmebolig sig her?")</div> 2712 </div> 2713 <div id="property-slider" class="property-slider" data-slider-feed="@Converter.ToString(sliderFeedPageId)" data-zip-code="@GetString("Ecom:Product:Field.xEjendomAdressePostnummer")" data-property-category="@propCategory" data-product-number="@product.Number"> 2714 <div class="property-slider-skeleton"> 2715 </div> 2716 </div> 2717 </section> 2718 } 2719 2720 @*SECTION: Climate*@ 2721 @if (bolig.ShowClimateCalculator) 2722 { 2723 <section id="climate-calculator-section" class="container climate-calculator-section"> 2724 <div class="climate-calculator"> 2725 <div class="climate-calculator-wrapper d-flex flex-column"> 2726 <h2 class="section-header semi-bold text-left mb-md-0"> 2727 @Translate("Custom.Propertypage.ClimateCalculatorSection.Header", "Prøv Klimaberegner") 2728 </h2> 2729 <div class="divider-orange d-none d-md-block"></div> 2730 <div class="climate-calculator-description"> 2731 @Translate("Custom.Propertypage.ClimateCalculatorSection.Description", "Prøv vores klimaberegner og find de mest rentable energiforbedringer til netop din bolig. Sammensæt dine egne løsninger og se straks den samlede gevinst for både din økonomi og for klimaet.") 2732 </div> 2733 <div class="climate-calculator-button-wrapper"> 2734 <div class="climate-calculator-button-text"> 2735 @Translate("Custom.Propertypage.ClimateCalculatorSection.Button.Text", "Forbedringer til") 2736 <span class="semi-bold">@bolig.Adresse.Replace(",", "")</span> 2737 </div> 2738 <div role="button" class="climate-calculator-button-label" onclick="document.getElementById('climate-calculator-frame').classList.toggle('active');"> 2739 @Translate("Custom.Propertypage.ClimateCalculatorSection.Button.Label", "Vis") 2740 <img src="@(iconPath + "plus-white.svg")" alt="" aria-hidden="true" /> 2741 </div> 2742 </div> 2743 </div> 2744 <img class="img-fluid d-none d-md-block" src="@(imagePath + "climate.png")" data-fallback="@fallbackImage" onerror="handleError(this)" alt="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom.Propertypage.ClimateCalculatorSection.ImageAlt", "Grafik med klimaberegnerikoner"))" /> 2745 <div id="climate-calculator-frame" class="climate-calculator-frame"> 2746 <div class="climate-calculator-divider"></div> 2747 <div id="climate_calculator" data-property-id="@productId" class="climate-calculator-frame-wrapper"></div> 2748 <script type="text/javascript" src="@Converter.ToString(Pageview.Area.Item["ClimateCalculatorScriptUrl"])"></script> 2749 </div> 2750 </div> 2751 </section> 2752 } 2753 2754 @*SECTION: Housing Calculator*@ 2755 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 2756 @using Dynamicweb.Frontend 2757 @using Dynamicweb 2758 @using Dynamicweb.Core 2759 @using Dynamicweb.Core.Encoders 2760 2761 2762 @functions { 2763 void RenderHousingCalculator(string originInput, string translateTagIdentifier = "", string cssClass = "", string scrollElement = "") 2764 { 2765 2766 var currentStep = !string.IsNullOrEmpty(Converter.ToString(Dynamicweb.Context.Current.Request["CurrentStep"])) ? Converter.ToInt32(Dynamicweb.Context.Current.Request["CurrentStep"]) : 1; 2767 var typeSelected = !string.IsNullOrEmpty(Converter.ToString(Dynamicweb.Context.Current.Request["Type"])) ? Converter.ToString(Dynamicweb.Context.Current.Request["Type"]) : ""; 2768 var placementScore = !string.IsNullOrEmpty(Converter.ToString(Dynamicweb.Context.Current.Request["PlacementScore"])) ? Converter.ToInt32(Dynamicweb.Context.Current.Request["PlacementScore"]) : 0; 2769 var insideScore = !string.IsNullOrEmpty(Converter.ToString(Dynamicweb.Context.Current.Request["InsideScore"])) ? Converter.ToInt32(Dynamicweb.Context.Current.Request["InsideScore"]) : 0; 2770 var outsideScore = !string.IsNullOrEmpty(Converter.ToString(Dynamicweb.Context.Current.Request["OutsideScore"])) ? Converter.ToInt32(Dynamicweb.Context.Current.Request["OutsideScore"]) : 0; 2771 var addressId = !string.IsNullOrEmpty(Converter.ToString(Dynamicweb.Context.Current.Request["AddressId"])) ? Converter.ToString(Dynamicweb.Context.Current.Request["AddressId"]) : string.Empty; 2772 var addressText = !string.IsNullOrEmpty(Converter.ToString(Dynamicweb.Context.Current.Request["AddressText"])) ? Converter.ToString(Dynamicweb.Context.Current.Request["AddressText"]) : string.Empty; 2773 var zipCode = !string.IsNullOrEmpty(Converter.ToString(Dynamicweb.Context.Current.Request["ZipCode"])) ? Converter.ToString(Dynamicweb.Context.Current.Request["ZipCode"]) : string.Empty; 2774 2775 int steps = 6; 2776 string translationPrefix = $"Custom.HousingCalculator{translateTagIdentifier}."; 2777 var housingCalculatorFeedId = Dynamicweb.Content.Services.Pages.GetPageByNavigationTag(Custom.Navigation.Config.GetMainSiteAreaId(), "HousingCalculatorFeed")?.ID; 2778 var origin = !string.IsNullOrEmpty(originInput) ? originInput : $"{Context.Current.Session["DP"]} Boligberegner (Global)"; 2779 var iconPath = "/Files/Templates/Designs/rm/assets/images/svg/"; 2780 2781 <section id="housing-calculator" class="@cssClass" housing-calculator> 2782 @*Step 1*@ 2783 <div class="container"> 2784 <div class="housing-wrapper"> 2785 <div class="housing-header d-flex d-lg-none"> 2786 <div class="steps d-flex"> 2787 @for (int i = 1; i <= steps; i++) 2788 { 2789 <div id="housing-step-indicator-@i" class="js-housing-step-indicator-@i step @(currentStep == i ? "active" : "")"> 2790 </div> 2791 } 2792 </div> 2793 </div> 2794 <div id="housing-step-1" class="housing-step-1 @(currentStep == 1 ? "active" : "") d-flex flex-column flex-lg-row gap-5 gap-lg-90"> 2795 <div class="d-flex flex-column w-100 w-lg-50 justify-content-center text-center text-lg-left gap-5 gap-lg-30"> 2796 <div class="body-header body-header__lg">@Translate(translationPrefix + "Step1.Header", "Hvad er din bolig værd lige nu?")</div> 2797 <div class="body-subheader">@Translate(translationPrefix + "Step1.Subheader", "Få et lynhurtigt prisestimat på din bolig. Indtast din adresse og svar på 3 korte spørgsmål om boligens stand – så viser vi dig, hvad den cirka kan handles for i dag")</div> 2798 </div> 2799 <div class="d-flex flex-column w-100 w-lg-50 justify-content-center"> 2800 <div class="label-lg">@Translate(translationPrefix + "Step1.AddressHeader", "Hvor ligger din bolig?")</div> 2801 <div class="address-selector-wrapper"> 2802 <div class="form-group"> 2803 <div class="autocomplete-container w-100 position-relative"> 2804 <span class="autocomplete-icon position-absolute"> 2805 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="22" viewBox="0 0 18 22" fill="none"> 2806 <path d="M9 12C10.6569 12 12 10.6569 12 9C12 7.34315 10.6569 6 9 6C7.34315 6 6 7.34315 6 9C6 10.6569 7.34315 12 9 12Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> 2807 <path d="M9 21C13 17 17 13.4183 17 9C17 4.58172 13.4183 1 9 1C4.58172 1 1 4.58172 1 9C1 13.4183 5 17 9 21Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" /> 2808 </svg> 2809 </span> 2810 <input id="dawa-autocomplete-input-housing-calculator" class="form-control js-adresse" name="autocompleteAdresse" type="search" placeholder="@HtmlEncoder.HtmlAttributeEncode(Translate(translationPrefix + "Address.Placeholder", "Indtast en addresse"))" value="@HtmlEncoder.HtmlAttributeEncode(addressText)" required data-message="@HtmlEncoder.HtmlAttributeEncode(Translate(translationPrefix + "Address.ErrorMessage", "Indtast venligst en gyldig adresse"))" data-feed-id="@housingCalculatorFeedId" /> 2811 </div> 2812 </div> 2813 <div id="address-valuation-error" class="address-valuation-error d-none">@Translate(translationPrefix + ".Step1.CanValuateAddress.Error", "Vi kan desværre ikke beregne en pris på den valgte adresse. Vælg venligst en anden adresse.")</div> 2814 </div> 2815 <div class="disclaimer">@Translate(translationPrefix + "Disclaimer", "Bemærk: Beregneren gælder for almindelige ejerboliger og sommerhuse. Har du en andelsbolig, ideel anpart, landbrug, nybyg eller ejendom med erhverv? Så giv din lokale mægler et kald for en præcis vurdering.")</div> 2816 </div> 2817 </div> 2818 <div id="housing-step-2" class="housing-step-2 @(currentStep == 2 ? "active" : "") d-flex flex-column flex-lg-row gap-5 gap-lg-90"> 2819 <div class="d-flex flex-column w-100 w-lg-50 justify-content-center text-center text-lg-left gap-5 gap-lg-30"> 2820 <div class="body-header">@Translate(translationPrefix + "Step2.Header", "Hvor god er...")</div> 2821 <div class="body-subheader d-flex justify-content-center justify-content-lg-start gap-5"> 2822 @Translate(translationPrefix + "Step2.Subheader", "din bolig's beliggenhed?") 2823 <div class="tooltip-icon" data-toggle="tooltip" title="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(Translate(translationPrefix + ".Step2.TootltipText", "Tænk på afstanden til skole, indkøb og natur. Ligger boligen ugeneret på en rolig vej, eller er der meget støj?"))"> 2824 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" fill="none"> 2825 <path d="M6.8175 6.75C6.99383 6.24875 7.34186 5.82608 7.79997 5.55685C8.25807 5.28762 8.79667 5.1892 9.32038 5.27903C9.84409 5.36886 10.3191 5.64114 10.6613 6.04765C11.0035 6.45415 11.1908 6.96864 11.19 7.5C11.19 9 8.94 9.75 8.94 9.75M9 12.75H9.0075M16.5 9C16.5 13.1421 13.1421 16.5 9 16.5C4.85786 16.5 1.5 13.1421 1.5 9C1.5 4.85786 4.85786 1.5 9 1.5C13.1421 1.5 16.5 4.85786 16.5 9Z" stroke="black" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round" /> 2826 </svg> 2827 </div> 2828 </div> 2829 </div> 2830 <div class="d-flex flex-column w-100 w-lg-50 justify-content-center"> 2831 <div class="slider-container" data-category-label="PlacementScore" data-current-score="@placementScore"> 2832 <svg class="slider" width="100%" height="100%" viewBox="0 0 564 224"> 2833 <defs> 2834 <!-- Gradient for active track --> 2835 <linearGradient id="orangeGradient" gradientUnits="userSpaceOnUse" x1="58" y1="224" x2="506" y2="224"> 2836 <stop offset="0%" style="stop-color:#6B3410;stop-opacity:1" /> 2837 <stop offset="15%" style="stop-color:#A0672A;stop-opacity:1" /> 2838 <stop offset="100%" style="stop-color:#CD853F;stop-opacity:1" /> 2839 </linearGradient> 2840 </defs> 2841 2842 <!-- Background track --> 2843 <path class="slider__track-bg" id="bgTrack" /> 2844 2845 <!-- Active track (updated by JS) --> 2846 <path class="slider__track-active" id="activeTrack" /> 2847 2848 <!-- Dots container --> 2849 <g id="dotsContainer" class="slider__dots"></g> 2850 2851 <!-- Dashed lines container --> 2852 <g id="dashesContainer" class="slider__dashes"></g> 2853 2854 <!-- Labels container --> 2855 <g id="labelsContainer" class="slider__labels"></g> 2856 2857 <!-- Needle/Arrow pointer --> 2858 <g class="slider__needle" id="needle"> 2859 <polygon class="slider__needle-polygon" id="needlePolygon" /> 2860 <circle class="slider__needle-base" cx="282" cy="224" r="14" /> 2861 </g> 2862 2863 <!-- Handle --> 2864 <g class="slider__handle" id="handle"> 2865 <rect class="slider__handle-pill" x="-32" y="-24" width="64" height="48" rx="24" /> 2866 <!-- Left chevron < --> 2867 <line class="slider__handle-arrow" x1="-8" y1="-5" x2="-13" y2="0" /> 2868 <line class="slider__handle-arrow" x1="-13" y1="0" x2="-8" y2="5" /> 2869 <!-- Right chevron > --> 2870 <line class="slider__handle-arrow" x1="8" y1="-5" x2="13" y2="0" /> 2871 <line class="slider__handle-arrow" x1="13" y1="0" x2="8" y2="5" /> 2872 </g> 2873 </svg> 2874 </div> 2875 </div> 2876 </div> 2877 <div id="housing-step-3" class="housing-step-3 @(currentStep == 3 ? "active" : "") d-flex flex-column flex-lg-row gap-5 gap-lg-90"> 2878 <div class="d-flex flex-column w-100 w-lg-50 justify-content-center text-center text-lg-left gap-5 gap-lg-30"> 2879 <div class="body-header">@Translate(translationPrefix + "Step3.Header", "Hvor god er...")</div> 2880 <div class="body-subheader d-flex justify-content-center justify-content-lg-start gap-5"> 2881 @Translate(translationPrefix + "Step3.Subheader", "din bolig's indvendige stand?") 2882 <div class="tooltip-icon" data-toggle="tooltip" title="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(Translate(translationPrefix + ".Step3.TootltipText", "Vurder standen på køkken, bad og gulve. Er boligen helt indflytningsklar, eller trænger den til en kærlig hånd?"))"> 2883 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" fill="none"> 2884 <path d="M6.8175 6.75C6.99383 6.24875 7.34186 5.82608 7.79997 5.55685C8.25807 5.28762 8.79667 5.1892 9.32038 5.27903C9.84409 5.36886 10.3191 5.64114 10.6613 6.04765C11.0035 6.45415 11.1908 6.96864 11.19 7.5C11.19 9 8.94 9.75 8.94 9.75M9 12.75H9.0075M16.5 9C16.5 13.1421 13.1421 16.5 9 16.5C4.85786 16.5 1.5 13.1421 1.5 9C1.5 4.85786 4.85786 1.5 9 1.5C13.1421 1.5 16.5 4.85786 16.5 9Z" stroke="black" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round" /> 2885 </svg> 2886 </div> 2887 </div> 2888 </div> 2889 <div class="d-flex flex-column w-100 w-lg-50 justify-content-center"> 2890 <div class="slider-container" data-category-label="InsideScore" data-current-score="@insideScore"> 2891 <svg class="slider" width="100%" height="100%" viewBox="0 0 564 224"> 2892 <defs> 2893 <!-- Gradient for active track --> 2894 <linearGradient id="orangeGradient" gradientUnits="userSpaceOnUse" x1="58" y1="224" x2="506" y2="224"> 2895 <stop offset="0%" style="stop-color:#6B3410;stop-opacity:1" /> 2896 <stop offset="15%" style="stop-color:#A0672A;stop-opacity:1" /> 2897 <stop offset="100%" style="stop-color:#CD853F;stop-opacity:1" /> 2898 </linearGradient> 2899 </defs> 2900 2901 <!-- Background track --> 2902 <path class="slider__track-bg" id="bgTrack" /> 2903 2904 <!-- Active track (updated by JS) --> 2905 <path class="slider__track-active" id="activeTrack" /> 2906 2907 <!-- Dots container --> 2908 <g id="dotsContainer" class="slider__dots"></g> 2909 2910 <!-- Dashed lines container --> 2911 <g id="dashesContainer" class="slider__dashes"></g> 2912 2913 <!-- Labels container --> 2914 <g id="labelsContainer" class="slider__labels"></g> 2915 2916 <!-- Needle/Arrow pointer --> 2917 <g class="slider__needle" id="needle"> 2918 <polygon class="slider__needle-polygon" id="needlePolygon" /> 2919 <circle class="slider__needle-base" cx="282" cy="224" r="14" /> 2920 </g> 2921 2922 <!-- Handle --> 2923 <g class="slider__handle" id="handle"> 2924 <rect class="slider__handle-pill" x="-32" y="-24" width="64" height="48" rx="24" /> 2925 <!-- Left chevron < --> 2926 <line class="slider__handle-arrow" x1="-8" y1="-5" x2="-13" y2="0" /> 2927 <line class="slider__handle-arrow" x1="-13" y1="0" x2="-8" y2="5" /> 2928 <!-- Right chevron > --> 2929 <line class="slider__handle-arrow" x1="8" y1="-5" x2="13" y2="0" /> 2930 <line class="slider__handle-arrow" x1="13" y1="0" x2="8" y2="5" /> 2931 </g> 2932 </svg> 2933 </div> 2934 </div> 2935 </div> 2936 <div id="housing-step-4" class="housing-step-4 @(currentStep == 4 ? "active" : "") d-flex flex-column flex-lg-row gap-5 gap-lg-90"> 2937 <div class="d-flex flex-column w-100 w-lg-50 justify-content-center text-center text-lg-left gap-5 gap-lg-30"> 2938 <div class="body-header">@Translate(translationPrefix + "Step4.Header", "Hvor god er...")</div> 2939 <div class="body-subheader d-flex justify-content-center justify-content-lg-start gap-5"> 2940 @Translate(translationPrefix + "Step4.Subheader", "din bolig's udvendige stand?") 2941 <div class="tooltip-icon" data-toggle="tooltip" title="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(Translate(translationPrefix + ".Step4.TootltipText", "Hvordan fremstår facaden, taget og vinduerne? Tag også højde for, om haven, terrassen eller altanen er velholdt."))"> 2942 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" fill="none"> 2943 <path d="M6.8175 6.75C6.99383 6.24875 7.34186 5.82608 7.79997 5.55685C8.25807 5.28762 8.79667 5.1892 9.32038 5.27903C9.84409 5.36886 10.3191 5.64114 10.6613 6.04765C11.0035 6.45415 11.1908 6.96864 11.19 7.5C11.19 9 8.94 9.75 8.94 9.75M9 12.75H9.0075M16.5 9C16.5 13.1421 13.1421 16.5 9 16.5C4.85786 16.5 1.5 13.1421 1.5 9C1.5 4.85786 4.85786 1.5 9 1.5C13.1421 1.5 16.5 4.85786 16.5 9Z" stroke="black" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round" /> 2944 </svg> 2945 </div> 2946 </div> 2947 </div> 2948 <div class="d-flex flex-column w-100 w-lg-50 justify-content-center"> 2949 <div class="slider-container" data-category-label="OutsideScore" data-current-score="@outsideScore"> 2950 <svg class="slider" width="100%" height="100%" viewBox="0 0 564 224"> 2951 <defs> 2952 <!-- Gradient for active track --> 2953 <linearGradient id="orangeGradient" gradientUnits="userSpaceOnUse" x1="58" y1="224" x2="506" y2="224"> 2954 <stop offset="0%" style="stop-color:#6B3410;stop-opacity:1" /> 2955 <stop offset="15%" style="stop-color:#A0672A;stop-opacity:1" /> 2956 <stop offset="100%" style="stop-color:#CD853F;stop-opacity:1" /> 2957 </linearGradient> 2958 </defs> 2959 2960 <!-- Background track --> 2961 <path class="slider__track-bg" id="bgTrack" /> 2962 2963 <!-- Active track (updated by JS) --> 2964 <path class="slider__track-active" id="activeTrack" /> 2965 2966 <!-- Dots container --> 2967 <g id="dotsContainer" class="slider__dots"></g> 2968 2969 <!-- Dashed lines container --> 2970 <g id="dashesContainer" class="slider__dashes"></g> 2971 2972 <!-- Labels container --> 2973 <g id="labelsContainer" class="slider__labels"></g> 2974 2975 <!-- Needle/Arrow pointer --> 2976 <g class="slider__needle" id="needle"> 2977 <polygon class="slider__needle-polygon" id="needlePolygon" /> 2978 <circle class="slider__needle-base" cx="282" cy="224" r="14" /> 2979 </g> 2980 2981 <!-- Handle --> 2982 <g class="slider__handle" id="handle"> 2983 <rect class="slider__handle-pill" x="-32" y="-24" width="64" height="48" rx="24" /> 2984 <!-- Left chevron < --> 2985 <line class="slider__handle-arrow" x1="-8" y1="-5" x2="-13" y2="0" /> 2986 <line class="slider__handle-arrow" x1="-13" y1="0" x2="-8" y2="5" /> 2987 <!-- Right chevron > --> 2988 <line class="slider__handle-arrow" x1="8" y1="-5" x2="13" y2="0" /> 2989 <line class="slider__handle-arrow" x1="13" y1="0" x2="8" y2="5" /> 2990 </g> 2991 </svg> 2992 </div> 2993 </div> 2994 </div> 2995 <div id="housing-step-5" class="housing-step-5 @(currentStep == 5 ? "active" : "") d-flex flex-column flex-lg-row gap-5 gap-lg-90"> 2996 <div class="d-flex flex-column w-100 w-lg-50 justify-content-center text-center text-lg-left gap-5 gap-lg-30"> 2997 <div class="body-header">@Translate(translationPrefix + "Step5.Header", "Hvilken type bolig bor du i?")</div> 2998 </div> 2999 <div class="d-flex flex-column w-100 w-lg-50 justify-content-center"> 3000 @{ 3001 var housingCategories = new[] 3002 { 3003 new { Type = "villa", TranslationKey = "Villa", DefaultText = "Villa" }, 3004 new { Type = "ejerlejlighed", TranslationKey = "Appartment", DefaultText = "Ejerlejlighed" }, 3005 new { Type = "rækkehus", TranslationKey = "TerracedHouse", DefaultText = "Rækkehus" }, 3006 new { Type = "fritidshus", TranslationKey = "VacationHome", DefaultText = "Fritidshus" } 3007 }; 3008 3009 var hasUserSelection = !string.IsNullOrEmpty(typeSelected); 3010 var selected = hasUserSelection ? typeSelected : housingCategories.First().Type; 3011 } 3012 3013 <div class="housing-categories"> 3014 @foreach (var category in housingCategories) 3015 { 3016 3017 @if (category.Type == selected) 3018 { 3019 <script> 3020 document.addEventListener('DOMContentLoaded',() => updateQueryParam('Type', '@category.Type')); 3021 </script> 3022 } 3023 3024 <label class="housing-category cursor-pointer" onclick="updateQueryParam('Type', '@category.Type')"> 3025 <input type="radio" class="d-none" name="housing-category" @(category.Type == selected ? "checked" : "") /> 3026 <div class="housing-icon"> 3027 <img src="@(iconPath + "housingcategory-" + category.Type + ".svg")" alt="@HtmlEncoder.HtmlAttributeEncode(Translate(translationPrefix + "HousingCategory." + category.TranslationKey, category.DefaultText))" /> 3028 </div> 3029 @Translate(translationPrefix + "HousingCategory." + category.TranslationKey, category.DefaultText) 3030 </label> 3031 } 3032 </div> 3033 </div> 3034 </div> 3035 <div id="housing-step-6" class="housing-step-6 @(currentStep == 6 ? "active" : "") d-flex flex-column flex-lg-row gap-5 gap-lg-90"> 3036 @{ 3037 var href = !string.IsNullOrEmpty(scrollElement) ? $"#{scrollElement}" : "javascript:panelSalgsvurdering('" + HtmlEncoder.JavaScriptStringEncode(origin.Trim()) + "');"; 3038 } 3039 <input type="hidden" id="panel-salgsvurdering-address-id" value="@addressId" /> 3040 @if (!string.IsNullOrEmpty(scrollElement)) 3041 { 3042 <input type="hidden" class="js-housingcalculator-origin" value="@origin" /> 3043 } 3044 <div class="d-flex flex-column w-100 w-lg-50 justify-content-center text-center text-lg-left gap-5 gap-lg-30"> 3045 <div class="body-header body-header__md">@Translate(translationPrefix + "Step6.Header", "Vil du have den korrekte pris?")</div> 3046 <div class="body-subheader d-flex justify-content-center justify-content-lg-start gap-5"> 3047 @Translate(translationPrefix + "Step6.Subheader", "Kontakt os allerede i dag for en gratis og uforpligtende vurdering. Her får du den rigtige pris.") 3048 </div> 3049 <a class="btn-orange d-none d-lg-block text-nowrap" href="@href" onclick="updateSalesAssessment();"> 3050 @Translate(translationPrefix + ".SalesAssessment.ButtonLabel", "Bestil gratis salgsvurdering") 3051 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none"> 3052 <path d="M3.33301 10H16.6663M16.6663 10L11.6663 5M16.6663 10L11.6663 15" stroke="white" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round" /> 3053 </svg> 3054 </a> 3055 </div> 3056 <div class="d-flex flex-column w-100 w-lg-50 justify-content-center housing-calculation"> 3057 <div class="housing-calculation-header d-flex justify-content-center gap-5 mb-3"> 3058 @Translate(translationPrefix + ".Calculation.Header", "Vi anslår prisen til at være") 3059 <div class="tooltip-icon" data-toggle="tooltip" title="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(Translate(translationPrefix + ".Step6.TootltipText", "Estimatet bygger på offentlige data, gennemsnitspriser i dit postnummer og de oplysninger, du lige har indtastet."))"> 3060 <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18" fill="none"> 3061 <path d="M6.8175 6.75C6.99383 6.24875 7.34186 5.82608 7.79997 5.55685C8.25807 5.28762 8.79667 5.1892 9.32038 5.27903C9.84409 5.36886 10.3191 5.64114 10.6613 6.04765C11.0035 6.45415 11.1908 6.96864 11.19 7.5C11.19 9 8.94 9.75 8.94 9.75M9 12.75H9.0075M16.5 9C16.5 13.1421 13.1421 16.5 9 16.5C4.85786 16.5 1.5 13.1421 1.5 9C1.5 4.85786 4.85786 1.5 9 1.5C13.1421 1.5 16.5 4.85786 16.5 9Z" stroke="black" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round" /> 3062 </svg> 3063 </div> 3064 </div> 3065 <div class="js-housing-calculation d-flex justify-content-center w-100 h-100" data-feed-id="@housingCalculatorFeedId"> 3066 <div class="d-flex flex-column align-items-center justify-content-center"> 3067 <div class="preloader-text mb-4">@Translate(translationPrefix + ".Calculation.Loading", "Beregner pris")</div> 3068 <div class="dots"> 3069 <div class="dot"></div> 3070 <div class="dot"></div> 3071 <div class="dot"></div> 3072 </div> 3073 </div> 3074 </div> 3075 </div> 3076 <div class="d-flex flex-column w-100 text-center d-lg-none"> 3077 <a class="btn-orange mt-5 mt-lg-0" href="@href" onclick="updateSalesAssessment();"> 3078 @Translate(translationPrefix + ".SalesAssessment.ButtonLabel", "Bestil gratis salgsvurdering") 3079 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none"> 3080 <path d="M3.33301 10H16.6663M16.6663 10L11.6663 5M16.6663 10L11.6663 15" stroke="white" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round" /> 3081 </svg> 3082 </a> 3083 </div> 3084 </div> 3085 <div class="housing-footer align-items-center"> 3086 <div class="justify-self-start d-flex d-lg-block w-100 w-lg-0"> 3087 <button id="housing-prev-button" class="btn-white @(currentStep == 1 ? "d-none" : "d-flex")" onclick="goToPreviousStep('@currentStep')"> 3088 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none"> 3089 <path d="M16.6666 10H3.33325M3.33325 10L8.33325 15M3.33325 10L8.33325 5" stroke="black" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round" /> 3090 </svg> 3091 @Translate(translationPrefix + "Step1.PreviousButton.Label", "Tilbage") 3092 </button> 3093 </div> 3094 <div class="steps d-none d-lg-flex justify-content-center"> 3095 @for (int i = 1; i <= steps; i++) 3096 { 3097 <div id="housing-step-indicator-@i" class="js-housing-step-indicator-@i step @(currentStep == i ? "active" : "")"> 3098 </div> 3099 } 3100 </div> 3101 <div class="justify-self-end d-flex d-lg-block w-100 w-lg-0"> 3102 <button id="housing-next-button" class="btn-orange @(currentStep == 6 ? "d-none" : "d-flex")" @(!string.IsNullOrEmpty(addressId) ? "" : "disabled") data-first-step-text="@Translate(translationPrefix + "Step.StartButton.Label", "Start")" data-next-step-text="@Translate(translationPrefix + "Step.NextButton.Label", "Næste")" onclick="goToNextStep('@currentStep')"> 3103 <span class="button-text"> 3104 @if (currentStep == 1) 3105 { 3106 @Translate(translationPrefix + "Step.StartButton.Label", "Start") 3107 } 3108 else 3109 { 3110 @Translate(translationPrefix + "Step.NextButton.Label", "Næste") 3111 } 3112 </span> 3113 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none"> 3114 <path d="M3.33337 10H16.6667M16.6667 10L11.6667 5M16.6667 10L11.6667 15" stroke="white" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round" /> 3115 </svg> 3116 </button> 3117 </div> 3118 </div> 3119 </div> 3120 </div> 3121 </section> 3122 3123 <script> 3124 3125 @if (currentStep == 6) 3126 { 3127 <text> 3128 makeCalculation(); 3129 </text> 3130 } 3131 3132 @if (!string.IsNullOrEmpty(addressId)) 3133 { 3134 <text> 3135 const addressInputElement = document.getElementById('dawa-autocomplete-input-housing-calculator'); 3136 3137 if (addressInputElement?.dataset?.feedId) { 3138 preValidateAddress('@HtmlEncoder.JavaScriptStringEncode(addressId)', addressInputElement.dataset.feedId); 3139 } 3140 </text> 3141 } 3142 3143 3144 3145 window.addEventListener("load", () => { 3146 initFeed(); 3147 }); 3148 3149 function updateSalesAssessment() { 3150 // Check if salesassessment autocomplete is present on the site and add address to field and update relevant fields. 3151 const mainAutoComplete = document.querySelector('#bestil-salgsvurdering #dawa-autocomplete-input'); 3152 const urlParams = new URLSearchParams(window.location.search); 3153 const selectedAddressId = urlParams.get('AddressId'); 3154 3155 if (mainAutoComplete && selectedAddressId) { 3156 mainAutoComplete.setAttribute('data-preselected-address-id', selectedAddressId); 3157 initAutoComplete(); 3158 3159 //change origin to housing calculator 3160 const originInput = document.querySelector('.js-salgsvurdering-origin'); 3161 const originSource = document.querySelector('.js-housingcalculator-origin'); 3162 3163 if (originInput && originSource) { 3164 originInput.value = `KH ${originSource.value} : ${originInput.value}`; 3165 } 3166 3167 //set values for inboxhandler 3168 const form = document.querySelector('.js-buyer-advisor-form'); 3169 if (form) { 3170 const placementScoreInput = form.querySelector('.js-housingcalculator-result-placement-score'); 3171 const insideScoreInput = form.querySelector('.js-housingcalculator-result-inside-score'); 3172 const outsideScoreInput = form.querySelector('.js-housingcalculator-result-outside-score'); 3173 const minPriceInput = form.querySelector('.js-housingcalculator-result-min-price'); 3174 const maxPriceInput = form.querySelector('.js-housingcalculator-result-max-price'); 3175 3176 if (placementScoreInput) { 3177 placementScoreInput.value = urlParams.get('PlacementScore'); 3178 } 3179 3180 if (insideScoreInput) { 3181 insideScoreInput.value = urlParams.get('InsideScore'); 3182 } 3183 3184 if (outsideScoreInput) { 3185 outsideScoreInput.value = urlParams.get('OutsideScore'); 3186 } 3187 3188 const calculationResult = document.querySelector('.js-range-slider-container'); 3189 3190 if (calculationResult) { 3191 3192 if (minPriceInput) { 3193 minPriceInput.value = calculationResult.dataset.min; 3194 } 3195 3196 if (maxPriceInput) { 3197 maxPriceInput.value = calculationResult.dataset.max; 3198 } 3199 } 3200 } 3201 } 3202 } 3203 3204 function initFeed() { 3205 var addressInputElement = document.getElementById('dawa-autocomplete-input-housing-calculator'); 3206 3207 if (addressInputElement) { 3208 3209 var component = dawaAutoComplete.dawaAutocomplete(addressInputElement, { 3210 id: '@HtmlEncoder.JavaScriptStringEncode(addressId)', 3211 select: function (selected) { 3212 3213 const selectedZipCode = selected.data.postnr; 3214 3215 if (selectedZipCode) { 3216 updateQueryParam('ZipCode', selectedZipCode); 3217 } 3218 3219 const selectedAddressId = selected.data.id; 3220 const selectedAddressText = selected.tekst || selected.forslagstekst || (selected.data && selected.data.adressebetegnelse) || addressInputElement.value; 3221 3222 if (selectedAddressId) { 3223 if (preValidateAddress(selectedAddressId, addressInputElement.dataset.feedId)) { 3224 updateQueryParam('AddressId', selectedAddressId); 3225 updateQueryParam('AddressText', selectedAddressText); 3226 const addressIdInput = document.getElementById('panel-salgsvurdering-address-id'); 3227 if (addressIdInput) { 3228 addressIdInput.value = selectedAddressId; 3229 } 3230 3231 }; 3232 } 3233 } 3234 }); 3235 } 3236 3237 3238 const scoreSliders = document.querySelectorAll('.slider-container').forEach(slider => { 3239 initializeSlider(slider); 3240 slider.addEventListener('scoreSelected', (e) => { 3241 updateQueryParam(e.detail.label, e.detail.score); 3242 }); 3243 }); 3244 } 3245 3246 function updateQueryParam(key, value) { 3247 const url = new URL(window.location.href); 3248 3249 // URLSearchParams handles ? and & automatically 3250 if (value !== null && value !== undefined && value !== '') { 3251 url.searchParams.set(key, value); 3252 } else { 3253 url.searchParams.delete(key); 3254 } 3255 3256 window.history.pushState({}, '', url.toString()); 3257 } 3258 3259 async function preValidateAddress(addressId, feedId) { 3260 3261 if (!addressId || !feedId) return false; 3262 3263 const url = window.location.origin + "/Default.aspx?ID=" + feedId + "&AddressId=" + addressId + "&PreValidate=true"; 3264 3265 const nextButton = document.getElementById('housing-next-button'); 3266 3267 if (nextButton) { 3268 nextButton.style.minWidth = nextButton.clientWidth + 'px'; 3269 nextButton.classList.add('loading'); 3270 } 3271 3272 try { 3273 const result = await fetch(url); 3274 3275 if (!result.ok) { 3276 handlePreValidationError(); 3277 throw new Error('Network response was not ok'); 3278 } 3279 3280 const response = await result.json(); 3281 3282 if (response.ArealTilBeboelseM2 == null || response.ArealTilBeboelseM2 <= 0) { 3283 handlePreValidationError(); 3284 } 3285 else { 3286 handlePreValidationSuccess(); 3287 } 3288 3289 } catch (error) { 3290 handlePreValidationError(); 3291 console.error('Error loading valuation status:', error); 3292 } 3293 } 3294 3295 function handlePreValidationError() { 3296 const errorElement = document.getElementById('address-valuation-error'); 3297 const nextButton = document.getElementById('housing-next-button'); 3298 3299 if (errorElement) { 3300 errorElement.classList.add('d-block'); 3301 errorElement.classList.remove('d-none'); 3302 3303 } 3304 3305 if (nextButton) { 3306 nextButton.disabled = true; 3307 nextButton.classList.remove('loading'); 3308 nextButton.style.minWidth = ''; 3309 } 3310 } 3311 3312 function handlePreValidationSuccess() { 3313 const errorElement = document.getElementById('address-valuation-error'); 3314 const nextButton = document.getElementById('housing-next-button'); 3315 3316 if (errorElement) { 3317 errorElement.classList.remove('d-block'); 3318 errorElement.classList.add('d-none'); 3319 } 3320 3321 if (nextButton) { 3322 nextButton.disabled = false; 3323 nextButton.classList.remove('loading'); 3324 nextButton.style.minWidth = ''; 3325 } 3326 3327 } 3328 3329 async function makeCalculation() { 3330 const housingCalculationElement = document.querySelector('.js-housing-calculation'); 3331 3332 if (housingCalculationElement) { 3333 3334 const feedId = housingCalculationElement.dataset.feedId; 3335 3336 if (parseFloat(feedId) > 0) { 3337 3338 const currentParams = new URLSearchParams(window.location.search); 3339 const url = window.location.origin + "/Default.aspx?ID=" + feedId + "&" + currentParams.toString(); 3340 3341 try { 3342 const result = await fetch(url); 3343 if (!result.ok) throw new Error('Network response was not ok'); 3344 const response = await result.text(); 3345 const parser = new DOMParser(); 3346 const doc = parser.parseFromString(response, 'text/html'); 3347 const responseFeedElement = doc.querySelector('.js-housing-calculation-feed'); 3348 3349 if (responseFeedElement) { 3350 housingCalculationElement.innerHTML = responseFeedElement.innerHTML; 3351 } 3352 3353 housingCalculationElement.querySelectorAll('script').forEach((script) => { 3354 const newScript = document.createElement('script'); 3355 if (script.src) { 3356 newScript.src = script.src; 3357 newScript.onload = () => document.body.removeChild(newScript); 3358 newScript.onerror = () => document.body.removeChild(newScript); 3359 } else { 3360 newScript.textContent = script.textContent; 3361 } 3362 document.body.appendChild(newScript); 3363 // Only remove inline scripts immediately — external scripts are removed via onload/onerror 3364 if (!script.src) { 3365 document.body.removeChild(newScript); 3366 } 3367 }); 3368 3369 } catch (error) { 3370 console.error('Error making calculation:', error); 3371 } 3372 } 3373 } 3374 } 3375 3376 function goToNextStep(currentStep) { 3377 3378 currentStep = parseFloat(localStorage.getItem('housingStep')) || parseFloat(currentStep); 3379 const nextStep = (parseFloat(localStorage.getItem('housingStep')) || parseFloat(currentStep)) + 1; 3380 3381 localStorage.setItem('housingStep', nextStep); 3382 updateQueryParam('CurrentStep', nextStep); 3383 3384 const currentElement = document.getElementById('housing-step-' + currentStep); 3385 const nextElement = document.getElementById('housing-step-' + nextStep); 3386 3387 if (currentElement && nextElement) { 3388 currentElement.classList.remove('active'); 3389 nextElement.classList.add('active'); 3390 3391 if (nextStep > 1) { 3392 const prevButton = document.getElementById('housing-prev-button'); 3393 if (prevButton) { 3394 prevButton.classList.add('d-flex'); 3395 prevButton.classList.remove('d-none'); 3396 } 3397 3398 const nextButton = document.getElementById('housing-next-button'); 3399 3400 if (nextButton) { 3401 const nextButtonText = nextButton.querySelector('.button-text'); 3402 3403 if (nextButtonText) { 3404 nextButtonText.innerHTML = nextButton.dataset.nextStepText; 3405 } 3406 } 3407 } 3408 3409 if (nextStep == 6) { 3410 makeCalculation(); 3411 } 3412 } 3413 3414 updateStepElements(currentStep, nextStep); 3415 } 3416 3417 function goToPreviousStep(currentStep) { 3418 currentStep = parseFloat(localStorage.getItem('housingStep')) || parseFloat(currentStep); 3419 const prevStep = (parseFloat(localStorage.getItem('housingStep')) || parseFloat(currentStep)) - 1; 3420 3421 localStorage.setItem('housingStep', prevStep); 3422 updateQueryParam('CurrentStep', prevStep); 3423 3424 const currentElement = document.getElementById('housing-step-' + currentStep); 3425 const prevElement = document.getElementById('housing-step-' + prevStep); 3426 3427 if (currentElement && prevElement) { 3428 currentElement.classList.remove('active'); 3429 prevElement.classList.add('active'); 3430 3431 if (prevStep == 1) { 3432 const prevButton = document.getElementById('housing-prev-button'); 3433 3434 if (prevButton) { 3435 prevButton.classList.add('d-none'); 3436 prevButton.classList.remove('d-flex'); 3437 } 3438 } 3439 3440 if (prevStep < 6) { 3441 const nextButton = document.getElementById('housing-next-button'); 3442 if (nextButton) { 3443 nextButton.classList.add('d-flex'); 3444 nextButton.classList.remove('d-none'); 3445 3446 if (prevStep == 1) { 3447 const nextButtonText = nextButton.querySelector('.button-text'); 3448 3449 if (nextButtonText) { 3450 nextButtonText.innerHTML = nextButton.dataset.firstStepText; 3451 } 3452 } 3453 } 3454 } 3455 3456 updateStepElements(currentStep, prevStep); 3457 } 3458 } 3459 3460 function updateStepElements(currentStep, nextStep) { 3461 const currentStepElements = document.querySelectorAll('.js-housing-step-indicator-' + currentStep); 3462 const nextStepElements = document.querySelectorAll('.js-housing-step-indicator-' + nextStep); 3463 3464 currentStepElements.forEach(currentStepElement => { 3465 currentStepElement.classList.remove('active'); 3466 }); 3467 3468 nextStepElements.forEach(nextStepElement => { 3469 nextStepElement.classList.add('active'); 3470 }); 3471 3472 if (nextStep == 6) { 3473 const nextButton = document.getElementById('housing-next-button'); 3474 3475 if (nextButton) { 3476 nextButton.classList.add('d-none'); 3477 nextButton.classList.remove('d-flex'); 3478 } 3479 } 3480 3481 } 3482 </script> 3483 3484 <script> 3485 function initializeSlider(sliderContainer) { 3486 const totalSteps = 9; 3487 const radius = 224; 3488 const centerX = 282; 3489 const centerY = 224; 3490 const labelRadius = 294; 3491 3492 const currentScore = parseFloat(sliderContainer.dataset.currentScore || '0'); 3493 let currentStep = getScoreStep(currentScore); 3494 let isDragging = false; 3495 let animationFrameId = null; 3496 3497 const handle = sliderContainer.querySelector('.slider__handle'); 3498 const needle = sliderContainer.querySelector('.slider__needle'); 3499 const needlePolygon = sliderContainer.querySelector('.slider__needle-polygon'); 3500 const activeTrack = sliderContainer.querySelector('.slider__track-active'); 3501 const bgTrack = sliderContainer.querySelector('.slider__track-bg'); 3502 let dotsContainer = sliderContainer.querySelector('.slider__dots'); 3503 const dashesContainer = sliderContainer.querySelector('.slider__dashes'); 3504 const labelsContainer = sliderContainer.querySelector('.slider__labels'); 3505 const categoryLabel = sliderContainer.dataset.categoryLabel; 3506 3507 const stepLabels = { 3508 0: '@Translate(translationPrefix + "Slider.Label.Worst","Dårlig")', 3509 2: '@Translate(translationPrefix + "Slider.Label.Worse","Mindre god")', 3510 4: '@Translate(translationPrefix + "Slider.Label.Medium", "Mellem")', 3511 6: '@Translate(translationPrefix + "Slider.Label.Good","God")', 3512 8: '@Translate(translationPrefix + "Slider.Label.Perfect", "Perfekt")' 3513 }; 3514 3515 const intermediateSteps = [1, 3, 5, 7]; 3516 3517 function getStepScore(step) { 3518 switch (step) { 3519 case 0: return -4; 3520 case 1: return -3; 3521 case 2: return -2; 3522 case 3: return -1; 3523 case 4: return 0; 3524 case 5: return 1; 3525 case 6: return 2; 3526 case 7: return 3; 3527 case 8: return 4; 3528 default: return 0; 3529 } 3530 } 3531 3532 function getScoreStep(score) { 3533 switch (score) { 3534 case -4: return 0; 3535 case -3: return 1; 3536 case -2: return 2; 3537 case -1: return 3; 3538 case 0: return 4; 3539 case 1: return 5; 3540 case 2: return 6; 3541 case 3: return 7; 3542 case 4: return 8; 3543 default: return 4; 3544 } 3545 } 3546 3547 function getStepAngle(step) { 3548 return (step / (totalSteps - 1)) * 180; 3549 } 3550 3551 function getPosition(angle, rad = radius) { 3552 const radians = (angle + 180) * (Math.PI / 180); 3553 return { 3554 x: centerX + Math.cos(radians) * rad, 3555 y: centerY + Math.sin(radians) * rad 3556 }; 3557 } 3558 3559 function getNearestStep(angle) { 3560 const stepSize = 180 / (totalSteps - 1); 3561 const step = Math.round(angle / stepSize); 3562 return Math.max(0, Math.min(totalSteps - 1, step)); 3563 } 3564 3565 function getAngleFromEvent(e) { 3566 const rect = sliderContainer.getBoundingClientRect(); 3567 const clientX = e.touches ? e.touches[0].clientX : e.clientX; 3568 const clientY = e.touches ? e.touches[0].clientY : e.clientY; 3569 3570 const relativeX = clientX - rect.left - rect.width / 2; 3571 const relativeY = clientY - rect.top - centerY; 3572 3573 let angle = Math.atan2(relativeY, relativeX) * (180 / Math.PI); 3574 3575 if (angle < 0) angle += 360; 3576 3577 if (angle >= 180) { 3578 return angle - 180; 3579 } else { 3580 return angle < 90 ? 180 : 0; 3581 } 3582 } 3583 3584 function createArcPath(startAngle, endAngle) { 3585 const start = getPosition(startAngle); 3586 const end = getPosition(endAngle); 3587 const largeArc = endAngle - startAngle > 180 ? 1 : 0; 3588 return `M ${start.x} ${start.y} A ${radius} ${radius} 0 ${largeArc} 1 ${end.x} ${end.y}`; 3589 } 3590 3591 function initializeSliderElements() { 3592 bgTrack.setAttribute('d', createArcPath(0, 180)); 3593 activeTrack.setAttribute('d', createArcPath(0, 180)); 3594 3595 const semicircleLength = Math.PI * radius; 3596 activeTrack.style.strokeDasharray = semicircleLength; 3597 activeTrack.style.strokeDashoffset = semicircleLength; 3598 3599 // Create dots 3600 intermediateSteps.forEach(step => { 3601 const angle = getStepAngle(step); 3602 const pos = getPosition(angle, labelRadius); 3603 3604 const dot = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); 3605 dot.classList.add('slider__dot'); 3606 dot.setAttribute('cx', pos.x); 3607 dot.setAttribute('cy', pos.y); 3608 dot.setAttribute('r', 5); 3609 dot.dataset.step = step; 3610 dotsContainer.appendChild(dot); 3611 }); 3612 3613 // Create labels with dashed lines 3614 Object.entries(stepLabels).forEach(([step, label]) => { 3615 const stepNum = parseInt(step); 3616 const angle = getStepAngle(stepNum); 3617 const pos = getPosition(angle, labelRadius); 3618 3619 const spacingAngle = 2; 3620 3621 // Left dash 3622 if (intermediateSteps.includes(stepNum - 1)) { 3623 const dotAngle = getStepAngle(stepNum - 1); 3624 const startAngle = angle - spacingAngle; 3625 const endAngle = dotAngle + spacingAngle; 3626 3627 const startPos = getPosition(startAngle, labelRadius); 3628 const endPos = getPosition(endAngle, labelRadius); 3629 3630 const angleSpan = Math.abs(startAngle - endAngle) * (Math.PI / 180); 3631 const arcLength = labelRadius * angleSpan; 3632 const dashLength = arcLength * 0.35; 3633 const gapLength = arcLength * 0.15; 3634 3635 const dashPath = document.createElementNS('http://www.w3.org/2000/svg', 'path'); 3636 dashPath.classList.add('slider__dash'); 3637 dashPath.setAttribute('d', `M ${startPos.x} ${startPos.y} A ${labelRadius} ${labelRadius} 0 0 0 ${endPos.x} ${endPos.y}`); 3638 dashPath.setAttribute('stroke-dasharray', `${dashLength} ${gapLength} ${dashLength} ${gapLength}`); 3639 dashesContainer.appendChild(dashPath); 3640 } 3641 3642 // Right dash 3643 if (intermediateSteps.includes(stepNum + 1)) { 3644 const dotAngle = getStepAngle(stepNum + 1); 3645 const startAngle = angle + spacingAngle; 3646 const endAngle = dotAngle - spacingAngle; 3647 3648 const startPos = getPosition(startAngle, labelRadius); 3649 const endPos = getPosition(endAngle, labelRadius); 3650 3651 const angleSpan = Math.abs(startAngle - endAngle) * (Math.PI / 180); 3652 const arcLength = labelRadius * angleSpan; 3653 const dashLength = arcLength * 0.35; 3654 const gapLength = arcLength * 0.15; 3655 3656 const dashPath = document.createElementNS('http://www.w3.org/2000/svg', 'path'); 3657 dashPath.classList.add('slider__dash'); 3658 dashPath.setAttribute('d', `M ${startPos.x} ${startPos.y} A ${labelRadius} ${labelRadius} 0 0 1 ${endPos.x} ${endPos.y}`); 3659 dashPath.setAttribute('stroke-dasharray', `${dashLength} ${gapLength} ${dashLength} ${gapLength}`); 3660 dashesContainer.appendChild(dashPath); 3661 } 3662 3663 // Create label 3664 const text = document.createElementNS('http://www.w3.org/2000/svg', 'text'); 3665 text.classList.add('slider__label'); 3666 if (stepNum === currentStep) { 3667 text.classList.add('active'); 3668 } 3669 text.setAttribute('x', pos.x); 3670 text.setAttribute('y', pos.y + 6); 3671 text.dataset.step = stepNum; 3672 text.textContent = label; 3673 labelsContainer.appendChild(text); 3674 }); 3675 3676 // Create needle polygon 3677 const needleLength = radius * 0.5; 3678 const gapFromCenter = 20; 3679 const points = `${centerX - 4},${centerY - gapFromCenter} ${centerX + 4},${centerY - gapFromCenter} ${centerX + 1},${centerY - needleLength - gapFromCenter} ${centerX - 1},${centerY - needleLength - gapFromCenter}`; 3680 needlePolygon.setAttribute('points', points); 3681 } 3682 3683 function updateSlider(angle) { 3684 if (animationFrameId) { 3685 cancelAnimationFrame(animationFrameId); 3686 } 3687 3688 animationFrameId = requestAnimationFrame(() => { 3689 const pos = getPosition(angle); 3690 3691 const semicircleLength = Math.PI * radius; 3692 const angleRatio = angle / 180; 3693 const visibleLength = semicircleLength * angleRatio; 3694 activeTrack.style.strokeDashoffset = semicircleLength - visibleLength; 3695 3696 handle.style.transform = `translate(${pos.x}px, ${pos.y}px)`; 3697 3698 const angleToHandle = Math.atan2(pos.y - centerY, pos.x - centerX) * (180 / Math.PI); 3699 const rotationAngle = angleToHandle + 90; 3700 needle.style.transform = `rotate(${rotationAngle}deg)`; 3701 3702 sliderContainer.querySelectorAll('.slider__label').forEach(label => { 3703 const labelStep = parseInt(label.dataset.step); 3704 if (labelStep === currentStep) { 3705 label.classList.add('active'); 3706 } else { 3707 label.classList.remove('active'); 3708 } 3709 }); 3710 3711 sliderContainer.querySelectorAll('.slider__dot').forEach(dot => { 3712 const dotStep = parseInt(dot.dataset.step); 3713 if (dotStep === currentStep) { 3714 dot.classList.add('active'); 3715 dot.setAttribute('r', '7'); 3716 } else { 3717 dot.classList.remove('active'); 3718 dot.setAttribute('r', '5'); 3719 } 3720 }); 3721 3722 const event = new CustomEvent('scoreSelected', { 3723 detail: { 3724 score: getStepScore(currentStep), 3725 label: categoryLabel 3726 }, 3727 bubbles: true 3728 }); 3729 sliderContainer.dispatchEvent(event); 3730 }); 3731 } 3732 3733 function handleStart(e) { 3734 e.preventDefault(); 3735 isDragging = true; 3736 handle.classList.add('dragging'); 3737 needle.classList.add('dragging'); 3738 activeTrack.classList.add('dragging'); 3739 } 3740 3741 function handleMove(e) { 3742 if (!isDragging) return; 3743 e.preventDefault(); 3744 3745 const angle = getAngleFromEvent(e); 3746 currentStep = getNearestStep(angle); 3747 updateSlider(angle, false); 3748 } 3749 3750 function handleEnd(e) { 3751 if (!isDragging) return; 3752 e.preventDefault(); 3753 3754 isDragging = false; 3755 handle.classList.remove('dragging'); 3756 needle.classList.remove('dragging'); 3757 activeTrack.classList.remove('dragging'); 3758 3759 const snapAngle = getStepAngle(currentStep); 3760 updateSlider(snapAngle, true); 3761 } 3762 3763 // Mouse events 3764 handle.addEventListener('mousedown', handleStart); 3765 document.addEventListener('mousemove', handleMove); 3766 document.addEventListener('mouseup', handleEnd); 3767 3768 // Touch events 3769 handle.addEventListener('touchstart', handleStart, { passive: false }); 3770 document.addEventListener('touchmove', handleMove, { passive: false }); 3771 document.addEventListener('touchend', handleEnd, { passive: false }); 3772 3773 // Initialize 3774 initializeSliderElements(); 3775 const initialAngle = getStepAngle(currentStep); 3776 updateSlider(initialAngle); 3777 } 3778 </script> 3779 3780 3781 } 3782 } 3783 3784 3785 @{ 3786 RenderHousingCalculator($"{Context.Current.Session["DP"]} Boligberegner (Emnevisning)", ".PropertyPage", "container"); 3787 } 3788 @*SECTION: Goldbuyer*@ 3789 @{ 3790 var becomeGoldBuyerLink = Dynamicweb.Frontend.PageView.Current().AreaSettings.GetRawValueString("BecomeGoldBuyerLink", ""); 3791 } 3792 3793 @if (!string.IsNullOrEmpty(becomeGoldBuyerLink)) 3794 { 3795 <section class="container goldbuyer-section"> 3796 <div class="goldbuyer"> 3797 <div class="goldbuyer-wrapper d-flex flex-column"> 3798 <h2 class="section-header semi-bold text-left mb-md-0"> 3799 @Translate("Custom.Propertypage.GoldBuyerSection.Header", "Guldkøber&reg;") 3800 </h2> 3801 <div class="divider-orange d-none d-md-block"></div> 3802 <div class="section-usps"> 3803 <div class="d-flex"> 3804 <img class="circle-gold mr-2" height="24px" width="24px" src="@(iconPath + "icon-check.svg")" /> 3805 @Translate("Custom.Propertypage.GoldBuyerSection.Usp1", "Få besked, når en bolig matcher dine ønsker.") 3806 </div> 3807 <div class="d-flex"> 3808 <img class="circle-gold mr-2" height="24px" width="24px" src="@(iconPath + "icon-check.svg")" /> 3809 @Translate("Custom.Propertypage.GoldBuyerSection.Usp2", "Vi overvåger markedet for dig.") 3810 </div> 3811 <div class="d-flex"> 3812 <img class="circle-gold mr-2" height="24px" width="24px" src="@(iconPath + "icon-check.svg")" /> 3813 @Translate("Custom.Propertypage.GoldBuyerSection.Usp3", "Få et nemt køb.") 3814 </div> 3815 </div> 3816 <a class="btn btn-gold align-self-center align-self-md-start" href="/Default.aspx?ID=@becomeGoldBuyerLink"> 3817 @Translate("Custom.Propertypage.GoldBuyerSection.ButtonLabel", "Bliv guldkøber") 3818 <img height="20px" width="20px" src="@(iconPath + "icon-arrow-right.svg")" /> 3819 </a> 3820 </div> 3821 <img class="img-fluid d-none d-md-block" src="@(imagePath + "goldbuyer.jpg")" data-fallback="@fallbackImage" onerror="handleError(this)" /> 3822 </div> 3823 </section> 3824 } 3825 3826 @*SECTION: Buyer Advice*@ 3827 @{ 3828 var rmBuyingAdvicePageId = Dynamicweb.Frontend.PageView.Current().AreaSettings.GetRawValueString("RMBuyingAdviceMasterPageID", ""); 3829 } 3830 3831 @if (!string.IsNullOrEmpty(rmBuyingAdvicePageId)) 3832 { 3833 <section class="container buyeradvice-section"> 3834 <div class="buyeradvice"> 3835 <img class="img-fluid d-none d-md-block" src="@(imagePath + "buyeradvice.jpg")" data-fallback="@fallbackImage" onerror="handleError(this)" /> 3836 <div class="buyeradvice-wrapper d-flex flex-column"> 3837 <h2 class="section-header semi-bold text-left mb-md-0"> 3838 @Translate("Custom.Propertypage.BuyerAdviceSection.Header", "Køber du hos anden mægler? Få ærlig køberrådgivning") 3839 </h2> 3840 <div class="divider-orange d-none d-md-block"></div> 3841 <div class="section-usps"> 3842 <div class="d-flex"> 3843 <img class="circle-blue mr-2" height="24px" width="24px" src="@(iconPath + "icon-check.svg")" /> 3844 @Translate("Custom.Propertypage.BuyerAdviceSection.Usp1", "Vi gennemgår købsaftale, skøde og finansiering, så du undgår skjulte faldgruber og dyre fejl.") 3845 </div> 3846 <div class="d-flex"> 3847 <img class="circle-blue mr-2" height="24px" width="24px" src="@(iconPath + "icon-check.svg")" /> 3848 @Translate("Custom.Propertypage.BuyerAdviceSection.Usp2", "Du får en dedikeret køberrådgiver, som kun arbejder for dig – ikke sælger.") 3849 </div> 3850 <div class="d-flex"> 3851 <img class="circle-blue mr-2" height="24px" width="24px" src="@(iconPath + "icon-check.svg")" /> 3852 @Translate("Custom.Propertypage.BuyerAdviceSection.Usp3", "Vi kan forhandle på dine vegne og ofte skaffe bedre pris, vilkår eller overtagelsesdato.") 3853 </div> 3854 </div> 3855 <a class="btn btn-blue align-self-center align-self-md-start" href="/Default.aspx?ID=@rmBuyingAdvicePageId"> 3856 @Translate("Custom.Propertypage.BuyerAdviceSection.ButtonLabel", "Sådan hjælper køberrådgivning dig") 3857 <img height="20px" width="20px" src="@(iconPath + "icon-arrow-right.svg")" /> 3858 </a> 3859 </div> 3860 </div> 3861 </section> 3862 } 3863 <div id="sticky-sales-assessment-button" class="sales-assessment-mobile d-block d-md-none"> 3864 <a class="btn btn-blue" href="javascript:panelSalgsvurdering('@origin');">@Translate("Custom.Propertypage.SalesAssessment.ButtonLabel", "Bestil salgsvurdering")</a> 3865 </div> 3866 </div> 3867 <!--PANELS--> 3868 @{ 3869 var settingsPersondatapolitik = settingsItem != null ? settingsItem["Persondatapolitik"] : ""; 3870 var termsMail = Dynamicweb.Frontend.PageView.Current().AreaSettings.GetRawValueString("TermsEmail", ""); 3871 var userId = Dynamicweb.Security.UserManagement.UserContext.Current.UserId; 3872 var user = Dynamicweb.Security.UserManagement.UserContext.Current.User; 3873 string brokerName = !string.IsNullOrEmpty(propBroker?.Broker?.CompanyName) ? propBroker.Broker.CompanyName : propBroker?.Broker?.Name; 3874 string butikId = brokerItem?["CBMedlemsnummer"] != null ? Converter.ToString(brokerItem["CBMedlemsnummer"]) : string.Empty; 3875 3876 } 3877 3878 <div id="panel-book-showing" class="panel panel-form" role="dialog" aria-modal="true" aria-labelledby="book-showing-title"> 3879 <button type="button" class="close" data-dismiss="panel-form" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.CloseForm", "Luk formular"))"> 3880 <b></b> 3881 </button> 3882 <h2 id="book-showing-title" class="js-showing-header">@Translate("form-fremvisning-titel", "Bestil fremvisning")</h2> 3883 <p>@Translate("form-fremvisning-beskrivelse", "")</p> 3884 <form id="book-showing" method="POST" action="/InboxHandler"> 3885 <div class="form-group"> 3886 <label><strong>@Translate("form-navn", "Navn")*</strong></label> 3887 <input class="form-control" type="text" name="navn" placeholder="@HtmlEncoder.HtmlAttributeEncode(Translate("Smartpage:Placeholder.Navn", "Indtast dit navn"))" value="@HtmlEncoder.HtmlAttributeEncode(user?.UserName)" required="required" aria-required="true" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.NameField", "Navn"))" /> 3888 </div> 3889 <div class="form-group"> 3890 <label><strong>@Translate("form-email", "E-mail")*</strong></label> 3891 <input class="form-control" type="email" pattern="[_a-z0-9.%+-]+&#64;[a-z0-9.-]+.[a-z]{2,4}$" name="email" placeholder="@HtmlEncoder.HtmlAttributeEncode(Translate("Smartpage:Placeholder.Email", "Indtast din e-mail"))" value="@HtmlEncoder.HtmlAttributeEncode(user?.Email)" required="required" aria-required="true" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.EmailField", "E-mail adresse"))" /> 3892 </div> 3893 <div class="form-group row"> 3894 <div class="col-6"> 3895 <label><strong>@Translate("form-mobile", "Mobil nr.")*</strong></label> 3896 <input class="form-control" type="tel" pattern="^[0-9]*$" maxlength="20" name="mobile" placeholder="@HtmlEncoder.HtmlAttributeEncode(Translate("Smartpage:Salgsopstilling.Placeholder.Mobile", "Indtast mobil nr."))" value="@HtmlEncoder.HtmlAttributeEncode(user?.Phone)" required="required" aria-required="true" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.MobileField", "Mobilnummer"))" /> 3897 </div> 3898 <div class="col-6"> 3899 <label><strong>@Translate("form-telephone", "Telefon nr.")</strong></label> 3900 <input class="form-control" type="tel" pattern="^[0-9]*$" maxlength="20" name="telefonnummer" placeholder="@HtmlEncoder.HtmlAttributeEncode(Translate("Smartpage:Salgsopstilling.Placeholder.Telefon", "Indtast tlf nr."))" value="@HtmlEncoder.HtmlAttributeEncode(user?.Phone)" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.PhoneField", "Telefonnummer"))" /> 3901 </div> 3902 </div> 3903 3904 <div class="form-group"> 3905 <label><strong>@Translate("form-tidspunkt", "Tidspunkt")*</strong></label> 3906 <input class="form-control" type="text" name="tidspunkt" placeholder="@HtmlEncoder.HtmlAttributeEncode(Translate("form-tidspunkt", "Tidspunkt"))" required="required" aria-required="true" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.TimeField", "Tidspunkt for fremvisning"))" /> 3907 </div> 3908 <button class="form-control text-left js-collapse-focus" type="button" data-toggle="collapse" data-target="#bookshowing-collapse" aria-expanded="false" aria-controls="bookshowing-collapse" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.AddComment", "Tilføj kommentar"))"> 3909 <strong class="f-12"><i class="fas fa-plus"></i> @Translate("Smartpage:.Skrivenkommentar", "Skriv en kommentar")</strong> 3910 </button> 3911 <div class="collapse" id="bookshowing-collapse"> 3912 <div class="form-group"> 3913 <textarea class="form-control" name="besked" placeholder="@HtmlEncoder.HtmlAttributeEncode(Translate("form-besked", "Besked"))" maxlength="150" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.MessageField", "Besked til mægler"))"></textarea> 3914 </div> 3915 </div> 3916 3917 <div class="form-group"> 3918 <div class="row"> 3919 <div class="col-12"> 3920 <button type="submit" class="btn btn-green btn-block js-showing-btn">@Translate("form-fremvisning-submitbtn", "Bestil fremvisning")</button> 3921 </div> 3922 </div> 3923 </div> 3924 <div class="form-group form-group-terms"> 3925 @string.Format(Translate("Custom.Propertypage.PanelBookShowing.Terms", "Ved at indsende formularen, giver du dit samtykke til, at dine data samles og behandles af RealMæglerne A/S for at kunne kontakte dig.\r\n Du kan til enhver tid tilbagekalde dit samtykke. For at gøre dette skal du blot sende en meddelelse til <a href=\"mailto:{0}\">{0}</a>.\r\n Læs mere på <a href=\"{1}\">privatlivspolitikkerne</a>."), termsMail, settingsPersondatapolitik) 3926 </div> 3927 <input type="hidden" name="kontaktmigok" value="true" /> 3928 <input type="hidden" name="fn" value="bf" /> 3929 <input type="hidden" name="origin" value="" /> 3930 <input type="hidden" name="brugerId" value="@userId" /> 3931 <input type="hidden" name="sagsnr" value="@productId" /> 3932 <input type="hidden" name="productid" value="@productId" /> 3933 <input type="hidden" name="eadresse" value="@HtmlEncoder.HtmlAttributeEncode(GetString("Ecom:Product:Field.xEjendomAdresseAdresseLinie"))" /> 3934 <input type="hidden" name="epostnrby" value="@HtmlEncoder.HtmlAttributeEncode(GetString("Ecom:Product:Field.xEjendomAdressePostAdresseLinie"))" /> 3935 <input type="hidden" name="areaid" value="@Pageview.AreaID" /> 3936 <input type="hidden" name="bnavn" value="@HtmlEncoder.HtmlAttributeEncode(brokerName)" /> 3937 <input type="hidden" name="greenmobility" value="@Converter.ToString(isValidForGreenMobility)" /> 3938 <input class="js-online-showing" type="hidden" name="onlineShowing" value="" /> 3939 <input type="hidden" name="butikId" value="@HtmlEncoder.HtmlAttributeEncode(butikId)" /> 3940 @if (employeeItem != null) 3941 { 3942 3943 <input type="hidden" name="mnavn" value="@HtmlEncoder.HtmlAttributeEncode(propBroker.Employee.Name)" /> 3944 if (!string.IsNullOrEmpty(propBroker.Employee.PhoneMobile) && Converter.ToBoolean(employeeItem["VisMobilNrPaaSager"])) 3945 { 3946 <input type="hidden" name="mtelefonnummer" value="@HtmlEncoder.HtmlAttributeEncode(propBroker.Employee.PhoneMobile)" /> 3947 } 3948 else 3949 { 3950 3951 <input type="hidden" name="mtelefonnummer" value="@HtmlEncoder.HtmlAttributeEncode(propBroker.Broker.Telephone)" /> 3952 } 3953 3954 <input type="hidden" name="memail" value="@RealMaeglerne.Library.Helper.ExtractMaskedEmail(propBroker.Employee.Email)" /> 3955 3956 } 3957 </form> 3958 <div id="book-showing-thanks" style="display:none;" role="status" aria-live="polite" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.ThankYouMessage", "Tak besked"))"> 3959 <p>@Translate("form-fremvisning-tak", "Tak for din bestilling af fremvisning. Du vil hurtigst muligt blive kontaktet af din mægler, for at bekræfte jeres aftale. Tak for din interesse.")</p> 3960 </div> 3961 </div> 3962 3963 <div id="panel-sales-documents" class="panel panel-form" role="dialog" aria-modal="true" aria-labelledby="sales-documents-title"> 3964 <button type="button" class="close" data-dismiss="panel-form" aria-label="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Accessibility.CloseForm", "Luk formular"))"> 3965 <b></b> 3966 </button> 3967 3968 <h2 id="sales-documents-title">@Translate("form-salgsopstilling-titel", "Bestil Salgsopstilling")</h2> 3969 3970 <p>@Translate("form-salgsopstilling-beskrivelse", "")</p> 3971 <form id="order-sales-documents" method="POST" action="/InboxHandler"> 3972 <div class="form-group"> 3973 <label><strong>@Translate("form-navn", "Navn")*</strong></label> 3974 <input class="form-control" type="text" name="navn" placeholder="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Salgsopstilling.Placeholder.Navn", "Indtast dit navn"))" value="@HtmlEncoder.HtmlAttributeEncode(user?.UserName)" required=required /> 3975 </div> 3976 <div class="form-group"> 3977 <label><strong>@Translate("form-email", "E-mail")*</strong></label> 3978 <input class="form-control" type="email" pattern="[_a-z0-9.%+-]+&#64;[a-z0-9.-]+.[a-z]{2,4}$" name="email" placeholder="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:.Salgsopstilling.Placeholder.Email", "Indtast din e-mail"))" value="@HtmlEncoder.HtmlAttributeEncode(user?.Email)" required=required /> 3979 </div> 3980 <div class="form-group row"> 3981 <div class="col-6"> 3982 <label><strong>@Translate("form-mobile", "Mobil nr.")*</strong></label> 3983 <input class="form-control" type="tel" pattern="^[0-9]*$" maxlength="20" name="mobile" placeholder="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Salgsopstilling.Placeholder.Mobile", "Indtast mobil nr."))" value="@HtmlEncoder.HtmlAttributeEncode(user?.Phone)" required=required /> 3984 </div> 3985 <div class="col-6"> 3986 <label><strong>@Translate("form-telephone", "Telefon nr.")</strong></label> 3987 <input class="form-control" type="tel" pattern="^[0-9]*$" maxlength="20" name="telefonnummer" placeholder="@HtmlEncoder.HtmlAttributeEncode(Translate("Custom:Salgsopstilling.Placeholder.Telefon", "Indtast tlf nr."))" value="@HtmlEncoder.HtmlAttributeEncode(user?.Phone)" /> 3988 </div> 3989 </div> 3990 <div class="form-group"> 3991 <div class="checkbox"> 3992 <label> 3993 <input type="checkbox" name="kontaktmigok" /> 3994 <span>@Translate("form-contactpermission-real", "Ja tak, RealMæglerne må gerne kontakte mig. *")</span> 3995 </label> 3996 </div> 3997 </div> 3998 <div class="form-group"> 3999 <div class="row"> 4000 <div class="col-12"> 4001 <button type="submit" class="btn btn-green btn-block">@Translate("form-salgsopstilling-submitbtn", "Bestil salgsopstilling")</button> 4002 </div> 4003 </div> 4004 </div> 4005 4006 4007 <div class="form-group form-group-terms"> 4008 @string.Format(Translate("Custom.Propertypage.PanelBookShowing.Terms", "Ved at indsende formularen, giver du dit samtykke til, at dine data samles og behandles af RealMæglerne A/S for at kunne kontakte dig.\r\n Du kan til enhver tid tilbagekalde dit samtykke. For at gøre dette skal du blot sende en meddelelse til <a href=\"mailto:{0}\">{0}</a>.\r\n Læs mere på <a href=\"{1}\">privatlivspolitikkerne</a>."), termsMail, settingsPersondatapolitik) 4009 </div> 4010 <input type="hidden" name="fn" value="bs" /> 4011 <input type="hidden" name="origin" value="" /> 4012 <input type="hidden" name="sagsnr" value="@productId" /> 4013 <input type="hidden" name="brugerId" value="@userId" /> 4014 <input type="hidden" name="areaid" value="@Pageview.AreaID" /> 4015 <input type="hidden" name="butikId" value="@HtmlEncoder.HtmlAttributeEncode(butikId)" /> 4016 <input type="hidden" name="productId" value="@productId" /> 4017 </form> 4018 <div id="download-sales-documents" style="display:none;"> 4019 <p>@Translate("form-salgsopstilling-downloadbeskrivelse", "Tak for din interesse")</p> 4020 <br /> 4021 @foreach (var item in edhFiles) 4022 { 4023 if (item.Value?.ToLower().Contains("salgsopstilling") == true) 4024 { 4025 <a href="@item.Key" class="btn btn-primary link" target="_blank" rel="nofollow noopener">@Translate("form-salgsopstilling-download", "Hent") @item.Value</a> 4026 <br /><br /> 4027 } 4028 } 4029 </div> 4030 </div> 4031 4032 <div id="panel-makeanoffer" class="panel panel-form"> 4033 <button type="button" class="close" data-dismiss="panel-form" aria-label="@HtmlEncoder.HtmlAttributeEncode(@Translate("Custom:Accessiblity.OfferPanel.Close","Luk"))"> 4034 <b></b> 4035 </button> 4036 4037 <h2>@Translate("Smartpage:MakeAnOffer.Title", "Skriv din pris")</h2> 4038 4039 <form id="make-an-offer" method="POST" action="/InboxHandler"> 4040 <p>@Translate("Smartpage:MakeAnOffer.Subtitle", "Giv et uforpligtende bud. Dit bud er ikke bindende for dig, ligesom sælger ikke er forpligtet til at acceptere dit bud.")</p> 4041 <div class="form-group"> 4042 <label><strong>@Translate("Smartpage:MakeAnOffer.Price", "Prisforslag")*</strong></label> 4043 @*checkmark*@ 4044 <input class="form-control js-input-offer" id="form-offer" type="text" name="price" placeholder="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(Translate("Smartpage:MakeAnOffer.Price", "Prisforslag") )" /> 4045 </div> 4046 <div class="form-group"> 4047 <label><strong>@Translate("form-navn", "Navn")*</strong></label> 4048 <input class="form-control" type="text" name="navn" placeholder="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(Translate("form-navn", "Navn") )" value="@HtmlEncoder.HtmlAttributeEncode(user?.UserName)" /> 4049 </div> 4050 <div class="form-group"> 4051 <label><strong>@Translate("form-email", "E-mail")*</strong></label> 4052 <input class="form-control" type="email" pattern="[_a-z0-9.%+-]+&#64;[a-z0-9.-]+.[a-z]{2,4}$" name="email" placeholder="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(Translate("form-email", "E-mail") )" value="@HtmlEncoder.HtmlAttributeEncode(user?.Email)" /> 4053 </div> 4054 <div class="form-group"> 4055 <label><strong>@Translate("form-telephone", "Telefon nr.")*</strong></label> 4056 <input class="form-control" type="tel" pattern="^[0-9]*$" maxlength="20" name="telefonnummer" placeholder="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(Translate("Smartpage:Salgsopstilling.Placeholder.Telefon", "Indtast tlf nr.") )" value="@HtmlEncoder.HtmlAttributeEncode(user?.Phone)" /> 4057 </div> 4058 <div class="form-group"> 4059 <div class="checkbox"> 4060 <label> 4061 <input type="checkbox" name="kontaktmigok" /> 4062 <span>@Translate("form-contactpermission-real", "Ja tak, RealMæglerne må gerne kontakte mig. *")</span> 4063 </label> 4064 </div> 4065 </div> 4066 <div class="form-group"> 4067 <div class="row"> 4068 <div class="col-12"> 4069 <button type="submit" class="btn btn-green btn-block">@Translate("Smartpage:MakeAnOffer.Button.Text", "Send mit bud")</button> 4070 </div> 4071 </div> 4072 </div> 4073 4074 4075 <div class="form-group form-group-terms"> 4076 @Translate("Smartpage:MakeAnOffer.TermsAndConditions", "* Der samles ingen personlige oplysninger uden dit udtrykkelige samtykke. Ved at klikke på denne checkboks giver du dit samtykke til, at dine data samles og behandles af RealMæglerne A/S for at kunne kontakte dig. Du kan til enhver tid tilbagekalde dit samtykke. For at gøre dette skal du blot sende en meddelelse til ") 4077 <a href="mailto:@termsMail">@termsMail</a>. 4078 @Translate("Smartpage:MakeAnOffer.TermsAndConditions.ReadMoreOn", "Læs mere på") <a href="@settingsPersondatapolitik">@Translate("Smartpage:MakeAnOffer.TermsAndConditions.PrivacyPolicy", "privatlivspolitikkerne")</a>. 4079 </div> 4080 <input type="hidden" name="fn" value="skp" /> 4081 <input type="hidden" name="origin" value="" /> 4082 <input type="hidden" name="sagsnr" value="@productId" /> 4083 <input type="hidden" name="brugerId" value="@userId" /> 4084 <input type="hidden" name="areaid" value="@Pageview.AreaID" /> 4085 <input type="hidden" name="butikId" value="@HtmlEncoder.HtmlAttributeEncode(butikId)" /> 4086 </form> 4087 <div class="js-thank-you-message" style="display:none;"> 4088 <p>@Translate("Smartpage:MakeAnOffer.ThankYouMessage", "Tak for dit bud. Du vil hurtigst muligt blive kontaktet af mægler. Tak for din interesse.")</p> 4089 </div> 4090 </div> 4091 4092 @{ 4093 string teaserDesc = System.Text.RegularExpressions.Regex.Replace(GetString("Ecom:Product.LongDescription"), "<[^>]*>", String.Empty); 4094 if (teaserDesc.Length > 300) 4095 { 4096 teaserDesc = teaserDesc.Substring(0, 300) + "..."; 4097 } 4098 string priceWithDecimal = GetInteger("Ecom:Product.DBPrice") + ".0"; 4099 } 4100 @SnippetStart("OpenGraphTags") 4101 4102 <meta property="og:type" content="website" /> 4103 <meta property="og:url" content="@Context.Current.Request.Url.AbsoluteUri" /> 4104 <meta property="og:image" content="@HtmlEncoder.HtmlAttributeEncode(primaryImage?.ImageXl)" /> 4105 <meta property="og:title" content="@HtmlEncoder.HtmlAttributeEncode(GetString("Ecom:Product:Field.xEjendomAdresseAdresseLinie")), @HtmlEncoder.HtmlAttributeEncode(GetString("Ecom:Product:Field.xEjendomAdressePostAdresseLinie"))" /> 4106 <meta property="og:description" content="@HtmlEncoder.HtmlAttributeEncode(teaserDesc)" /> 4107 4108 @{ 4109 if (!bolig.Solgt && !bolig.PurchaseAgreementSigned) 4110 { 4111 <meta property="og:price:amount" content="@priceWithDecimal" /> 4112 <meta property="og:price:currency" content="DKK" /> 4113 } 4114 } 4115 4116 @*TWITTER CARD*@ 4117 <!-- Twitter Card data --> 4118 <meta name="twitter:card" content="product" /> 4119 <meta name="twitter:site" content="@Context.Current.Request.Url.AbsoluteUri" /> 4120 <meta name="twitter:title" content="@HtmlEncoder.HtmlAttributeEncode(GetString("Ecom:Product:Field.xEjendomAdresseAdresseLinie")), @HtmlEncoder.HtmlAttributeEncode(GetString("Ecom:Product:Field.xEjendomAdressePostAdresseLinie"))" /> 4121 <meta name="twitter:description" content="@HtmlEncoder.HtmlAttributeEncode(teaserDesc)" /> 4122 <!-- Twitter summary card with large image must be at least 280x150px --> 4123 <meta name="twitter:image:src" content="@HtmlEncoder.HtmlAttributeEncode(primaryImage?.ImageLg)" /> 4124 @*TWITTER CARD END*@ 4125 4126 @SnippetEnd("OpenGraphTags") 4127 4128 @SnippetStart("StructuredData") 4129 <script type="application/ld+json"> 4130 { 4131 "@@context": "http://schema.org", 4132 "@@type": "Residence", 4133 "address": { 4134 "@@type": "PostalAddress", 4135 "addressCountry": "Denmark", 4136 "postalCode": "@GetString("Ecom:Product:Field.xEjendomAdressePostnummer")", 4137 "streetAddress": "@GetString("Ecom:Product:Field.xEjendomAdresseAdresseLinie")" 4138 } 4139 } 4140 </script> 4141 @SnippetEnd("StructuredData") 4142 4143 4144 @SnippetStart("GtmDatalayer") 4145 4146 @{ 4147 var settings_Google_Tag_Manager_ID = !string.IsNullOrEmpty(Converter.ToString(settingsItem["Google_Tag_Manager_ID"])) ? settingsItem["Google_Tag_Manager_ID"] : ""; 4148 } 4149 4150 <!-- GTM --> 4151 @if (!string.IsNullOrEmpty(Converter.ToString(settings_Google_Tag_Manager_ID))) 4152 { 4153 var gtmPropertyType = ""; 4154 4155 if (isRental) 4156 { 4157 gtmPropertyType = Translate("Smartpage:Boligsiden.Information.Type.Lejebolig", "Lejebolig"); 4158 } 4159 else 4160 { 4161 gtmPropertyType = propTypeDisplay; 4162 } 4163 4164 <script> 4165 // on load 4166 window.dataLayer.push({ 4167 'propertyID': '@product', 4168 'propertyType': '@gtmPropertyType', 4169 }); 4170 </script> 4171 4172 if (propBroker != null) 4173 { 4174 <script> 4175 // on load 4176 // MH: needs to be rewritten if it should support multiple brokers 4177 window.dataLayer.push({ 4178 'realEstateAgentId': '@butikId', 4179 }); 4180 </script> 4181 } 4182 } 4183 <!-- GTM end --> 4184 @SnippetEnd("GtmDatalayer") 4185 @SnippetStart("JavaScriptBottom") 4186 @{ 4187 var boligsideFileInfo = new System.IO.FileInfo(Dynamicweb.Core.SystemInformation.MapPath("/Files/Templates/Designs/rm/assets/dist/bundle.boligside.min.js")); 4188 } 4189 <script type="text/javascript" src="/Files/Templates/Designs/rm/assets/dist/bundle.boligside.min.js?@(boligsideFileInfo.LastWriteTime.Ticks)"></script> 4190 <script> 4191 4192 4193 document.addEventListener("DOMContentLoaded", () => { 4194 checkIfStuck("[propertypage-anchor]"); 4195 initHiddenStickyElements("sticky-sales-assessment-button", "address-section"); 4196 initImageNavigation('.blueprints', { imageSelector: '.blueprints-wrapper img', buttonIdPostFix: '-blueprints', threshold: 1, scrollDirection: 'horizontal', overflowWrapperSelector: '.js-blueprints-wrapper' }); 4197 initImageNavigation('.usps', { imageSelector: '.usp-item', buttonIdPostFix: '-usps', threshold: 1, scrollDirection: 'horizontal' }); 4198 syncSelectors('openhouse-selector-desktop', 'openhouse-selector-mobile'); 4199 initSliderObserver('property-slider'); 4200 initMetricsSlider('.js-popular-metrics-wrapper', '.popular-metric'); 4201 initThumbnailKeyboardNav(); 4202 }) 4203 4204 function initSliderObserver(sliderElementId) { 4205 4206 const sliderElement = document.getElementById(sliderElementId); 4207 4208 const observer = new IntersectionObserver((entries) => { 4209 entries.forEach(entry => { 4210 if (entry.isIntersecting) { 4211 addSlider(entry); 4212 observer.unobserve(entry.target); 4213 } 4214 }); 4215 }, { 4216 root: null, 4217 threshold: 0.1 4218 }); 4219 4220 // Observe elements 4221 observer.observe(sliderElement); 4222 } 4223 4224 async function addSlider(entry) { 4225 const sliderFeedId = entry.target.dataset.sliderFeed; 4226 4227 if (sliderFeedId != null) { 4228 const params = new URLSearchParams({ ID: sliderFeedId }); 4229 4230 const zipCode = entry.target.dataset.zipCode; 4231 if (zipCode) { 4232 params.set('zipcodefrom', zipCode); 4233 params.set('zipcodeto', zipCode); 4234 } 4235 4236 const propertyCategory = entry.target.dataset.propertyCategory; 4237 if (propertyCategory) { 4238 params.set('propertycategory', propertyCategory); 4239 } 4240 4241 const productNumber = entry.target.dataset.productNumber; 4242 if (productNumber) { 4243 params.set('ExcludeProductNumber', productNumber); 4244 } 4245 4246 const url = `/Default.aspx?${params}`; 4247 4248 try { 4249 const result = await fetch(url); 4250 if (!result.ok) throw new Error('Network response was not ok'); 4251 const response = await result.text(); 4252 entry.target.innerHTML = response; 4253 window.observePropertyCards(); 4254 } catch (error) { 4255 console.error('Error loading slider:', error); 4256 entry.target.innerHTML = '<p>@Dynamicweb.Core.Encoders.HtmlEncoder.JavaScriptStringEncode(Translate("Custom.Propertypage.PropertySlider.ErrorMessage", "Failed to load content"))</p>'; 4257 } 4258 } 4259 4260 } 4261 4262 function initMetricsSlider(wrapperElement, children) { 4263 document.querySelectorAll(wrapperElement).forEach(wrapper => { 4264 const metrics = wrapper.querySelectorAll(children); 4265 4266 // Skip if only one metric 4267 if (metrics.length <= 1) return; 4268 4269 // Measure widths 4270 const widths = []; 4271 metrics.forEach(metric => { 4272 widths.push(metric.offsetWidth); 4273 }); 4274 4275 // Setup wrapper 4276 wrapper.style.width = widths[0] + 'px'; 4277 wrapper.style.transition = 'width 1s ease-in-out'; 4278 4279 // Setup metrics 4280 metrics.forEach((metric, index) => { 4281 metric.style.position = 'absolute'; 4282 metric.style.top = '0'; 4283 metric.style.left = '0'; 4284 metric.style.transition = 'opacity 1s ease-in-out'; 4285 metric.style.opacity = index === 0 ? '1' : '0'; 4286 }); 4287 4288 // Animation loop 4289 let current = 0; 4290 setInterval(() => { 4291 const next = (current + 1) % metrics.length; 4292 4293 // Fade out current, fade in next 4294 metrics[current].style.opacity = '0'; 4295 metrics[next].style.opacity = '1'; 4296 4297 // Change width 4298 wrapper.style.width = widths[next] + 'px'; 4299 4300 current = next; 4301 }, 4000); 4302 }); 4303 } 4304 4305 function syncSelectors(firstSelectorId, secondSelectorId) { 4306 const select1 = document.getElementById(firstSelectorId); 4307 const select2 = document.getElementById(secondSelectorId); 4308 4309 if (select1 && select2) { 4310 select1.addEventListener('change', function () { 4311 select2.value = this.value; 4312 }); 4313 4314 select2.addEventListener('change', function () { 4315 select1.value = this.value; 4316 }); 4317 } 4318 } 4319 4320 function stopPropagation(event) { 4321 event.stopPropagation(); 4322 } 4323 4324 function fullScreen(elementId, clickedButton) { 4325 const element = document.getElementById(elementId); 4326 4327 if (element) { 4328 const closeText = clickedButton.dataset.textClose; 4329 const openText = clickedButton.dataset.textOpen; 4330 4331 if (element.classList.contains('full-screen')) { 4332 const labelElement = clickedButton.querySelector('.js-button-label'); 4333 if (labelElement) { 4334 labelElement.innerText = openText; 4335 } 4336 element.classList.remove('full-screen'); 4337 } else { 4338 const labelElement = clickedButton.querySelector('.js-button-label'); 4339 if (labelElement) { 4340 labelElement.innerText = closeText; 4341 } 4342 element.classList.add('full-screen'); 4343 } 4344 } 4345 } 4346 4347 function checkIfStuck(stickyElementSelector) { 4348 const stickyElement = document.querySelector(stickyElementSelector); 4349 const stickyTop = parseInt(getComputedStyle(stickyElement).top) || 0; 4350 4351 const observer = new IntersectionObserver( 4352 ([entry]) => { 4353 const targetTop = entry.boundingClientRect.top; 4354 4355 if (targetTop <= stickyTop) { 4356 stickyElement.classList.add('is-stuck'); 4357 } else { 4358 stickyElement.classList.remove('is-stuck'); 4359 } 4360 }, 4361 { 4362 threshold: [1], 4363 rootMargin: `-${stickyTop + 1}px 0px 0px 0px` 4364 } 4365 ); 4366 4367 observer.observe(stickyElement); 4368 } 4369 4370 function initHiddenStickyElements(stickyElementId, triggerElementId) { 4371 const stickyElement = document.getElementById(stickyElementId); 4372 const sentinel = document.getElementById(triggerElementId); 4373 4374 if (stickyElement && sentinel) { 4375 const observer = new IntersectionObserver((entries) => { 4376 entries.forEach(entry => { 4377 if (entry.boundingClientRect.top <= 0) { 4378 stickyElement.classList.add('visible'); 4379 } else { 4380 stickyElement.classList.remove('visible'); 4381 } 4382 }); 4383 }, { 4384 threshold: 1, 4385 rootMargin: '0px' 4386 }); 4387 4388 observer.observe(sentinel); 4389 } 4390 else { 4391 console.debug("Elements not found in initHiddenStickyElements using stickyElementId: ", stickyElementId, " and triggerElementId: ", triggerElementId); 4392 } 4393 } 4394 4395 function shareProperty(event, clickedButton) { 4396 event.preventDefault(); 4397 4398 const shareData = { 4399 title: document.title, 4400 text: clickedButton.dataset.shareText, 4401 url: window.location.href 4402 }; 4403 4404 if (navigator.share && navigator.canShare && navigator.canShare(shareData)) { 4405 navigator.share(shareData); 4406 } else { 4407 navigator.clipboard.writeText(window.location.href).then(() => { 4408 const alertText = clickedButton.dataset.alertText || 'Link copied to clipboard!'; 4409 alert(alertText); 4410 }); 4411 } 4412 } 4413 4414 function scrollToElementById(id, block = "start") { 4415 var element = document.getElementById(id); 4416 if (element) { 4417 element.scrollIntoView({ behavior: "smooth", block: block, container: "nearest" }); 4418 } 4419 } 4420 4421 function scrollGalleryToImage(imageId) { 4422 const image = document.getElementById(imageId); 4423 if (!image) return; 4424 4425 const gallery = image.closest('.image-gallery'); 4426 if (!gallery) return; 4427 4428 // Get position relative to gallery 4429 const imageRect = image.getBoundingClientRect(); 4430 const galleryRect = gallery.getBoundingClientRect(); 4431 const scrollOffset = imageRect.top - galleryRect.top + gallery.scrollTop; 4432 4433 gallery.scrollTo({ 4434 top: scrollOffset, 4435 behavior: "smooth" 4436 }); 4437 } 4438 4439 function initImageNavigation(parentSelector, options = {}) { 4440 // Default configuration 4441 const config = { 4442 imageSelector: 'img', 4443 nextButtonId: 'image-next', 4444 prevButtonId: 'image-prev', 4445 buttonIdPostFix: '', 4446 storageKey: 'currentImageIndex_' + parentSelector, 4447 threshold: 0.8, 4448 scrollBehavior: 'smooth', 4449 scrollDirection: 'vertical', // 'vertical' or 'horizontal' 4450 overflowWrapperSelector: '', 4451 ...options 4452 }; 4453 4454 // Get parent element 4455 const parent = document.querySelector(parentSelector); 4456 4457 if (!parent) { 4458 console.warn(`Parent element "${parentSelector}" not found`); 4459 return null; 4460 } 4461 4462 // Get images within parent 4463 const images = parent.querySelectorAll(config.imageSelector); 4464 if (images.length === 0) { 4465 console.warn(`No images found in "${parentSelector}"`); 4466 return null; 4467 } 4468 4469 let currentVisibleIndex = 0; 4470 let lastDirection = null; // Track navigation direction: 'forward' or 'backward' 4471 let visibleIndices = new Set(); // Persistent set of all visible image indices 4472 4473 // Set up Intersection Observer 4474 const observer = new IntersectionObserver((entries) => { 4475 // Update the set based on what changed 4476 entries.forEach(entry => { 4477 const index = Array.from(images).indexOf(entry.target); 4478 4479 if (entry.isIntersecting) { 4480 visibleIndices.add(index); 4481 } else { 4482 visibleIndices.delete(index); 4483 } 4484 }); 4485 4486 if (visibleIndices.size > 0) { 4487 const visibleArray = Array.from(visibleIndices); 4488 4489 // Check for boundary cases first 4490 if (visibleIndices.has(images.length - 1)) { 4491 // Last image is visible - set to MIN (prepare for backward movement) 4492 currentVisibleIndex = Math.min(...visibleArray); 4493 lastDirection = 'backward'; 4494 } else if (visibleIndices.has(0)) { 4495 // First image is visible - set to MAX (prepare for forward movement) 4496 currentVisibleIndex = Math.max(...visibleArray); 4497 lastDirection = 'forward'; 4498 } else { 4499 // Middle of the list - use direction logic 4500 if (lastDirection === 'forward') { 4501 currentVisibleIndex = Math.max(...visibleArray); 4502 } else if (lastDirection === 'backward') { 4503 currentVisibleIndex = Math.min(...visibleArray); 4504 } else { 4505 // Default to min when no direction set (initial load) 4506 currentVisibleIndex = Math.min(...visibleArray); 4507 } 4508 } 4509 4510 if (config.storageKey) { 4511 localStorage.setItem(config.storageKey, currentVisibleIndex); 4512 } 4513 4514 updateButtonStates(); 4515 } 4516 }, { 4517 root: null, 4518 threshold: config.threshold 4519 }); 4520 4521 // Observe all images 4522 images.forEach(img => observer.observe(img)); 4523 4524 function updateButtonStates() { 4525 const wrapper = document.querySelector(config.overflowWrapperSelector); 4526 const hasOverflow = wrapper ? wrapper.scrollWidth > wrapper.clientWidth : true; 4527 4528 const nextButton = parent.querySelector('#' + config.nextButtonId + config.buttonIdPostFix); 4529 const prevButton = parent.querySelector('#' + config.prevButtonId + config.buttonIdPostFix); 4530 if (nextButton) { 4531 // Disable if last image is visible 4532 if (visibleIndices.has(images.length - 1) || !hasOverflow) { 4533 nextButton.classList.add('disabled'); 4534 } else { 4535 nextButton.classList.remove('disabled'); 4536 } 4537 } 4538 4539 if (prevButton) { 4540 // Disable if first image is visible 4541 if (visibleIndices.has(0) || !hasOverflow) { 4542 prevButton.classList.add('disabled'); 4543 } else { 4544 prevButton.classList.remove('disabled'); 4545 } 4546 } 4547 } 4548 4549 // Helper function to scroll to specific image 4550 function scrollToImage(index, direction) { 4551 if (index >= 0 && index < images.length) { 4552 lastDirection = direction; 4553 4554 const scrollOptions = { 4555 behavior: config.scrollBehavior 4556 }; 4557 4558 // Set scroll alignment based on direction 4559 if (config.scrollDirection === 'horizontal') { 4560 scrollOptions.inline = 'start'; 4561 scrollOptions.block = 'nearest'; 4562 } else { 4563 scrollOptions.block = 'start'; 4564 scrollOptions.inline = 'nearest'; 4565 } 4566 4567 images[index].scrollIntoView(scrollOptions); 4568 currentVisibleIndex = index; 4569 4570 if (config.storageKey) { 4571 localStorage.setItem(config.storageKey, index); 4572 } 4573 4574 updateButtonStates(); 4575 } 4576 } 4577 4578 // Set up navigation buttons 4579 const nextButton = parent.querySelector('#' + config.nextButtonId + config.buttonIdPostFix); 4580 const prevButton = parent.querySelector('#' + config.prevButtonId + config.buttonIdPostFix); 4581 4582 const handleNext = () => { 4583 const nextIndex = Math.min(currentVisibleIndex + 1, images.length - 1); 4584 scrollToImage(nextIndex, 'forward'); 4585 }; 4586 4587 const handlePrev = () => { 4588 const prevIndex = Math.max(currentVisibleIndex - 1, 0); 4589 scrollToImage(prevIndex, 'backward'); 4590 }; 4591 4592 if (nextButton) { 4593 nextButton.addEventListener('click', handleNext); 4594 } else { 4595 console.warn(`Next button "${config.nextButtonId}" not found`); 4596 } 4597 4598 if (prevButton) { 4599 prevButton.addEventListener('click', handlePrev); 4600 } else { 4601 console.warn(`Prev button "${config.prevButtonId}" not found`); 4602 } 4603 4604 // Initialize button states 4605 updateButtonStates(); 4606 } 4607 4608 /** 4609 * Initialize keyboard navigation for image thumbnails 4610 * Allows navigation with ArrowUp/ArrowDown keys 4611 * Wraps around from last to first and vice versa 4612 * Uses checked radio state and data-index for navigation 4613 */ 4614 function initThumbnailKeyboardNav() { 4615 const container = document.querySelector('.js-image-thumbnails'); 4616 if (!container) return; 4617 4618 const thumbnails = container.querySelectorAll('.js-thumbnail-radio'); 4619 if (!thumbnails.length) return; 4620 4621 // Get current index from checked radio button 4622 function getCurrentIndex() { 4623 const checkedRadio = container.querySelector('input[type="radio"]:checked'); 4624 if (checkedRadio) { 4625 const label = checkedRadio.closest('.js-thumbnail-radio'); 4626 return parseInt(label.dataset.index, 10) || 0; 4627 } 4628 return 0; 4629 } 4630 4631 // Navigate to thumbnail by index 4632 function navigateToIndex(index) { 4633 const targetLabel = container.querySelector('.js-thumbnail-radio[data-index="' + index + '"]'); 4634 if (targetLabel) { 4635 targetLabel.click(); 4636 } 4637 } 4638 4639 // Listen for keyboard navigation on the container 4640 container.addEventListener('keydown', (e) => { 4641 const currentIndex = getCurrentIndex(); 4642 const totalThumbnails = thumbnails.length; 4643 let newIndex; 4644 4645 if (e.key === 'ArrowDown' || e.key === 'ArrowRight') { 4646 e.preventDefault(); 4647 // Wrap to first if at end 4648 newIndex = currentIndex >= totalThumbnails - 1 ? 0 : currentIndex + 1; 4649 navigateToIndex(newIndex); 4650 } else if (e.key === 'ArrowUp' || e.key === 'ArrowLeft') { 4651 e.preventDefault(); 4652 // Wrap to last if at beginning 4653 newIndex = currentIndex <= 0 ? totalThumbnails - 1 : currentIndex - 1; 4654 navigateToIndex(newIndex); 4655 } else if (e.key === 'Home') { 4656 e.preventDefault(); 4657 navigateToIndex(0); 4658 } else if (e.key === 'End') { 4659 e.preventDefault(); 4660 navigateToIndex(totalThumbnails - 1); 4661 } 4662 }); 4663 } 4664 4665 function handleError(img) { 4666 const fallback = img.dataset.fallback; 4667 if (fallback.length) { 4668 img.src = fallback; 4669 } 4670 } 4671 </script> 4672 @*Video Autoplay fallback*@ 4673 <script defer> 4674 const video = document.querySelector('.js-primary-video'); 4675 if (video) { 4676 video.play().then(() => { 4677 // Autoplay worked 4678 }).catch((error) => { 4679 // Autoplay was blocked 4680 // Show a play button 4681 showPlayButton(); 4682 }); 4683 } 4684 </script> 4685 4686 @*INPUT FIELDS FOR SPECIFIC JAVASCRIPT*@ 4687 @if (!bolig.Solgt && propBroker != null && brokerItem != null) 4688 { 4689 <input type="hidden" class="js-broker-radio-val" value="@Converter.ToString(brokerItem["CBMedlemsnummer"])" /> 4690 <input type="hidden" class="js-broker-image-val js-maegler-img-val" value="@HtmlEncoder.HtmlAttributeEncode(propBroker.Broker.GeolocationIcon.ToString())" /> 4691 <input type="hidden" class="js-choose-broker-address-val" value="@HtmlEncoder.HtmlAttributeEncode(propBroker.Broker.Address)" /> 4692 <input type="hidden" class="js-choose-broker-zip-val" value="@propBroker.Broker.ZipCode" /> 4693 <input type="hidden" class="js-choose-broker-name-val js-maegler-name-val" value="@HtmlEncoder.HtmlAttributeEncode(propBroker.Broker.CompanyName)" /> 4694 <input type="hidden" class="js-maegler-mail-val" value="@Converter.ToString(brokerItem["Email"])" /> 4695 <input type="hidden" class="js-maegler-phone-val" value="@propBroker.Broker.Telephone" /> 4696 <input type="hidden" class="js-updatebroker-list-val" value="@GetString("Ecom:Product:Field.xEjendomAdressePostnummer")" /> 4697 } 4698 4699 @if (settingsItem != null && !string.IsNullOrEmpty(settingsItem["Leadhub_Pixel_ID"].ToString())) 4700 { 4701 string offeringType = "sale"; 4702 if (GetString("Ecom:Product:Field.xUdbudsForm") == "Leje") 4703 { 4704 offeringType = "rent"; 4705 } 4706 <script> 4707 lhi('viewContent', { 4708 content_name: '@HtmlEncoder.JavaScriptStringEncode(GetString("Ecom:Product:Field.xEjendomAdresseAdresseLinie")), @HtmlEncoder.JavaScriptStringEncode(GetString("Ecom:Product:Field.xEjendomAdressePostAdresseLinie"))', 4709 content_ids: ['@productId'], 4710 content_type: 'product', 4711 value: @priceWithDecimal, 4712 currency: 'DKK' 4713 }); 4714 lhi('addTag', { 4715 type: 'ViewProperty', 4716 price: @priceWithDecimal, 4717 propertyType: '@propTypeDisplay', 4718 city: '@GetString("Ecom:Product:Field.xEjendomAdressePostDistrikt")', 4719 offeringType: '@offeringType', 4720 @if (hasMapCoordinates) 4721 { 4722 @:lat: @mapLat, 4723 @:lon: @mapLng, 4724 } 4725 squareMeters: @GetString("Ecom:Product:Field.xEjendomArealerBoligAreal") 4726 }); 4727 </script> 4728 } 4729 4730 @if (settingsItem != null && Convert.ToBoolean(settingsItem["UseOptinMonster"])) 4731 { 4732 <!-- This site is converting visitors into subscribers and customers with OptinMonster - https://optinmonster.com --> 4733 <script type="text/javascript" src="https://a.optmnstr.com/app/js/api.min.js" data-campaign="x2jkobozynuz9fbczh7c" data-user="42632" async=async></script><!-- / https://optinmonster.com --> 4734 } 4735 @SnippetEnd("JavaScriptBottom") 4736 4737 @{ 4738 var productName = StripHtml(GetString("Ecom:Product.Name")); 4739 var shortDescription = StripHtml(GetString("Ecom:Product.ShortDescription")); 4740 var areaName = StripHtml(GetString("Ecom:Product:Area.Name")); 4741 4742 Pageview.Meta.Title = string.IsNullOrEmpty(shortDescription) 4743 ? $"{productName} - {areaName}" 4744 : $"{productName} - {SetMaxLength(shortDescription, 75)} - {areaName}"; 4745 }
Fandt du ikke det du søgte? - Opret dig som bruger og få mere ud af din boligsøgning
Dit RealMæglerne

Log ind på RealMæglernes Boligagent

Med Mit RealMæglerne er det nemt at følge boligmarkedet. Leder du efter nyt, kan du gemme dine favorit boliger og målrette din søgning ned til mindste detalje. Skal du sælge, kan du løbende følge interessen for din bolig og meget mere.


Kontakt Mægler

Din bolig

* Der samles ingen personlige oplysninger uden dit udtrykkelige samtykke. Ved at klikke på denne checkboks giver du dit samtykke til, at dine data samles og behandles af RealMæglerne A/S for at kunne kontakte dig. Du kan til enhver tid tilbagekalde dit samtykke. For at gøre dette skal du blot sende en meddelelse til info@realmaeglerne.dk. Læs mere på privatlivspolitikkerne.

Tilmeld til åbent hus

Adresse:
Dato:
Tidspunkt:

Kontakt Mægler

* Der samles ingen personlige oplysninger uden dit udtrykkelige samtykke. Ved at klikke på denne checkboks giver du dit samtykke til, at dine data samles og behandles af RealMæglerne A/S for at kunne kontakte dig. Du kan til enhver tid tilbagekalde dit samtykke. For at gøre dette skal du blot sende en meddelelse til info@realmaeglerne.dk. Læs mere på privatlivspolitikkerne.

Bestil gratis salgsvurdering

Din bolig

Send salgsvurdering til:

Vælg mægler

* Der samles ingen personlige oplysninger uden dit udtrykkelige samtykke. Ved at klikke på denne checkboks giver du dit samtykke til, at dine data samles og behandles af RealMæglerne A/S for at kunne kontakte dig. Du kan til enhver tid tilbagekalde dit samtykke. For at gøre dette skal du blot sende en meddelelse til info@realmaeglerne.dk. Læs mere på privatlivspolitikkerne.

Bestil gratis salgsvurdering

Din bolig

Send salgsvurdering til:

Vælg mægler

* Der samles ingen personlige oplysninger uden dit udtrykkelige samtykke. Ved at klikke på denne checkboks giver du dit samtykke til, at dine data samles og behandles af RealMæglerne A/S for at kunne kontakte dig. Du kan til enhver tid tilbagekalde dit samtykke. For at gøre dette skal du blot sende en meddelelse til info@realmaeglerne.dk. Læs mere på privatlivspolitikkerne.