Error executing template "Designs/Hags2024/eCom/Productlist/h24-product-list.cshtml" System.ArgumentException: An item with the same key has already been added. at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource) at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add) at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value) at Dynamicweb.Rendering.Translation.Source.GetTranslationSource(String designName, String moduleName, String cultureName) at Dynamicweb.Rendering.Template.TranslateText(String text, String defaultValue, String cultureName) at Dynamicweb.Rendering.TemplateBase`1.Translate(String text, String defaultValue) at CompiledRazorTemplates.Dynamic.RazorEngine_0d0104835020459cb6a1336a55e471eb.Execute() in B:\Projects\Hags_Dw915\Files\Templates\Designs\Hags2024\eCom\Productlist\h24-product-list.cshtml:line 416 at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader) at RazorEngine.Templating.RazorEngineCore.RunTemplate(ICompiledTemplate template, TextWriter writer, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.DynamicWrapperService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer) at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter) at RazorEngine.Templating.RazorEngineServiceExtensions.RunCompile(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 System 3 @using System.Globalization; 4 @using System.Collections.Generic 5 @using System.Linq 6 @using HagsWeb.Library.Methods.AssetManager; 7 @using HagsWeb.Library.BusinessObjects.UsersLists; 8 @using HagsWeb.Library.State; 9 @using HagsWeb.Library.Utilities; 10 @using System.Text.RegularExpressions; 11 @using System.Text; 12 @using System.Web; 13 14 @* for this page we want the header to be positioned over the content *@ 15 @SnippetStart("headerClass")@("out-flow")@SnippetEnd("headerClass") 16 17 @using System.Web; 18 @using System.IO; 19 @using System.Linq; 20 @using System.Net; 21 @using System.Configuration; 22 23 @functions { 24 25 public string maxMindIpCheck(string ipToCheck) { 26 27 string apiKey = "1146064"; 28 string apiSecret = "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"; 29 30 string encodedKey = WebUtility.UrlEncode(apiKey); 31 string encodedSecret = WebUtility.UrlEncode(apiSecret); 32 33 string apiResponse = ""; 34 string authHeader = ""; 35 string requestBody = ""; 36 bool requestError = false; 37 38 string countryReturn = ""; 39 40 string apiUrl = "https://geoip.maxmind.com/geoip/v2.1/country/" + ipToCheck; 41 42 try 43 { 44 HttpWebRequest apiRequest = (HttpWebRequest)WebRequest.Create(apiUrl); 45 apiRequest.Method = "GET"; 46 apiRequest.Accept = "application/json"; 47 string credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{encodedKey}:{encodedSecret}")); 48 //string credentials = consumerKey + ":" + consumerSecret; 49 apiRequest.Headers["Authorization"] = "Basic " + credentials; 50 51 // Get the response 52 using (var response = (HttpWebResponse)apiRequest.GetResponse()) 53 { 54 using (var reader = new StreamReader(response.GetResponseStream())) 55 { 56 apiResponse = reader.ReadToEnd(); // Return the response as a string 57 } 58 } 59 } 60 61 catch (Exception ex) 62 { 63 // Handle any errors 64 apiResponse = "ERROR ** " + ex.Message; 65 requestError = true; 66 } 67 68 if ( !requestError ) { 69 70 // convert the woo json into an object 71 Newtonsoft.Json.Linq.JToken apiObject = Newtonsoft.Json.Linq.JToken.Parse(apiResponse); 72 73 var countryObj = apiObject["country"]; 74 countryReturn = countryObj["iso_code"]?.ToString(); 75 76 } 77 78 return countryReturn; 79 80 } 81 82 public string extremeIpLookup(string ipAddress) { 83 84 string ipLookupKey = ConfigurationManager.AppSettings["ExtremeIpLookupApiKey"].ToString(); 85 string ipLookupUrl = "http://extreme-ip-lookup.com/json/" + ipAddress + "?key=" + ipLookupKey; 86 string ipLookupError = ""; 87 string ipCountryCode = ""; 88 89 90 HttpWebRequest ipLookupRequest = (HttpWebRequest)WebRequest.Create(ipLookupUrl); 91 ipLookupRequest.Method = "GET"; // Set method to GET 92 ipLookupRequest.ContentType = "application/json"; 93 94 try 95 { 96 // Get the response from the API 97 using (HttpWebResponse ipLookupResponse = (HttpWebResponse)ipLookupRequest.GetResponse()) 98 { 99 // Check if the response is OK 100 if (ipLookupResponse.StatusCode == HttpStatusCode.OK) 101 { 102 // Read the response stream 103 using (StreamReader reader = new StreamReader(ipLookupResponse.GetResponseStream())) 104 { 105 // Parse the JSON response 106 string jsonResponse = reader.ReadToEnd(); 107 108 // Parse JSON using JObject (from Newtonsoft.Json.Linq) 109 Newtonsoft.Json.Linq.JObject jsonObject = Newtonsoft.Json.Linq.JObject.Parse(jsonResponse); 110 111 // Extract a specific value (assuming the JSON has a field named "desiredField") 112 ipCountryCode = (string)jsonObject["countryCode"]; 113 ipCountryCode = ipCountryCode.ToLower(); 114 } 115 } 116 } 117 } 118 119 catch (Exception ex) 120 { 121 // Handle any errors 122 //set default to au 123 ipCountryCode = ""; 124 ipLookupError = ex.Message; 125 } 126 127 return ipCountryCode; 128 129 } 130 131 } 132 133 134 135 @{ 136 Dynamicweb.Frontend.PageView thisPage = Dynamicweb.Frontend.PageView.Current() ?? Dynamicweb.Frontend.PageView.Current(); 137 138 string baseUrl = GetGlobalValue("Global:Request.Scheme") + "://" + GetGlobalValue("Global:Request.Host"); 139 string pageUrl = baseUrl + thisPage.SearchFriendlyUrl; 140 string ipAddress = HttpContext.Current.Request.ServerVariables["remote_addr"]; 141 142 143 string canonicalUrl = baseUrl + Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl("Default.aspx?ID=" + GetValue("Ecom:ProductList:Page.ID")); // works 144 string canonicalListUrl = "<link rel=\"canonical\" href=\"" + canonicalUrl + "\" />"; 145 string h1Text = string.Empty; 146 string titleText = string.Empty; 147 148 string[] queryStrCollection = System.Web.HttpContext.Current.Request.QueryString.AllKeys; 149 150 foreach (var key in queryStrCollection) 151 { 152 switch(key) 153 { 154 case "GroupID": 155 canonicalUrl = canonicalUrl + "?GroupID="; 156 break; 157 case "PageNum": 158 int value = HagsWeb.Library.Utilities.WebUtilities.CheckInteger(System.Web.HttpContext.Current.Request[key]); 159 if(value > 1) 160 { 161 //canonicalListUrl = "<link rel=\"canonical\" href=\" " + canonicalUrl + " Page " + value + "\"/>"; 162 canonicalListUrl = "<link rel=\"canonical\" href=\" " + canonicalUrl + "&PageNum=" + value + "\"/>"; 163 titleText = thisPage.Meta.Title + " | Page " + value; 164 h1Text = "Page " + value; 165 Pageview.Meta.Title = titleText; 166 } 167 168 break; 169 170 case "sortBy": 171 canonicalListUrl = "<link rel=\"canonical\" href=\"" + canonicalUrl + "\" />"; 172 break; 173 174 default: 175 // do nowt 176 break; 177 } 178 } 179 180 Pageview.Meta.AddTag("customCan", canonicalListUrl); 181 182 string currentCulture = GetGlobalValue("Global:Area.LongLang"); 183 string currentCountry = currentCulture.Substring(currentCulture.Length - 2); // GB, SE 184 string weglotHeader = System.Web.HttpContext.Current.Request.Headers["weglot-language"]; 185 186 //List<ProductCollectionItem> productCollectionItems = SessionManager.UsersMyProductCollection != null ? SessionManager.UsersMyProductCollection : new List<ProductCollectionItem>(); 187 var siteSection = HagsWeb.Library.Methods.Page.HagsPages.GetSiteSection(thisPage.AreaID, thisPage.ID); 188 189 string globalAreaId = GetGlobalValue("Global:Area.ID"); 190 string globalAreaLongLang = GetGlobalValue("Global:Area.LongLang"); 191 192 var pagelink = "/Default.aspx?ID=" + GetValue("Ecom:ProductList:Page.ID"); 193 string ipPriceAllowed = string.Empty; 194 string ipCountryCode = ""; 195 bool showPrice = false; 196 string productLink = string.Empty; 197 198 string weglotLangProduct = System.Web.HttpContext.Current.Request.Headers["weglot-language"]; 199 200 //price visible check 201 202 if ( weglotLangProduct == "se" ) // Sweden only at the moment 203 { 204 //ipPriceAllowed = HagsWeb.Library.Services.IPService.IPCheck.CountryPriceAllowed(currentCountry); // ZZZ,Hags_GB,Hags_SE and Hags_, Anon_GB, Anon_SE network range checker (Web.config) 205 206 //check if the show prices cookie is set 207 HttpCookie spCookieGet = System.Web.HttpContext.Current.Request.Cookies["hags-sp"]; 208 209 if ( spCookieGet != null ) 210 { 211 if ( spCookieGet.Value == "true" ) { 212 showPrice = true; 213 } 214 } 215 216 //get the IP country code - if the show price is still false after cookie check above 217 if ( !showPrice ) 218 { 219 //ipCountryCode = HagsWeb.Library.Services.IPService.IPCheck.CountryCode().ToLower(); 220 ipCountryCode = maxMindIpCheck(ipAddress); 221 222 // allow only se at the moment 223 if ( ipCountryCode == "se") 224 { 225 showPrice = true; 226 } 227 } 228 229 } 230 231 List<string> materialOptions = new List<string>(); 232 if (SessionManager.IsSessionValueSet("FilterOptions_" + thisPage.ID)) 233 { 234 materialOptions = SessionManager.GetSessionItem("FilterOptions_" + thisPage.ID) as List<string>; 235 } 236 else 237 { 238 foreach (LoopItem item in GetLoop("Products")) 239 { 240 string[] variantId = item.GetString("Ecom:Product.DefaultVariantComboID").Split('.'); 241 string[] variantName = item.GetString("Ecom:Product.DefaultVariantComboName").Split('-'); 242 243 244 if (variantId.Length > 0 && !variantId[0].Contains("A1DEFAULT") && variantName.Length > 0 && !variantName[0].Contains("Not Applicable")) 245 { 246 var material = string.Join(",", variantId[0], variantName[0]); 247 if (!materialOptions.Contains(material) && material != ",") 248 { 249 materialOptions.Add(material); 250 } 251 } 252 } 253 SessionManager.SetSession("FilterOptions_" + thisPage.ID, materialOptions); 254 } 255 var productCount = GetLoop("Products").Count; 256 257 // ProductListWithParagraph.cshtml Get the Paragraph Item Type content the eCom_Catalog module sits on. The Paragraph Template must be CleanModule.cshtml 258 // with an eCom_Catalog module applied and the module List Template must be this template. 259 Dynamicweb.Content.Paragraph paragraph = new Dynamicweb.Content.ParagraphService().GetParagraphsByPageId(thisPage.ID) 260 .FirstOrDefault(n => n.ItemType == "Dw_Paragraph" 261 && n.Template == "CleanModule.cshtml" 262 && n.ModuleSystemName == "eCom_Catalog" && n.ShowParagraph == true); 263 264 // Lookup the Paragraph Item Type for additional content 265 Dynamicweb.Content.Items.Item paragraphItem = new Dynamicweb.Content.Items.Item(); 266 if (paragraph != null) 267 { 268 paragraphItem = new Dynamicweb.Content.ItemService().GetItem(paragraph.ItemType, paragraph.ItemId); 269 } 270 } 271 272 <!--Templates/Hags2024/eCom/ProductList/h24-product-list.cshtml--> 273 274 @if (paragraph != null && paragraphItem != null) 275 { 276 string imageSrc = (string)paragraphItem["Image"]; 277 string imageAltTag = ""; 278 var imageMetadata = Dynamicweb.Content.Files.Metadata.EditorFactory.GetMetadataForFile(imageSrc); 279 imageAltTag = imageMetadata != null ? imageMetadata.GetValue("Image_Alt_Tag") : ""; 280 if (!string.IsNullOrEmpty(imageSrc)) 281 { 282 <section> 283 <div class="hero hero--vignette"> 284 <img class="hero__img" src="@imageSrc" alt="@imageAltTag" /> 285 286 @if ( paragraphItem["Image_Heading"] != "") 287 { 288 <div class="wrapper z-up-10"> 289 <div class="hero__content flow"> 290 <h2>@paragraphItem["Image_Heading"]</h2> 291 </div> 292 </div> 293 } 294 295 </div> 296 </section> 297 } 298 299 @helper renderPageBreadcrumb(string thisUrl, string currentCulture, string productName, string variantOptions) { 300 301 string[] segments = Array.Empty<string>(); 302 Uri uri = new Uri(thisUrl); 303 if (uri.IsWellFormedOriginalString()) 304 { 305 segments = uri.Segments; 306 } 307 308 @* set up this so we can use it's title case method *@ 309 TextInfo thisTextInfo = new CultureInfo(currentCulture,false).TextInfo; 310 311 string first = segments.FirstOrDefault(); 312 string last = segments.LastOrDefault(); 313 314 if (!string.IsNullOrEmpty(productName)) 315 { 316 string stripSpaces = Regex.Replace(productName, @"\s+", " "); // some product names may have 2 or 3 spaces in them 317 productName = stripSpaces.Replace(" ", "-").ToLower(); 318 } 319 320 string concat = string.Empty; 321 322 StringBuilder sb = new StringBuilder(); 323 sb.Append("<ul class=\"product-nav product-nav--arrows\" role=\"list\">"); 324 325 326 foreach (var item in segments.Select((value,i)=>new{i,value})) 327 { 328 var index = item.i; 329 if (true) 330 { 331 string linkText = item.value.Replace("/",""); 332 concat += item.value; 333 334 if (segments.Length <= 2) // A shorthand URL like www.hags.com/hags-dragonfly or www.hags.de/hags-dragonfly 335 { 336 sb.Append("<li>" + thisTextInfo.ToTitleCase(linkText.Replace("-", " ")) + "</li>"); 337 } 338 // Request from the Product List with no Product Name 339 else if (item.value.Equals(last, StringComparison.CurrentCultureIgnoreCase) && string.IsNullOrEmpty(productName)) 340 { 341 sb.Append("<li><a href='" + concat.TrimEnd('/') + "' class=''> " + thisTextInfo.ToTitleCase(linkText.Replace("-", " ")) + "</a></li>"); 342 break; 343 } 344 // will be either the master product or the variant 345 else if (item.value.Equals(last, StringComparison.CurrentCultureIgnoreCase) && !item.value.Equals(productName, StringComparison.CurrentCultureIgnoreCase)) 346 { 347 linkText = variantOptions.Trim().Replace("Not applicable", "").ToLower(); 348 349 350 sb.Append("<li><a href='" + concat.TrimEnd('/') + "' class=''> " + thisTextInfo.ToTitleCase(linkText.Replace("-", " ")) + "</a></li>"); 351 } 352 else if (index == 2) 353 { 354 sb.Append("<li><a href='" + concat.TrimEnd('/') + "' class=''>Home</a></li>"); 355 } else if ( index > 2 ) { 356 sb.Append("<li><a href='" + concat.TrimEnd('/') + "' class=''>" + thisTextInfo.ToTitleCase(linkText.Replace("-", " ")) + "</a></li>"); 357 } 358 } 359 } 360 361 sb.Append("</ul>"); 362 363 @(sb.ToString()) 364 } 365 366 <nav class="breadcrumb"> 367 <div class="wrapper"> 368 @renderPageBreadcrumb(pageUrl, GetGlobalValue("Global:Area.LongLang"), string.Empty, string.Empty) 369 </div> 370 </nav> 371 372 <section class="page-intro"> 373 <div class="wrapper"> 374 <div class="page-intro__copy flow"> 375 376 @if ( string.IsNullOrEmpty((string)paragraphItem["Display_Heading"]) ) { 377 <h1 class="ts-5">@paragraphItem["Header"] @h1Text</h1> 378 } else { 379 <h1 class="ts-5">@paragraphItem["Display_Heading"] @h1Text</h1> 380 } 381 382 @paragraphItem["Content"] 383 384 </div> 385 </div> 386 </section> 387 } 388 389 @RenderSnippet("nextLevelNav") 390 391 <section> 392 <div class="wrapper flow"> 393 394 @{ 395 string sortOrder = System.Web.HttpContext.Current.Request.QueryString["SortOrder"]; 396 string sortBy = System.Web.HttpContext.Current.Request.QueryString["sortBy"]; 397 string thisSortUrl = "&sortBy=" + sortBy + "&SortOrder=" + sortOrder; 398 399 string[,] sortOptions = new string[,] 400 { 401 {"&sortBy=ProductName&SortOrder=Asc","NameA-Z","Name A-Z" }, 402 {"&sortBy=ProductName&SortOrder=Desc","NameZ-A","Name Z-A"}, 403 {"&sortBy=AgeRange&SortOrder=Asc","AgeAscending","Age Ascending"}, 404 {"&sortBy=AgeRange&SortOrder=Desc","AgeDescending","Age Descending"}, 405 {"&sortBy=SafetyArea&SortOrder=Asc","SafetyAreaAscending","Safety Area Ascending"}, 406 {"&sortBy=SafetyArea&SortOrder=Desc","SafetyAreaDescending","Safety Area Descending"}, 407 {"&sortBy=FallHeight&SortOrder=Asc","FallHeightAscending","Fall Height Ascending"}, 408 {"&sortBy=FallHeight&SortOrder=Desc","FallHeightDescending","Fall Height Descending"} 409 }; 410 } 411 <nav aria-label="Product sort order and filters" class="dropdown-links"> 412 <ul> 413 <li class="dropdown-links__items"> 414 <!-- aria-expanded needs managed with Javascript --> 415 <button type="button" class="btn btn--outline dropdown-links__title" aria-expanded="false" aria-controls="sort-dropdown"> 416 @Translate("SortBy", "Sort by") 417 </button> 418 <ul class="dropdown-links__menu" id="sort-dropdown"> 419 <li> 420 <a href="@(pagelink)" 421 data-action-page="Product listing" 422 data-action-type="Sort by" 423 data-action-label="Default" 424 data-action-value=""> 425 @Translate("Default", "Default") 426 </a> 427 </li> 428 429 @for (int i = 0; i < sortOptions.GetLength(0); i++) 430 { 431 string activeClass = thisSortUrl == sortOptions[i, 0] ? "active" : ""; 432 <li> 433 <a href="@(pagelink)@(sortOptions[i, 0])" class="@activeClass" 434 data-action-page="Product listing" 435 data-action-type="Sort by" 436 data-action-label="@sortOptions[i, 2]" 437 data-action-value=""> 438 @Translate(@sortOptions[i, 1], @sortOptions[i, 2]) 439 </a> 440 </li> 441 } 442 443 @if (((thisPage.AreaID == 2)) && (ipPriceAllowed.Contains(currentCountry) || ipPriceAllowed.Contains("Hags_"))) 444 { 445 <li><a href="@(pagelink)&sortBy=Price&SortOrder=Asc">@Translate("Pricelow-high", "Price low-high")</a></li> 446 <li><a href="@(pagelink)&sortBy=Price&SortOrder=Desc">@Translate("Pricehigh-low", "Price high-low")</a></li> 447 } 448 </ul> 449 </li> 450 @if (materialOptions.Count > 1) 451 { 452 <li class="dropdown-links__items"> 453 <button type="button" class="btn btn--outline dropdown-links__title" aria-expanded="false" aria-controls="filter-dropdown"> 454 @Translate("MaterialOptions", "Material Options") 455 </button> 456 <ul class="dropdown-links__menu" id="filter-dropdown"> 457 <li><a href="@(pagelink)&sortBy=Default&filterBy=Default">@Translate("Default", "Default")</a></li> 458 @foreach (var a in materialOptions) 459 { 460 string[] s = a.Split(','); 461 <li> 462 <a href="@(pagelink)&sortBy=Default&filterBy=@(s[0])" 463 data-action-page="Product listing" 464 data-action-type="Filter by" 465 data-action-label="@s[1]" 466 data-action-value=""> 467 @s[1] 468 </a> 469 </li> 470 } 471 </ul> 472 </li> 473 } 474 </ul> 475 </nav> 476 477 @helper renderPagination(){ 478 <div class="wrapper"> 479 <nav class="pagination"> 480 <p class="pagination__count">@GetInteger("Ecom:ProductList.PageProdCnt") products</p> 481 <ul class="pagination__list" role="list"> 482 @{ 483 var prevLink = GetString("Ecom:ProductList.PrevPage.Clean"); 484 var nextLink = @GetString("Ecom:ProductList.NextPage.Clean"); 485 var prevLinkAttr = @GetString("Ecom:ProductList.PrevPage"); 486 var nextLinkAttr = @GetString("Ecom:ProductList.NextPage"); 487 var prevLinkClass = (prevLink == "") ? "inactive" : ""; 488 var nextLinkClass = (nextLink == "") ? "inactive" : ""; 489 string anchorTagPrev = (prevLink != "") ? "<a id=\"prevpage\" href=\"" + prevLink + "\" aria-label=\"Previous\">" : ""; 490 string anchorTagPrevClose = (prevLink != "") ? "</a>" : ""; 491 string anchorTagNext = (nextLink != "") ? "<a id=\"nextpage\" href=\"" + nextLink + "\" aria-label=\"Next\">" : ""; 492 string anchorTagNextClose = (nextLink != "") ? "</a>" : ""; 493 } 494 <li class="@prevLinkClass"> 495 @(anchorTagPrev) 496 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 212 212" class="h24-icon h24-icon--prev"><path fill="currentColor" fill-rule="evenodd" d="M106 6c55.193 0 100 44.807 100 100s-44.807 100-100 100S6 161.193 6 106 50.807 6 106 6Zm0 5.333c-26.124 0-49.792 10.603-66.928 27.74C21.936 56.207 11.333 79.875 11.333 106c0 26.124 10.603 49.792 27.74 66.928 17.135 17.136 40.803 27.739 66.927 27.739 26.124 0 49.792-10.603 66.928-27.74 17.136-17.135 27.739-40.803 27.739-66.927 0-26.124-10.603-49.792-27.74-66.928C155.793 21.936 132.125 11.333 106 11.333Zm16.66 55.907c2.993-2.14 7.16-1.44 9.3 1.553 2.14 2.994 1.44 7.16-1.554 9.3L113.21 90.376l-1.168.834L91.333 106l39.073 27.907c2.994 2.14 3.694 6.306 1.554 9.3-2.14 2.993-6.307 3.693-9.3 1.553l-20.642-14.745-1.038-.741-1.562-1.116-1.041-.744-14.79-10.567A13.319 13.319 0 0 1 78 106c0-4.307 2.08-8.347 5.586-10.847l14.79-10.567 1.042-.744 1.562-1.116 1.038-.741L122.66 67.24Z"/></svg> 497 <span class="visually-hidden">@Translate("page_Previous", "Previous")</span> 498 @(anchorTagPrevClose) 499 </li> 500 <li>@GetString("Ecom:ProductList.CurrentPage") @Translate("page_Of", "of") @GetString("Ecom:ProductList.TotalPages")</li> 501 <li class="@nextLinkClass"> 502 @(anchorTagNext) 503 <span class="visually-hidden">@Translate("page_Next", "Next")</span> 504 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 212 212" class="h24-icon h24-icon--next"><path fill="currentColor" fill-rule="evenodd" d="M106 6c55.193 0 100 44.807 100 100s-44.807 100-100 100S6 161.193 6 106 50.807 6 106 6Zm0 5.333c-26.124 0-49.792 10.603-66.928 27.74C21.936 56.207 11.333 79.875 11.333 106c0 26.124 10.603 49.792 27.74 66.928 17.135 17.136 40.803 27.739 66.927 27.739 26.124 0 49.792-10.603 66.928-27.74 17.136-17.135 27.739-40.803 27.739-66.927 0-26.124-10.603-49.792-27.74-66.928C155.793 21.936 132.125 11.333 106 11.333ZM96.54 67.24l20.642 14.745 1.038.741 1.561 1.116 1.042.744 1.559 1.114 1.034.739 12.197 8.714A13.319 13.319 0 0 1 141.2 106c0 4.307-2.08 8.347-5.587 10.847l-12.197 8.714-1.034.739-1.559 1.114-1.042.744-1.561 1.116-1.038.741A512447.69 512447.69 0 0 1 96.54 144.76c-2.993 2.14-7.16 1.44-9.3-1.553-2.14-2.994-1.44-7.16 1.553-9.3L127.867 106 88.793 78.093c-2.993-2.14-3.693-6.306-1.553-9.3 2.14-2.993 6.307-3.693 9.3-1.553Z"/></svg> 505 @(anchorTagNextClose) 506 </li> 507 </ul> 508 </nav> 509 </div> 510 } 511 512 513 @renderPagination() 514 </div> 515 </section> 516 517 518 519 520 <section class="products-listing"> 521 <div class="wrapper"> 522 <div class="products-listing__grid"> 523 524 525 @foreach (LoopItem item in GetLoop("Products")) 526 { 527 // Use imageUrl = HagsWeb.Library.Utilities.DWUtilities.GetSingleProductImageUrl(prod); 528 IEnumerable<ProductAsset> productImages = AssetManager_Repository.GetAssets(item.GetString("Ecom:Product.Number"), AssetType.Images, true) 529 .Where(n => n.FileName.StartsWith("medium_")); 530 531 ProductAsset image = productImages.FirstOrDefault(); 532 533 if (!string.IsNullOrEmpty(item.GetString("Ecom:Product.VariantID"))) 534 { 535 productLink = item.GetString("Ecom:Product.Link.Clean") + "&VariantID=" + item.GetString("Ecom:Product.VariantID"); 536 } 537 else 538 { 539 productLink = item.GetString("Ecom:Product.Link.Clean"); 540 } 541 542 543 // item.GetLoop("AgeRange.Options") is unreliable in the latest release DW 9.7.2 544 List<string> ageRanges = new List<string>(); 545 if (!string.IsNullOrEmpty(item.GetString("Ecom:Product:Field.AgeRange"))) 546 { 547 ageRanges = HagsWeb.Library.Methods.ProductProperties.ProductAgeRanges.GetAgeRanges(item.GetString("Ecom:Product:Field.AgeRange"), item.GetString("Ecom:Product.LanguageID")); 548 } 549 550 string ageRange = item.GetString("Ecom:Product:Field.AgeRange"); 551 string safetyArea = item.GetString("Ecom:Product:Field.SafetyArea"); 552 string fallHeight = item.GetString("Ecom:Product:Field.FallHeight"); 553 554 string variantId = item.GetString("Ecom:Product.VariantID"); 555 string formattedCurrency = item.GetInteger("Ecom:Product.DBPrice").ToString("C", new CultureInfo("sv-SE")); 556 557 //item.GetString("Ecom:Product:Field.AgeRange"); 558 //item.GetString("Ecom:Product:Field.SafetyArea"); 559 //item.GetString("Ecom:Product:Field.FallHeight"); 560 561 //bool isProductCollection = productCollectionItems.Any(n => n.ProductNumber == item.GetString("Ecom:Product.Number")); 562 //var s = HagsWeb.Library.Utilities.DWUtilities.GetProductUrl((item.GetString("Ecom:Product.Number"), thisPage.AreaID); 563 //string productLink = thisPage.SearchFriendlyUrl; 564 //var collectionLink = String.Format(productLink + "?ProductID={0}", item.GetString("Ecom:Product.ID")); 565 string collectionData = string.Format("CCAddToMyLists={0}&CCAddToListVariantID={1}&CCAddToListLanguageID={2}#{3}", item.GetString("Ecom:Product.Number"), item.GetString("Ecom:Product.VariantID"), thisPage.Area.GetByKey("areaecomlanguageid"), siteSection); 566 <div class="product-card"> 567 <input type="hidden" value="@variantId" /> 568 569 <!--div class="product-card__actions"> 570 <button type="button" class="action-btn" data-removeproductlist="" data-addproductlist="@collectionData"> 571 <span class="visually-hidden">@Translate("AddToCollection", "Add to my collection")</span> 572 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 212 212" class="h24-icon h24-icon--plus"><path fill="currentColor" fill-rule="evenodd" d="M106 6c55.193 0 100 44.807 100 100s-44.807 100-100 100S6 161.193 6 106 50.807 6 106 6Zm0 5.333c-26.124 0-49.792 10.603-66.928 27.74C21.936 56.207 11.333 79.875 11.333 106c0 26.124 10.603 49.792 27.74 66.928 17.135 17.136 40.803 27.739 66.927 27.739 26.124 0 49.792-10.603 66.928-27.74 17.136-17.135 27.739-40.803 27.739-66.927 0-26.124-10.603-49.792-27.74-66.928C155.793 21.936 132.125 11.333 106 11.333Zm.772 59.504a6.5 6.5 0 0 1 6.5 6.5v21.5h21.5a6.5 6.5 0 0 1 6.5 6.5v1a6.5 6.5 0 0 1-6.5 6.5h-21.5v21.5a6.5 6.5 0 0 1-6.5 6.5h-1a6.5 6.5 0 0 1-6.5-6.5v-21.5h-21.5a6.5 6.5 0 0 1-6.5-6.5v-1a6.5 6.5 0 0 1 6.5-6.5h21.5v-21.5a6.5 6.5 0 0 1 6.5-6.5h1Z"></path></svg> 573 </button> 574 </div--> 575 <div class="product-card__img-silo"> 576 577 @if (image != null && !String.IsNullOrEmpty(image.uri)) 578 { 579 <a href="@productLink"><img class="product-card__img" src="@image.uri"/></a> 580 } 581 else 582 { 583 <a href="@productLink"><img class="product-card__img" src="/Files/Templates/Designs/HagsCore/res/img/image-not-found.png" /></a> 584 } 585 586 </div> 587 588 589 <div class="product-card__copy" data-weglot="@(ipCountryCode)"> 590 591 <p class="product-card__heading"><a href="@productLink">@item.GetString("Ecom:Product.Name")</a></p> 592 @if ( showPrice ) 593 { 594 <p><span class="ts-0">@(formattedCurrency)</p> 595 } 596 </div> 597 </div> 598 } 599 </div> 600 </div> 601 </section> 602 603 @renderPagination()
Warranties
Find out what you are covered for.
Maintenance guide
How to look after your products.
Color & Anchoring Options
Explore your options.