Tuotteet

47 tuotteet
Error executing template "/Designs/Swift/Paragraph/SwiftCustom_ProductListGridView.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 Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.GetFieldDisplayGroupValues(ProductViewModelSettings settings, Product product, String languageID, Lazy`1 productIds)
   at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.<>c__DisplayClass3_1.<BulkCreateView>b__51()
   at System.Lazy`1.CreateValue()
   at System.Lazy`1.LazyInitValue()
   at CompiledRazorTemplates.Dynamic.RazorEngine_aaaaa7dedb1343fcbcc16663124079d8.<RenderProductList>b__6_0(TextWriter __razor_helper_writer) in D:\DW9\Solutions\witt.dk\Files\Templates\Designs\Swift\Paragraph\SwiftCustom_ProductListGridView.cshtml:line 172
   at CompiledRazorTemplates.Dynamic.RazorEngine_aaaaa7dedb1343fcbcc16663124079d8.Execute() in D:\DW9\Solutions\witt.dk\Files\Templates\Designs\Swift\Paragraph\SwiftCustom_ProductListGridView.cshtml:line 47
   at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader)
   at RazorEngine.Templating.RazorEngineService.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 Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template)
   at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template)
   at Dynamicweb.Rendering.Template.RenderRazorTemplate()

1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using Dynamicweb.Ecommerce.ProductCatalog 3 @using Dynamicweb.Ecommerce.CustomerExperienceCenter.Favorites 4 @using System.Linq 5 @using Dynamicweb.Core 6 7 @functions 8 { 9 bool isLazyLoadingForProductInfoEnabled = Dynamicweb.Ecommerce.DynamicwebLiveIntegration.TemplatesHelper.IsLazyLoadingForProductInfoEnabled; 10 string liveInfoClass = ""; 11 string productInfoFeed = ""; 12 13 string showPricesWithVat = ""; 14 bool neverShowVat = false; 15 16 ProductListViewModel productList = new ProductListViewModel(); 17 } 18 @{ 19 if (Dynamicweb.Context.Current.Items.Contains("ProductList")) 20 { 21 productList = (ProductListViewModel)Dynamicweb.Context.Current.Items["ProductList"]; 22 } 23 24 showPricesWithVat = Pageview.Area.EcomPricesWithVat.ToLower(); 25 neverShowVat = string.IsNullOrEmpty(showPricesWithVat); 26 27 if (isLazyLoadingForProductInfoEnabled) 28 { 29 if (Dynamicweb.Context.Current.Items.Contains("ProductInfoFeed")) 30 { 31 productInfoFeed = Dynamicweb.Context.Current.Items["ProductInfoFeed"]?.ToString(); 32 if (!string.IsNullOrEmpty(productInfoFeed)) 33 { 34 productInfoFeed = $"data-product-info-feed=\"{productInfoFeed}\""; 35 } 36 } 37 liveInfoClass = "js-live-info"; 38 } 39 40 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 41 string themePadding = theme != string.Empty ? "p-3" : string.Empty; 42 } 43 44 @if (!string.IsNullOrEmpty(theme)) 45 { 46 <div class="h-100@(theme) @themePadding item_@Model.Item.SystemName.ToLower()" @productInfoFeed> 47 @RenderProductList() 48 </div> 49 } 50 else 51 { 52 <div class="pt-3 item_@Model.Item.SystemName.ToLower()" @productInfoFeed> 53 @RenderProductList() 54 </div> 55 } 56 57 @helper RenderProductList() 58 { 59 string anonymousUsersLimitations = Pageview.AreaSettings.GetRawValueString("AnonymousUsers", ""); 60 bool anonymousUser = Pageview.User == null; 61 bool hidePrice = anonymousUsersLimitations.Contains("price") && anonymousUser || Pageview.AreaSettings.GetBoolean("ErpDownHidePrices") && !Dynamicweb.Ecommerce.DynamicwebLiveIntegration.TemplatesHelper.IsWebServiceConnectionAvailable(); 62 63 string detailsPageLink = Dynamicweb.Context.Current.Items["DetailsPageLink"] != null ? Dynamicweb.Context.Current.Items["DetailsPageLink"].ToString() : ""; 64 string productTheme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("ProductTheme")) ? " theme " + Model.Item.GetRawValueString("ProductTheme").Replace(" ", "").Trim().ToLower() : ""; 65 string productThemePadding = productTheme != string.Empty ? "p-3" : string.Empty; 66 67 string url = Dynamicweb.Context.Current.Request.RawUrl; 68 bool hideFavoritesSelector = !string.IsNullOrEmpty(Model.Item.GetString("HideFavoritesSelector")) ? Model.Item.GetBoolean("HideFavoritesSelector") : false; 69 string staticVariantsLayout = Model.Item.GetRawValueString("StaticVariantsLayout", "hide"); 70 71 string groupId = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("GroupID")) ? Dynamicweb.Context.Current.Request.QueryString.Get("GroupID") : ""; 72 73 var badgeParms = new Dictionary<string, object>(); 74 badgeParms.Add("saleBadgeType", Model.Item.GetRawValue("SaleBadgeType")); 75 badgeParms.Add("saleBadgeCssClassName", Model.Item.GetRawValue("SaleBadgeDesign")); 76 badgeParms.Add("newBadgeCssClassName", Model.Item.GetRawValue("NewBadgeDesign")); 77 badgeParms.Add("newPublicationDays", Model.Item.GetInt32("NewPublicationDays")); 78 badgeParms.Add("campaignBadgesValues", Model.Item.GetRawValueString("CampaignBadges")); 79 80 bool saleBadgeEnabled = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("SaleBadgeDesign")) && Model.Item.GetRawValueString("SaleBadgeDesign") != "none" ? true : false; 81 bool newBadgeEnabled = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("NewBadgeDesign")) && Model.Item.GetRawValueString("NewBadgeDesign") != "none" ? true : false; 82 83 var favoriteParameters = new Dictionary<string, object>(); 84 if (!anonymousUser && !hideFavoritesSelector) 85 { 86 int defaultFavoriteListId = 0; 87 88 IEnumerable<FavoriteList> favoreiteLists = Pageview.User.GetFavoriteLists(); 89 if (favoreiteLists.Count() == 1) 90 { 91 foreach (FavoriteList list in favoreiteLists) 92 { 93 defaultFavoriteListId = list.ListId; 94 } 95 } 96 97 favoriteParameters.Add("ListId", defaultFavoriteListId); 98 } 99 100 if (productList.TotalProductsCount > 0) 101 { 102 int pageSizeSetting = 30; 103 int pageSize = productList.PageSize; 104 pageSize += pageSizeSetting; 105 106 int loadedProducts = productList.PageSize > productList.TotalProductsCount ? productList.TotalProductsCount : productList.PageSize; 107 108 //REMOVE BEFORE RELEASE 109 //Dynamicweb.Ecommerce.Common.Context.CartContext = Dynamicweb.Ecommerce.Orders.OrderContext.GetOrderContextById("ORDERCONTEXT2"); 110 111 <div class="grid grid-2 grid-lg-3"> 112 @foreach (ProductViewModel product in productList.Products) 113 { 114 var defaultGroupId = product.PrimaryOrDefaultGroup.Id; 115 var selectedDetailPage = Dynamicweb.Ecommerce.Services.ProductGroups.GetGroup(defaultGroupId)?.Meta.PrimaryPage ?? string.Empty; 116 117 string link = string.IsNullOrEmpty(selectedDetailPage) ? $"{detailsPageLink}&groupid={defaultGroupId}" : selectedDetailPage; 118 link += "&productid=" + product.Id; 119 link += !string.IsNullOrEmpty(product.VariantId) ? "&variantid=" + product.VariantId : ""; 120 121 string imagePath = product?.DefaultImage?.Value ?? ""; 122 imagePath = Dynamicweb.Context.Current.Server.UrlEncode(imagePath); 123 124 string ratio = Model.Item.GetRawValueString("ImageAspectRatio", ""); 125 ratio = ratio != "0" ? ratio : ""; 126 string ratioCssClass = ratio != "" ? " ratio" : ""; 127 string ratioVariable = ratio != "" ? "--bs-aspect-ratio: " + ratio : ""; 128 129 string imagePathXs = "/Admin/Public/GetImage.ashx?width=" + 480 + "&image=" + imagePath + "&format=webp"; 130 string imagePathS = "/Admin/Public/GetImage.ashx?width=" + 640 + "&image=" + imagePath + "&format=webp"; 131 string imagePathFallBack = "/Admin/Public/GetImage.ashx?width=" + 640 + "&image=" + imagePath + "&format=webp"; 132 133 string imageTheme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("ImageTheme")) ? " theme " + Model.Item.GetRawValueString("ImageTheme").Replace(" ", "").Trim().ToLower() : ""; 134 string imageThemePadding = imageTheme != string.Empty ? "p-3" : string.Empty; 135 string imageOutlineStyle = imageTheme == string.Empty ? "style=\"border: 1px solid transparent\"" : string.Empty; 136 137 string imageId = "ProductImage_" + product.Id + product.VariantId; 138 string priceId = "ProductPrice_" + product.Id + product.VariantId; 139 140 @* Alternative image *@ 141 var supportedImageFormats = new string[] { ".jpg", ".webp", ".png", ".gif" }; 142 string defaultImage = product.DefaultImage != null ? product.DefaultImage.Value : ""; 143 var selectedAssetCategories = Model.Item.GetRawValueString("AlternativeImageAssets"); 144 IEnumerable<MediaViewModel> alternativeImagesList = product.AssetCategories.Where(x => selectedAssetCategories.Contains(x.SystemName)).SelectMany(x => x.Assets); 145 146 if (alternativeImagesList.FirstOrDefault() != null) 147 { 148 alternativeImagesList = alternativeImagesList.OrderByDescending(x => x.Value.Equals(defaultImage)); 149 150 if (alternativeImagesList.First().Value == defaultImage) 151 { 152 alternativeImagesList = alternativeImagesList.Skip(1); 153 } 154 } 155 156 string alternativeImage = alternativeImagesList.FirstOrDefault() != null ? alternativeImagesList.FirstOrDefault().Value : ""; 157 alternativeImage = !string.IsNullOrEmpty(alternativeImage) ? "/Admin/Public/GetImage.ashx?width=" + 640 + "&image=" + alternativeImage + "&format=webp" : ""; 158 159 160 @* Badges *@ 161 DateTime createdDate = product.Created.Value; 162 bool showBadges = saleBadgeEnabled && product.PriceInformative.Price > product.Price.Price ? true : false; 163 showBadges = (newBadgeEnabled && Model.Item.GetInt32("NewPublicationDays") == 0) || (newBadgeEnabled && (createdDate.AddDays(Model.Item.GetInt32("NewPublicationDays")) > DateTime.Now)) ? true : showBadges; 164 showBadges = !string.IsNullOrEmpty(Model.Item.GetRawValueString("CampaignBadges")) ? true : showBadges; 165 166 @* Main features *@ 167 IEnumerable<string> selectedDisplayGroups = Model.Item.GetRawValueString("MainFeatures").Split(',').ToList(); 168 List<CategoryFieldViewModel> mainFeatures = new List<CategoryFieldViewModel>(); 169 170 foreach (var selection in selectedDisplayGroups) 171 { 172 foreach (CategoryFieldViewModel group in product.FieldDisplayGroups.Values) 173 { 174 if (selection == group.Id) 175 { 176 mainFeatures.Add(group); 177 } 178 } 179 } 180 181 <article class="position-relative@(productTheme) product-list-item product @liveInfoClass mb-4" data-product-id="@product.Id" itemscope itemtype="https://schema.org/Product"> 182 @if (!anonymousUser && !hideFavoritesSelector && product.VariantInfo.VariantInfo == null) 183 { 184 185 <div class="position-absolute top-0 end-0 my-3" style="z-index: 2"> 186 @RenderPartial("Components/ToggleFavorite.cshtml", product, favoriteParameters) 187 </div> 188 } 189 190 @if (showBadges) 191 { 192 <div class="position-absolute top-0 left-0 p-1 p-lg-2 ps-0 ps-lg-0" style="z-index: 2"> 193 @RenderPartial("Components/Custom_EcommerceBadge.cshtml", product, badgeParms) 194 </div> 195 } 196 197 <div class="d-flex flex-column d-block h-100"> 198 199 @if (product.VariantInfo.VariantInfo == null) 200 { 201 @:<a href="@link" class="text-decoration-none"> 202 } 203 204 <div class="overflow-hidden@(imageTheme)" @imageOutlineStyle> 205 <div class="ratio" style="@(ratioVariable)"> 206 <div class="d-flex justify-content-center align-items-start"> 207 @if (product.VariantInfo.VariantInfo != null) 208 { 209 <div id="swiper-@product.Id" class="swiper variant-swiper swiper-container h-100"> 210 <div class="swiper-wrapper"> 211 @foreach (var variantGroup in product.VariantGroups()) 212 { 213 foreach (var variant in variantGroup.Options) 214 { 215 imagePath = variant.Image.Value; 216 imagePathXs = "/Admin/Public/GetImage.ashx?width=" + 480 + "&image=" + imagePath + "&format=webp"; 217 imagePathS = "/Admin/Public/GetImage.ashx?width=" + 640 + "&image=" + imagePath + "&format=webp"; 218 219 <div class="swiper-slide text-center"> 220 <a href="@link"> 221 <img id="@imageId" 222 srcset="@imagePathXs 480w,@imagePathS 640w" 223 sizes="(min-width: 992px) 33vw, 50vw" 224 src="@imagePathFallBack" 225 loading="lazy" 226 decoding="async" 227 class="mw-100 mh-100 @imageThemePadding" 228 alt="@variant.Name"> 229 </a> 230 </div> 231 232 } 233 } 234 </div> 235 <!--If we need navigation buttons --> 236 <div class="swiper-button-prev swiper-nav"></div> 237 <div class="swiper-button-next swiper-nav"></div> 238 </div> 239 240 <script> 241 new Swiper("#swiper-@product.Id", { 242 navigation: { 243 nextEl: ".swiper-button-next", 244 prevEl: ".swiper-button-prev", 245 }, 246 }); 247 </script> 248 249 } 250 else 251 { 252 if (string.IsNullOrEmpty(alternativeImage)) 253 { 254 <img id="@imageId" 255 srcset=" 256 @imagePathXs 480w, 257 @imagePathS 640w" 258 sizes="(min-width: 992px) 33vw, 50vw" 259 src="@imagePathFallBack" 260 loading="lazy" 261 decoding="async" 262 class="mw-100 mh-100 @imageThemePadding" 263 alt="@product.Name"> 264 } 265 else 266 { 267 <img id="@imageId" 268 src="@imagePathFallBack" 269 loading="lazy" 270 decoding="async" 271 class="mw-100 mh-100 @imageThemePadding" 272 alt="@product.Name" 273 onmouseover="this.src='@alternativeImage'" 274 onmouseout="this.src='@imagePathFallBack'"> 275 } 276 277 } 278 </div> 279 </div> 280 </div> 281 <div class="@productThemePadding"> 282 <div class="flex-grow-1"> 283 <h3 class="h6 mb-0 text-break"> 284 @product.Name @if (!string.IsNullOrEmpty(product.VariantName)) 285 {<text>(@product.VariantName)</text>} 286 </h3> 287 @if (!Model.Item.GetBoolean("HideProductNumber")) 288 { 289 <p class="fs-7 opacity-85 mb-2">@product.Number</p> 290 } 291 @if (mainFeatures.Count > 0) 292 { 293 <ul class="p-0 lh-sm opacity-75" style="list-style-position: inside"> 294 @foreach (CategoryFieldViewModel mainFeatureGroup in mainFeatures) 295 { 296 foreach (var field in mainFeatureGroup.Fields) 297 { 298 @RenderField(field.Value) 299 } 300 } 301 </ul> 302 } 303 </div> 304 305 @if (!hidePrice) 306 { 307 string priceMin = ""; 308 string priceMax = ""; 309 310 <div> 311 <div> 312 <span itemprop="priceCurrency" content="@product.Price.CurrencyCode" class="d-none"></span> 313 314 @if (showPricesWithVat == "false" && !neverShowVat) 315 { 316 if (isLazyLoadingForProductInfoEnabled) 317 { 318 <span itemprop="price" content="" class="d-none"></span> 319 <span class="text-decoration-line-through js-text-decoration-line-through opacity-75 me-3 text-price js-text-price d-none" data-show-if="LiveProductInfo.product.Price.Price != LiveProductInfo.product.PriceInformative.Price"></span> 320 } 321 else 322 { 323 string beforePrice = product.PriceInformative.PriceWithoutVatFormatted; 324 <span itemprop="price" content="@product.Price.PriceWithoutVat" class="d-none"></span> 325 if (product.Price.Price != product.PriceInformative.Price) 326 { 327 <span class="text-decoration-line-through opacity-75 me-3 text-price">@beforePrice</span> 328 } 329 } 330 331 } 332 else 333 { 334 335 if (isLazyLoadingForProductInfoEnabled) 336 { 337 <span itemprop="price" content="" class="d-none"></span> 338 <span class="text-decoration-line-through js-text-decoration-line-through opacity-75 me-3 text-price js-text-price d-none" data-show-if="LiveProductInfo.product.Price.Price != LiveProductInfo.product.PriceInformative.Price"></span> 339 } 340 else 341 { 342 string beforePrice = product.PriceInformative.PriceFormatted; 343 <span itemprop="price" content="@product.Price.Price" class="d-none"></span> 344 if (product.Price.Price != product.PriceInformative.Price && !string.IsNullOrWhiteSpace(beforePrice)) 345 { 346 <span class="text-decoration-line-through opacity-75 me-3 text-price">@beforePrice</span> 347 } 348 } 349 } 350 351 @if (showPricesWithVat == "false" && !neverShowVat) 352 { 353 if (isLazyLoadingForProductInfoEnabled) 354 { 355 <span class="text-price js-text-price"><div class="spinner-border" role="status"></div></span> 356 } 357 else 358 { 359 string price = product.Price.PriceWithoutVatFormatted; 360 if (product?.VariantInfo?.VariantInfo != null) 361 { 362 priceMin = product?.VariantInfo?.PriceMin?.PriceWithoutVatFormatted != null ? product.VariantInfo.PriceMin.PriceWithoutVatFormatted : ""; 363 priceMax = product?.VariantInfo?.PriceMax?.PriceWithoutVatFormatted != null ? product.VariantInfo.PriceMax.PriceWithoutVatFormatted : ""; 364 } 365 if (priceMin != priceMax) 366 { 367 price = priceMin + " - " + priceMax; 368 } 369 <span class="text-price">@price</span> 370 } 371 } 372 else 373 { 374 if (isLazyLoadingForProductInfoEnabled) 375 { 376 <span class="text-price js-text-price"><div class="spinner-border" role="status"></div></span> 377 } 378 else 379 { 380 string price = product.Price.PriceFormatted; 381 if (product?.VariantInfo?.VariantInfo != null) 382 { 383 priceMin = product?.VariantInfo?.PriceMin?.PriceFormatted != null ? product.VariantInfo.PriceMin.PriceFormatted : ""; 384 priceMax = product?.VariantInfo?.PriceMax?.PriceFormatted != null ? product.VariantInfo.PriceMax.PriceFormatted : ""; 385 } 386 if (priceMin != priceMax) 387 { 388 price = priceMin + " - " + priceMax; 389 } 390 <span class="text-price">@price</span> 391 } 392 } 393 </div> 394 @if (showPricesWithVat == "false" && !neverShowVat) 395 { 396 if (isLazyLoadingForProductInfoEnabled) 397 { 398 <div class="fs-7 opacity-85 text-price js-text-price-with-vat d-none" data-suffix="@Translate("Incl. VAT")"></div> 399 } 400 else 401 { 402 string price = product.Price.PriceWithVatFormatted; 403 if (product?.VariantInfo?.VariantInfo != null) 404 { 405 priceMin = product?.VariantInfo?.PriceMin?.PriceWithVatFormatted != null ? product.VariantInfo.PriceMin.PriceWithVatFormatted : ""; 406 priceMax = product?.VariantInfo?.PriceMax?.PriceWithVatFormatted != null ? product.VariantInfo.PriceMax.PriceWithVatFormatted : ""; 407 } 408 if (priceMin != priceMax) 409 { 410 price = priceMin + " - " + priceMax; 411 } 412 <div class="fs-7 opacity-85 text-price">@price @Translate("Incl. VAT")</div> 413 } 414 } 415 </div> 416 } 417 418 @if (product.VariantInfo.VariantInfo != null && staticVariantsLayout == "swatches") 419 { 420 var optionCount = product.VariantInfo.VariantInfo.Count(); 421 var showMaxVariants = 5; 422 423 <div class="d-flex flex-row gap-1 align-items-center"> 424 @foreach (VariantInfoViewModel variant in product.VariantInfo.VariantInfo.Take(showMaxVariants)) 425 { 426 <span class="colorbox colorbox-sm rounded-circle border me-1" style="background-color: @variant.OptionColor"></span> 427 } 428 @if (optionCount > showMaxVariants) 429 { 430 int left = optionCount - showMaxVariants; 431 <span class="ms-2">+@left</span> 432 } 433 </div> 434 } 435 </div> 436 437 438 @if (product.VariantInfo.VariantInfo == null) 439 { 440 @:</a> 441 } 442 443 <div class="px-3 mt-auto"> 444 @{ 445 string actionUrl = "/Default.aspx?ID=" + (GetPageIdByNavigationTag("CartService")); 446 string disableAddToCart = (product.StockLevel <= 0 && !product.NeverOutOfstock) ? "disabled" : ""; 447 string buttonTitle = disableAddToCart == "disabled" ? Translate("Out of stock") : Translate("Add to cart"); 448 bool hasExpectedDelivery = product.ExpectedDelivery != null && product.ExpectedDelivery > DateTime.Now; 449 string expectedDeliveryDate = product.ExpectedDelivery?.ToShortDateString() ?? ""; 450 } 451 452 @if (product.NeverOutOfstock) 453 { 454 if (product.StockLevel <= 0) 455 { 456 <div class="p-2"> 457 458 <div class="m-0 small"> 459 <span class="text-button-secondary icon-2"> 460 <svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" width="18" height="18" class="bi bi-exclamation-circle-fill" viewBox="0 0 18 18"> 461 <path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM8 4a.905.905 0 0 0-.9.995l.35 3.507a.552.552 0 0 0 1.1 0l.35-3.507A.905.905 0 0 0 8 4zm.002 6a1 1 0 1 0 0 2 1 1 0 0 0 0-2z" /> 462 </svg> 463 </span> 464 <span>@Translate("Out of Stock")</span> 465 @if (hasExpectedDelivery) 466 { 467 <span class="">(@Translate("Expected delivery date:") @expectedDeliveryDate)</span> 468 } 469 </div> 470 471 </div> 472 473 } 474 } 475 476 @if (product.VariantGroups().Any()) 477 { 478 <div class="d-grid"> 479 <a href="@link" class="btn btn-primary flex-fill" title="@buttonTitle" id="AddToCartButton@(product.Id)">@Translate("Choose")</a> 480 </div> 481 } 482 else 483 { 484 <form method="post" action="@actionUrl"> 485 <input type="hidden" name="redirect" value="false" /> 486 <input type="hidden" name="ProductId" value="@product.Id" /> 487 <input type="hidden" name="cartcmd" value="add" /> 488 489 @if (!string.IsNullOrEmpty(product.VariantId)) 490 { 491 <input type="hidden" name="VariantId" value="@product.VariantId" /> 492 } 493 494 <input id="Quantity_@(product.Id)_@product.VariantId" name="Quantity" value="1" type="hidden"> 495 496 <div class="d-grid"> 497 <button type="button" onclick="AddToCartGTM(this, @BuildGMTParameterString(product));" class="btn btn-primary flex-fill js-add-to-cart-button @disableAddToCart" @disableAddToCart title="@buttonTitle" id="AddToCartButton@(product.Id)">@buttonTitle</button> 498 </div> 499 500 </form> 501 } 502 </div> 503 </div> 504 </article> 505 } 506 </div> 507 508 <div class="my-3" id="LoadMoreButton"> 509 <div class="text-center d-flex flex-column gap-3"> 510 <div class="opacity-85">@loadedProducts @Translate("out of") @productList.TotalProductsCount @Translate("products")</div> 511 @if (productList.PageCount != 1) 512 { 513 string sortBySelection = Dynamicweb.Context.Current.Request?.Form["SortBy"] ?? "NameForSort"; 514 sortBySelection = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("SortBy")) ? Dynamicweb.Context.Current.Request.QueryString.Get("SortBy") : sortBySelection; 515 516 string searchQuery = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("q")) ? Dynamicweb.Context.Current.Request.QueryString.Get("q") : ""; 517 string searchLayout = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("SearchLayout")) ? Dynamicweb.Context.Current.Request.QueryString.Get("SearchLayout") : ""; 518 519 <form method="get" action="@url" data-response-target-element="content" class="w-100"> 520 @foreach (FacetGroupViewModel facetGroup in productList.FacetGroups) 521 { 522 foreach (FacetViewModel facetItem in facetGroup.Facets) 523 { 524 foreach (FacetOptionViewModel facetOption in facetItem.Options) 525 { 526 if (facetOption.Selected) 527 { 528 <input type="hidden" name="@facetItem.QueryParameter" value="[@facetOption.Value]" /> 529 } 530 } 531 } 532 } 533 534 @if (productList?.Group?.Id != null) 535 { 536 <input type="hidden" name="GroupId" value="@productList.Group.Id" /> 537 } 538 539 <input type="hidden" name="PageSize" value="@pageSize" /> 540 <input type="hidden" name="SortBy" value="@sortBySelection" /> 541 <input type="hidden" name="RequestType" value="UpdateList" /> 542 543 @if (!string.IsNullOrEmpty(searchQuery)) 544 { 545 <input type="hidden" name="q" value="@searchQuery" /> 546 <input type="hidden" name="SearchLayout" value="@searchLayout" /> 547 } 548 549 <button class="btn btn-primary" type="button" onclick="swift.ProductList.Update(event)">@Translate("Load more products")</button> 550 </form> 551 } 552 </div> 553 </div> 554 555 <script> 556 function switchVariantProduct(id, price, imagesrc) { 557 var productImageElement = document.querySelector("#ProductImage_" + id); 558 var productPriceElement = document.querySelector("#ProductPrice_" + id + " .text-price"); 559 560 if (productPriceElement) { 561 productPriceElement.innerText = price; 562 } 563 564 if (productImageElement) { 565 productImageElement.src = imagesrc; 566 567 var imageSrcset = productImageElement.srcset; 568 imageSrcset = imageSrcset.replace(/image=.*?&/g, 'image=' + imagesrc + "&"); 569 570 productImageElement.srcset = imageSrcset; 571 } 572 } 573 </script> 574 } 575 else 576 { 577 if (!Pageview.IsVisualEditorMode) 578 { 579 <div class="alert alert-dark m-0"> 580 @Translate("We did not find anything matching your search result") 581 </div> 582 } 583 else 584 { 585 <div class="alert alert-dark m-0" role="alert"> 586 <span>@Translate("Product list: The list will be shown here, if any")</span> 587 </div> 588 } 589 } 590 } 591 592 @helper RenderField(FieldValueViewModel field) 593 { 594 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 595 596 if (fieldValue != "") 597 { 598 fieldValue = fieldValue == "False" ? Translate("No") : fieldValue; 599 fieldValue = fieldValue == "True" ? Translate("Yes") : fieldValue; 600 601 if (field.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 602 { 603 fieldValue = ""; 604 605 foreach (FieldOptionValueViewModel option in field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>) 606 { 607 fieldValue = option.Name; 608 } 609 } 610 611 bool isColor = false; 612 if (fieldValue.Contains("#") && (Translate(field.Name) == Translate("Color") || Translate(field.Name) == Translate("Colour"))) 613 { 614 isColor = true; 615 } 616 617 if (!string.IsNullOrEmpty(fieldValue)) 618 { 619 if (!isColor) 620 { 621 <li>@(field.Name): @fieldValue</li> 622 } 623 else 624 { 625 <li class="position-relative"> 626 <span class="colorbox-sm" style="background-color: @fieldValue"></span> 627 </li> 628 } 629 } 630 } 631 } 632 633 @functions { 634 635 private string BuildGMTParameterString(ProductViewModel product) 636 { 637 //currencyCode, productName, productId, productPrice, productCategory, quantity, img 638 string currencyCode = product.Price.CurrencyCode; 639 string productName = System.Web.HttpUtility.JavaScriptStringEncode(product.Name); 640 string productId = product.Number; 641 string productPrice = product.Price.Price.ToString(); 642 string productCategory = System.Web.HttpUtility.JavaScriptStringEncode(product.PrimaryOrDefaultGroup.Name); 643 int quantity = 1; 644 645 return $"'{currencyCode}', '{productName}', '{productId}', '{productPrice}', '{productCategory}', {quantity}"; 646 } 647 }