Primy Rare R stålhåndvask, Rust

Vare nr.

440004

Vejl pris inkl. moms

10.299,00 DKK InStock

by Primy Rare R er en fritstående håndvask i massiv fortolkning med runde former og slanke linjer. Vasken er håndlavet med et unikt udtryk, hvor skandinavisk minimalisme kombineres med elegance.
Bundventil i matchende farve kan tilkøbes.
by Primy er vores mest eksklusive serie og kombinerer kvalitetsmaterialer og design i rustfrit stål med specielt udvalgte overflader i ultramat PVD*.

• Fremstillet i rustfrit stål med PVD* overfladebehandling i farven Rust
• Diameter: 375 mm
• Højde 90 mm

*PVD betyder Physical Vapour Deposition og er en trykpåført overfladebehandling som giver en slidstærk overflade.

Specifikationer

Materiale Rustfrit stål, PVD
Overflade PVD
Farve Rust
Godstykkelse 3
Hanehul Nej
Monteringsmuligheder (vask) På bord
Mål Ø375 x 90 mm
Kummemål Ø331 x 75 mm
Overløb Nej
Bundventil medfølger Nej
VVS nr. 643061615
EAN 7350086952070
Error executing template "Designs/Swift/Paragraph/Related_ProductList_Custom.cshtml"
System.Data.SqlClient.SqlException (0x80131904): Transaction (Process ID 71) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   at System.Data.SqlClient.SqlDataReader.TryHasMoreRows(Boolean& moreRows)
   at System.Data.SqlClient.SqlDataReader.TryReadInternal(Boolean setTimeout, Boolean& more)
   at System.Data.SqlClient.SqlDataReader.Read()
   at Dynamicweb.Ecommerce.Prices.PriceDataBaseDependecy.GetPrices(String ids)
   at Dynamicweb.Ecommerce.Prices.Price.LoadPricesOnProducts(IEnumerable`1 products)
   at Dynamicweb.Ecommerce.Prices.PriceManager.PreparePrices(PriceContext context, IEnumerable`1 selections)
   at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.PreparePrices(PriceContext context, Boolean& pricesHasBeenPrepared, Object lock, IList`1 products, Int64 stockLocationId)
   at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.GetPrice(PriceViewModelSettings settings, IList`1 products, Boolean& pricesHasBeenPrepared, Object lock, Lazy`1 priceInfo)
   at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.<>c__DisplayClass3_2.<BulkCreateView>b__49()
   at System.Lazy`1.CreateValue()
   at System.Lazy`1.LazyInitValue()
   at CompiledRazorTemplates.Dynamic.RazorEngine_a71d1e04291f4232a4be3262fe5b988a.<>c__DisplayClass0_0.<RenderProduct>b__0(TextWriter __razor_helper_writer) in D:\dynamicweb.net\Solutions\twodayco3\lavabo.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Related_ProductList_Custom.cshtml:line 622
   at CompiledRazorTemplates.Dynamic.RazorEngine_a71d1e04291f4232a4be3262fe5b988a.Execute() in D:\dynamicweb.net\Solutions\twodayco3\lavabo.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Related_ProductList_Custom.cshtml:line 496
   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()
ClientConnectionId:bbf4d03d-020e-47b0-928f-6cd84d4ea851
Error Number:1205,State:52,Class:13

1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel> 2 @using System 3 @using System.Collections.Generic 4 @using System.Linq 5 @using Dynamicweb.Core.Encoders 6 @using Dynamicweb.Ecommerce.ProductCatalog 7 @using Dynamicweb.Environment 8 @using Dynamicweb.Frontend 9 10 @{ 11 ProductViewModel dwProduct = new ProductViewModel(); 12 13 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 14 { 15 dwProduct = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 16 } 17 if (dwProduct == null) 18 { 19 return; 20 } 21 List<RelatedGroupViewModel> dwProductRelGroups = dwProduct.RelatedGroups; 22 23 if (dwProductRelGroups == null || !dwProductRelGroups.Any()) 24 { 25 return; 26 } 27 28 string anonymousUsersLimitations = Pageview.AreaSettings.GetRawValueString("AnonymousUsers", ""); 29 bool anonymousUser = Pageview.User == null; 30 bool isErpConnectionDown = !Dynamicweb.Ecommerce.DynamicwebLiveIntegration.TemplatesHelper.IsWebServiceConnectionAvailable(); 31 bool hideAddToCart = anonymousUsersLimitations.Contains("cart") && anonymousUser || Pageview.AreaSettings.GetBoolean("ErpDownHideAddToCart") && isErpConnectionDown; 32 bool hidePrice = anonymousUsersLimitations.Contains("price") && anonymousUser || Pageview.AreaSettings.GetBoolean("ErpDownHidePrices") && isErpConnectionDown; 33 34 string url = "/Default.aspx?ID=" + (GetPageIdByNavigationTag("CartService")); 35 if (!url.Contains("LayoutTemplate")) 36 { 37 url += url.Contains("?") ? "&LayoutTemplate=Swift_MiniCart.cshtml" : "?LayoutTemplate=Swift_MiniCart.cshtml"; 38 } 39 40 string iconPath = "/Files/icons/"; 41 42 string showPricesWithVat = Pageview.Area.EcomPricesWithVat.ToLower(); 43 bool neverShowVat = string.IsNullOrEmpty(showPricesWithVat); 44 45 IEnumerable<string> selectedDisplayGroupsList = Model.Item.GetRawValueString("Fields").Split(',').ToList(); 46 //Collect the titles for all available fields 47 List<string> fieldsHeaders = new List<string>(); 48 Dictionary<string, List<ProductViewModel>> productLists = new Dictionary<string, List<ProductViewModel>>(); 49 List<string> selectedRelGroups = Model.Item.GetRawValueString("VisibleRelatedGroups").Split(',').ToList(); 50 51 foreach (string selectedRelGroupId in selectedRelGroups) 52 { 53 RelatedGroupViewModel dwProductGroup = dwProductRelGroups.FirstOrDefault(rg => rg.Id == selectedRelGroupId); 54 55 if (dwProductGroup == null) 56 { 57 continue; 58 } 59 60 productLists[dwProductGroup.Name] = new List<ProductViewModel>(); 61 foreach (ProductInfoViewModel dwProductViewModelInfo in dwProductGroup.Products) 62 { 63 ProductViewModelSettings productSetting = new ProductViewModelSettings 64 { 65 LanguageId = Dynamicweb.Ecommerce.Common.Context.LanguageID, 66 CurrencyCode = Dynamicweb.Ecommerce.Common.Context.Currency.Code, 67 CountryCode = Dynamicweb.Ecommerce.Common.Context.Country.Code2, 68 ShopId = Pageview.Area.EcomShopId 69 }; 70 71 ProductViewModel productViewModel = dwProductViewModelInfo.ProductId != "" ? ViewModelFactory.CreateView(productSetting, dwProductViewModelInfo.ProductId) : new ProductViewModel(); 72 productLists[dwProductGroup.Name].Add(productViewModel); 73 } 74 } 75 76 foreach (var product in productLists.SelectMany(v => v.Value)) 77 { 78 foreach (var selection in selectedDisplayGroupsList) 79 { 80 foreach (CategoryFieldViewModel group in product.FieldDisplayGroups.Values) 81 { 82 if (selection.ToString() == group.Id) 83 { 84 foreach (var field in group.Fields) 85 { 86 if (!fieldsHeaders.Contains(field.Value.Name)) 87 { 88 bool noValues = false; 89 if (field.Value.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) { 90 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 91 noValues = values.Count > 0 ? false : true; 92 } else if (string.IsNullOrEmpty(field.Value.Value.ToString())) { 93 noValues = true; 94 } 95 96 if (!noValues) 97 { 98 fieldsHeaders.Add(field.Value.Name); 99 } 100 } 101 } 102 } 103 } 104 } 105 } 106 107 108 109 int pageSizeSetting = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["PageSizeSetting"]) ? Convert.ToInt32(Dynamicweb.Context.Current.Request.Form["PageSizeSetting"].ToString()) : 10; 110 string requestType = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["RequestType"]) ? Dynamicweb.Context.Current.Request.Form["RequestType"].ToString() : ""; 111 string title = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["Title"]) ? Dynamicweb.Context.Current.Request.Form["Title"].ToString() : ""; 112 string mainProductId = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["MainProductID"]) ? Dynamicweb.Context.Current.Request.Form["MainProductID"].ToString() : ""; 113 string paragraphID = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["ParagraphID"]) ? Dynamicweb.Context.Current.Request.Form["ParagraphID"].ToString() : ""; 114 string servicePageId = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["ID"]) ? Dynamicweb.Context.Current.Request.Form["ID"].ToString() : ""; 115 bool hideTitle = Model.Item.GetBoolean("HideTitle"); 116 bool hideImage = Model.Item.GetBoolean("HideImage"); 117 bool hideProductNumber = Model.Item.GetBoolean("HideProductNumber"); 118 bool hideProductName = Model.Item.GetBoolean("HideProductName"); 119 bool hideStock = Model.Item.GetBoolean("HideStock"); 120 bool quantitySelector = Model.Item.GetBoolean("QuantitySelector"); 121 string addToCartColWidth = quantitySelector ? "200" : "60"; 122 123 124 string saleBadgeType = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("SaleBadgeType")) ? Dynamicweb.Context.Current.Request.Form.Get("SaleBadgeType") : ""; 125 string saleBadgeCssClassName = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("SaleBadgeCssClassName")) ? Dynamicweb.Context.Current.Request.Form.Get("SaleBadgeCssClassName") : ""; 126 string newBadgeCssClassName = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("NewBadgeCssClassName")) ? Dynamicweb.Context.Current.Request.Form.Get("NewBadgeCssClassName") : ""; 127 int newPublicationDays = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("NewPublicationDays")) ? Convert.ToInt32(Dynamicweb.Context.Current.Request.Form.Get("NewPublicationDays")) : 0; 128 string campaignBadgesValues = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("CampaignBadgesValues")) ? Dynamicweb.Context.Current.Request.Form.Get("CampaignBadgesValues") : ""; 129 130 var badgeParms = new Dictionary<string, object>(); 131 badgeParms.Add("saleBadgeType", saleBadgeType); 132 badgeParms.Add("saleBadgeCssClassName", saleBadgeCssClassName); 133 badgeParms.Add("newBadgeCssClassName", newBadgeCssClassName); 134 badgeParms.Add("campaignBadgesValues", campaignBadgesValues); 135 badgeParms.Add("newPublicationDays", newPublicationDays); 136 137 bool saleBadgeEnabled = !string.IsNullOrWhiteSpace(saleBadgeCssClassName) && saleBadgeCssClassName != "none" ? true : false; 138 bool newBadgeEnabled = !string.IsNullOrWhiteSpace(newBadgeCssClassName) && newBadgeCssClassName != "none" ? true : false; 139 140 string theme = Model.Item.GetString("Theme"); 141 string modalTheme = Model.Item.GetString("ModalTheme"); 142 string titleFontSize = Model.Item.GetString("TitleFontSize"); 143 string contentPadding = Model.Item.GetString("ContentPadding"); 144 145 string contextCart = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["OrderContext"]) ? Dynamicweb.Context.Current.Request.Form["OrderContext"].ToString() : ""; 146 147 string googleAnalyticsTrackingID = Pageview.AreaSettings.GetString("GoogleAnalyticsTrackingID"); 148 string googleAnalyticsMeasurementID = Pageview.AreaSettings.GetString("GoogleAnalyticsMeasurementID"); 149 var cookieOptInLevel = CookieManager.GetCookieOptInLevel(); 150 bool allowTracking = cookieOptInLevel == CookieOptInLevel.All || (cookieOptInLevel == CookieOptInLevel.Functional && CookieManager.GetCookieOptInCategories().Contains("Statistical")); 151 152 if (Model.Item != null) 153 { 154 theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 155 contentPadding = Model.Item.GetRawValueString("ContentPadding", ""); 156 contentPadding = contentPadding == "none" ? "p-0" : contentPadding; 157 contentPadding = contentPadding == "small" ? "p-2 p-md-3" : contentPadding; 158 contentPadding = contentPadding == "large" ? "p-4 p-md-5" : contentPadding; 159 contentPadding = contentPadding == "small-x" ? "px-2 px-md-3" : contentPadding; 160 contentPadding = contentPadding == "large-x" ? "px-4 px-md-5" : contentPadding; 161 } 162 } 163 164 @if (productLists.Any()) { 165 166 if (!string.IsNullOrWhiteSpace(googleAnalyticsMeasurementID)) 167 { 168 string itemVariant = string.Empty; 169 170 <script> 171 gtag("event", "view_item_list", { 172 item_list_id: "related_product_list", 173 item_list_name: "Related products list", 174 items: [ 175 @foreach (ProductViewModel product in productLists.SelectMany(v => v.Value)) 176 { 177 if (!string.IsNullOrEmpty(product.VariantName)) 178 { 179 itemVariant = $"item_variant:'{product.VariantName}',"; 180 } 181 <text>{ 182 item_id: '@product.Number', 183 item_name: '@product.Name', 184 @itemVariant 185 currency: '@product.Price.CurrencyCode', 186 price: @product.Price.Price 187 },</text> 188 } 189 ] 190 }); 191 </script> 192 } 193 //The products list table 194 if (Model.Item.GetRawValueString("RelatedGroupsLayout") == "list") 195 { 196 197 <div class="table-responsive w-100"> 198 199 200 201 @foreach (KeyValuePair<string, List<ProductViewModel>> productListDict in productLists) 202 { 203 <div class="h-100 mb-4 @(contentPadding) @theme"> 204 <h3 class="@titleFontSize">@productListDict.Key</h3> 205 206 <table class="table table-sm table-striped align-middle text-nowrap mobile-responsive-table"> 207 <thead> 208 <tr class="fw-bold"> 209 @if (!hideImage) 210 { 211 <td scope="col">&nbsp;</td> 212 } 213 @if (!hideProductNumber) 214 { 215 <td scope="col" title="#">#</td> 216 } 217 @if (!hideProductName) 218 { 219 <td scope="col" style="width:50%;" title="@Translate("Product")">@Translate("Product")</td> 220 } 221 @foreach (var header in fieldsHeaders) 222 { 223 <td scope="col" title="@header">@header</td> 224 } 225 @if (!hideStock) 226 { 227 <td scope="col" title="@Translate("Stock")">@Translate("Stock")</td> 228 } 229 @if (!hidePrice) 230 { 231 <td scope="col" align="right" class="pe-2" title="@Translate("Price")">@Translate("Price")</td> 232 } 233 @if (!hideAddToCart) 234 { 235 <td scope="col" title="@Translate("Qty")">@Translate("Qty")</td> 236 } 237 </tr> 238 </thead> 239 240 <tbody> 241 @foreach (var product in productListDict.Value) 242 { 243 string image = product.DefaultImage.Value; 244 string popoverImage = product.DefaultImage.Value; 245 image = $"/Admin/Public/GetImage.ashx?image={image}&width=30&format=webp"; 246 popoverImage = $"/Admin/Public/GetImage.ashx?image={popoverImage}&width=350&Format=WebP&Quality=70"; 247 248 DateTime createdDate = product.Created.Value; 249 bool showBadges = saleBadgeEnabled && product.Discount.Price != 0 ? true : false; 250 showBadges = (newBadgeEnabled && newPublicationDays == 0) || (newBadgeEnabled && (createdDate.AddDays(newPublicationDays) > DateTime.Now)) ? true : showBadges; 251 showBadges = !string.IsNullOrEmpty(campaignBadgesValues) ? true : showBadges; 252 253 List<CategoryFieldViewModel> categories = new List<CategoryFieldViewModel>(); 254 foreach (var selection in selectedDisplayGroupsList) 255 { 256 foreach (CategoryFieldViewModel group in product.FieldDisplayGroups.Values) 257 { 258 if (selection.ToString() == group.Id) 259 { 260 categories.Add(group); 261 } 262 } 263 } 264 265 string variantIdForLink = !string.IsNullOrEmpty(product.VariantId) ? $"&VariantID={product.VariantId}" : ""; 266 variantIdForLink = string.IsNullOrEmpty(variantIdForLink) && !string.IsNullOrEmpty(product.DefaultVariantId) ? $"&VariantID={product.DefaultVariantId}" : variantIdForLink; 267 268 string link = "Default.aspx?ID=" + GetPageIdByNavigationTag("Shop"); 269 link += $"&GroupID={product.PrimaryOrDefaultGroup.Id}"; 270 link += $"&ProductID={product.Id}"; 271 link += variantIdForLink; 272 link = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(link); 273 274 <tr> 275 @if (!hideImage) 276 { 277 <td width="30" scope="row" data-bs-toggle="popover" data-bs-placement="right" data-bs-content="<img src='@popoverImage' style='max-width:100%;' />" data-bs-html="true" data-bs-trigger="hover focus"> 278 <img src="@image"/> 279 </td> 280 } 281 @if (!hideProductNumber) 282 { 283 <td scope="row" title="#"> 284 <a href="@link"> 285 @product.Number 286 </a> 287 </td> 288 } 289 @if (!hideProductName) 290 { 291 <td scope="row" title="@Translate("Product")"> 292 @if (!string.IsNullOrEmpty(product.VariantName)) 293 { 294 <div>@product.Name - @product.VariantName</div> 295 } 296 else 297 { 298 @product.Name 299 } 300 301 @if (showBadges) 302 { 303 <div class="fs-7"> 304 @RenderPartial("Components/EcommerceBadge.cshtml", product, badgeParms) 305 </div> 306 } 307 </td> 308 } 309 @foreach (string fieldCell in fieldsHeaders) 310 { 311 FieldValueViewModel fieldValue = new FieldValueViewModel(); 312 bool fieldFound = false; 313 string fieldTitle = default(string); 314 315 foreach (CategoryFieldViewModel category in categories) 316 { 317 foreach (var field in category.Fields) 318 { 319 bool noValues = false; 320 if (field.Value.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 321 { 322 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 323 noValues = values.Count > 0 ? false : true; 324 } 325 else if (string.IsNullOrEmpty(field.Value.Value.ToString())) 326 { 327 noValues = true; 328 } 329 330 if (!noValues) 331 { 332 string fieldName = field.Value.Name; 333 if (fieldName == fieldCell) 334 { 335 fieldValue = field.Value; 336 fieldTitle = fieldName; 337 fieldFound = true; 338 } 339 } 340 } 341 } 342 343 if (fieldFound) 344 { 345 <td title="@fieldTitle">@RenderFieldValue(fieldValue)</td> 346 } 347 else 348 { 349 <td>&nbsp;</td> 350 } 351 } 352 353 @if (!hideStock) 354 { 355 <td title="@Translate("Stock")"> 356 @if (product.StockLevel > 0) 357 { 358 <span class="text-success">@Translate("In stock")</span> 359 } 360 else 361 { 362 <span class="text-danger">@Translate("Out of stock")</span> 363 } 364 </td> 365 } 366 @if (!hidePrice) 367 { 368 <td align="right" class="pe-2" title="@Translate("Price")"> 369 <div itemprop="offers" itemscope itemtype="https://schema.org/Offer"> 370 <span itemprop="priceCurrency" content="@product.Price.CurrencyCode" class="d-none"></span> 371 372 @if (showPricesWithVat == "false" && !neverShowVat) 373 { 374 <span itemprop="price" content="@product.Price.PriceWithoutVat" class="d-none"></span> 375 if (product.Price.Price != product.PriceBeforeDiscount.Price) 376 { 377 <span class="text-decoration-line-through opacity-75 me-3"> 378 @product.PriceBeforeDiscount.PriceWithoutVatFormatted 379 </span> 380 } 381 } 382 else 383 { 384 <span itemprop="price" content="@product.Price.Price" class="d-none"></span> 385 if (product.Price.Price != product.PriceBeforeDiscount.Price) 386 { 387 <span class="text-decoration-line-through opacity-75 me-3"> 388 @product.PriceBeforeDiscount.PriceFormatted 389 </span> 390 } 391 } 392 393 @if (showPricesWithVat == "false" && !neverShowVat) 394 { 395 <span class="text-price">@product.Price.PriceWithoutVatFormatted</span> 396 } 397 else 398 { 399 <span class="text-price">@product.Price.PriceWithVatFormatted</span> 400 } 401 </div> 402 @if (showPricesWithVat == "false" && !neverShowVat) 403 { 404 <small class="opacity-85 fst-normal">@product.Price.PriceWithVatFormatted @Translate("Incl. VAT")</small> 405 } 406 </td> 407 } 408 @if (!hideAddToCart) 409 { 410 bool isDiscontinued = product.Discontinued; 411 bool IsNeverOutOfStock = product.NeverOutOfstock; 412 string disableAddToCart = (product.StockLevel <= 0) ? "disabled" : ""; 413 disableAddToCart = isDiscontinued ? "disabled" : disableAddToCart; 414 disableAddToCart = IsNeverOutOfStock ? "" : disableAddToCart; 415 416 string minQty = product.PurchaseMinimumQuantity != 1 ? "min=\"" + product.PurchaseMinimumQuantity.ToString() + "\"" : "min=\"1\""; 417 string stepQty = product.PurchaseQuantityStep > 1 ? product.PurchaseQuantityStep.ToString() : "1"; 418 string valueQty = product.PurchaseMinimumQuantity > product.PurchaseQuantityStep ? product.PurchaseMinimumQuantity.ToString() : stepQty; 419 string qtyValidCheck = stepQty != "1" ? "onkeyup=\"swift.Cart.QuantityValidate(event)\"" : ""; 420 421 <td width="@addToCartColWidth" style="min-width: @(addToCartColWidth)px" align="right" title="@Translate("Qty")"> 422 <form method="post" action="@url"> 423 @if (!string.IsNullOrEmpty(contextCart)) 424 { 425 <input type="hidden" name="OrderContext" value="@contextCart"/> 426 <input type="hidden" name="minicartid" value="@contextCart"/> 427 } 428 <input type="hidden" name="redirect" value="false"/> 429 <input type="hidden" name="ProductId" value="@product.Id"/> 430 <input type="hidden" name="ProductName" value="@product.Name"/> 431 <input type="hidden" name="ProductVariantName" value="@product.VariantName"/> 432 <input type="hidden" name="ProductCurrency" value="@Dynamicweb.Ecommerce.Common.Context.Currency.Code"/> 433 <input type="hidden" name="ProductPrice" value="@product.Price"/> 434 <input type="hidden" name="ProductReferer" value="product_list_related"> 435 <input type="hidden" name="cartcmd" value="add"/> 436 437 @if (!string.IsNullOrEmpty(product.VariantId)) 438 { 439 <input type="hidden" name="VariantId" value="@product.VariantId"/> 440 } 441 442 @if (quantitySelector) 443 { 444 <div class="flex-fill input-group input-primary-button-group d-flex flex-row"> 445 <label for="Quantity_@(product.Id)_@product.VariantId" class="visually-hidden">@Translate("Quantity")</label> 446 <input id="Quantity_@(product.Id)_@product.VariantId" name="Quantity" value="0" step="@stepQty" @minQty class="form-control" style="max-width: 100px" type="number" onkeydown="swift.Cart.UpdateOnEnterKey(event)"> 447 <button type="button" onclick="swift.Cart.Update(event)" class="btn btn-primary flex-fill js-add-to-cart-button icon-2 @disableAddToCart" @disableAddToCart title="@Translate("Add to cart")" id="AddToCartButton@(product.Id)">@ReadFile(iconPath + "shopping-cart.svg")</button> 448 @if (stepQty != "1") 449 { 450 <div class="invalid-feedback d-none"> 451 @Translate("Please select a quantity that is dividable by") @stepQty 452 </div> 453 } 454 </div> 455 } 456 else 457 { 458 <input id="Quantity_@(product.Id)_@product.VariantId" name="Quantity" value="@valueQty" type="hidden"> 459 <button type="button" onclick="swift.Cart.Update(event)" class="btn btn-primary flex-fill js-add-to-cart-button @disableAddToCart icon-2" @disableAddToCart title="@Translate("Add to cart")" id="AddToCartButton@(product.Id)">@ReadFile(iconPath + "shopping-cart.svg")</button> 460 } 461 </form> 462 </td> 463 } 464 </tr> 465 } 466 </tbody> 467 </table> 468 </div> 469 } 470 471 472 </div> 473 } 474 475 if (Model.Item.GetRawValueString("RelatedGroupsLayout") == "slider") 476 { 477 <style> 478 .slider-indicators>*{ background-color: #000;} 479 </style> 480 <script type="module" src="/Files/Templates/Designs/Swift/Assets/js/swiffy-slider.js"></script> 481 <script type="module"> 482 swift.AssetLoader.Load('Files/Templates/Designs/Swift/Assets/css/swiffy-slider.min.css', 'css'); 483 </script> 484 <div class="h-100 grid gap-0"> 485 @foreach (var productDict in productLists) 486 { 487 Guid guid = Guid.NewGuid(); 488 489 490 <div class="g-col-12 mt-4 item_@(Model.Item.SystemName.ToLower())"> 491 <h3 class="mb-4">@productDict.Key</h3> 492 <div id="Slider_@guid" class="swiffy-slider slider-item-show5 slider-nav-chevron-default slider-item-reveal slider-nav-on-slides slider-indicators-dash" style="--swiffy-slider-nav-light:var(--swift-foreground-color);--swiffy-slider-nav-dark:var(--swift-background-color);"> 493 <ul class="slider-container"> 494 @foreach (var product in productDict.Value) 495 { 496 @RenderProduct(product) 497 } 498 </ul> 499 <button type="button" title="@Translate("Previous slide")" class="slider-nav" style="z-index:2;"> 500 <span class="visually-hidden">@Translate("Previous slide")</span> 501 </button> 502 <button type="button" title="@Translate("Next slide")" class="slider-nav slider-nav-next" style="z-index:2;"> 503 <span class="visually-hidden">@Translate("Next slide")</span> 504 </button> 505 506 <div class="slider-indicators" style="z-index:2;bottom: -2em;"> 507 @{ 508 bool isActive = true; 509 int slideCount = 1; 510 } 511 512 @foreach (var item in productDict.Value) 513 { 514 <button @(isActive ? "class=\"active\"" : string.Empty) type="button" title='@Translate("Go to slide") @slideCount' > 515 <span class="visually-hidden">@Translate("Go to slide") @slideCount</span> 516 </button> 517 { 518 slideCount++; 519 } 520 isActive = false; 521 } 522 </div> 523 </div> 524 525 526 527 <script type="module"> 528 document.addEventListener('load.swift.assetloader', () => { 529 swiffyslider.initSlider(document.querySelector('#Slider_@guid')); 530 document.querySelector('#Slider_@guid').style.opacity = 1; 531 document.querySelector('#Slider_@guid').style.visibility = "visible"; 532 }); 533 </script> 534 </div> 535 536 537 538 } 539 </div> 540 } 541 542 543 } 544 545 @helper RenderProduct(ProductViewModel product) { 546 string anonymousUsersLimitations = Pageview.AreaSettings.GetRawValueString("AnonymousUsers", ""); 547 bool anonymousUser = Pageview.User == null; 548 bool hidePrice = anonymousUsersLimitations.Contains("price") && anonymousUser || Pageview.AreaSettings.GetBoolean("ErpDownHidePrices") && !Dynamicweb.Ecommerce.DynamicwebLiveIntegration.TemplatesHelper.IsWebServiceConnectionAvailable(); 549 bool showFavoritesSelectorMasterProduct = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("ShowFavoritesSelectorMasterProduct")) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.Form.Get("ShowFavoritesSelectorMasterProduct")) : false; 550 551 string ratio = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("ImageAspectRatio")) ? Dynamicweb.Context.Current.Request.Form.Get("ImageAspectRatio") : ""; 552 string ratioCssClass = ratio != "" ? "ratio" : ""; 553 string ratioVariable = ratio != "" ? "--bs-aspect-ratio: " + ratio : ""; 554 555 string theme = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("Theme")) ? Dynamicweb.Context.Current.Request.Form.Get("Theme") : ""; 556 string themePadding = theme != string.Empty ? "p-3" : string.Empty; 557 string imageTheme = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("ImageTheme")) ? Dynamicweb.Context.Current.Request.Form.Get("ImageTheme") : ""; 558 string imageOutlineStyle = imageTheme == string.Empty ? "border: 1px solid transparent;" : string.Empty; 559 string imageThemePadding = imageTheme != string.Empty ? "p-3" : string.Empty; 560 string ContentPadding = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("ContentPadding")) ? Dynamicweb.Context.Current.Request.Form.Get("ContentPadding") : ""; 561 562 string showPricesWithVat = Pageview.Area.EcomPricesWithVat.ToLower(); 563 bool neverShowVat = string.IsNullOrEmpty(showPricesWithVat); 564 565 string variantIdForLink = !string.IsNullOrEmpty(product.VariantId) ? $"&VariantID={product.VariantId}" : ""; 566 variantIdForLink = string.IsNullOrEmpty(variantIdForLink) && !string.IsNullOrEmpty(product.DefaultVariantId) ? $"&VariantID={product.DefaultVariantId}" : variantIdForLink; 567 568 string link = "Default.aspx?ID=" + GetPageIdByNavigationTag("Shop"); 569 link += $"&GroupID={product.PrimaryOrDefaultGroup.Id}"; 570 link += $"&ProductID={product.Id}"; 571 link += variantIdForLink; 572 link = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(link); 573 574 string imagePath = product?.DefaultImage.Value.ToString() ?? ""; 575 imagePath = "/Admin/Public/GetImage.ashx?image=" + imagePath + "&width=" + 350 + "&Format=WebP&Quality=70"; 576 577 string saleBadgeType = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("SaleBadgeType")) ? Dynamicweb.Context.Current.Request.Form.Get("SaleBadgeType") : ""; 578 string saleBadgeCssClassName = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("SaleBadgeCssClassName")) ? Dynamicweb.Context.Current.Request.Form.Get("SaleBadgeCssClassName") : ""; 579 string newBadgeCssClassName = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("NewBadgeCssClassName")) ? Dynamicweb.Context.Current.Request.Form.Get("NewBadgeCssClassName") : ""; 580 int newPublicationDays = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("NewPublicationDays")) ? Convert.ToInt32(Dynamicweb.Context.Current.Request.Form.Get("NewPublicationDays")) : 0; 581 string campaignBadgesValues = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("CampaignBadgesValues")) ? Dynamicweb.Context.Current.Request.Form.Get("CampaignBadgesValues") : ""; 582 583 var badgeParms = new Dictionary<string, object>(); 584 badgeParms.Add("saleBadgeType", saleBadgeType); 585 badgeParms.Add("saleBadgeCssClassName", saleBadgeCssClassName); 586 badgeParms.Add("newBadgeCssClassName", newBadgeCssClassName); 587 badgeParms.Add("campaignBadgesValues", campaignBadgesValues); 588 badgeParms.Add("newPublicationDays", newPublicationDays); 589 590 bool saleBadgeEnabled = !string.IsNullOrWhiteSpace(saleBadgeCssClassName) && saleBadgeCssClassName != "none" ? true : false; 591 bool newBadgeEnabled = !string.IsNullOrWhiteSpace(newBadgeCssClassName) && newBadgeCssClassName != "none" ? true : false; 592 DateTime createdDate = product.Created.Value; 593 bool showBadges = saleBadgeEnabled && product.Discount.Price != 0 ? true : false; 594 showBadges = (newBadgeEnabled && newPublicationDays == 0) || (newBadgeEnabled && (createdDate.AddDays(newPublicationDays) > DateTime.Now)) ? true : showBadges; 595 showBadges = !string.IsNullOrEmpty(campaignBadgesValues) ? true : showBadges; 596 <li> 597 <a href="@link" class="text-decoration-none d-block h-100"> 598 <div class="h-100 d-flex flex-column justify-content-between theme theme-gray-border"> 599 <div style="border: 1px solid transparent;"> 600 <div class="ratio position-relative" style="--bs-aspect-ratio: 75%"> 601 @if (showBadges) { 602 <div class="position-absolute top-0 left-0 p-1 p-lg-2" style="z-index: 2"> 603 @RenderPartial("Components/EcommerceBadge.cshtml", product, badgeParms) 604 </div> 605 } 606 <img loading="lazy" decoding="async" src="@imagePath" class="h-100 w-100 " style="object-fit: contain;" alt="@product.Name"> 607 </div> 608 </div> 609 <div class="flex-fill d-flex flex-column justify-content-between p-3"> 610 <h3 class="h6 opacity-85">@product.Name @product.VariantName</h3> 611 612 @if (!hidePrice) { 613 <div> 614 <p class="h6 m-0"> 615 @if (showPricesWithVat == "false" && !neverShowVat) { 616 if (product.Price.Price != product.PriceBeforeDiscount.Price) { 617 <span class="text-decoration-line-through opacity-75 me-1"> 618 @product.PriceBeforeDiscount.PriceWithoutVatFormatted 619 </span> 620 } 621 } else { 622 if (product.Price.Price != product.PriceBeforeDiscount.Price) { 623 <span class="text-decoration-line-through opacity-75 me-1"> 624 @product.PriceBeforeDiscount.PriceFormatted 625 </span> 626 } 627 } 628 629 @if (showPricesWithVat == "false" && !neverShowVat) { 630 <span class="text-price fw-bold">@product.Price.PriceWithoutVatFormatted</span> 631 } else { 632 <span class="text-price fw-bold">@product.Price.PriceWithVatFormatted</span> 633 } 634 </p> 635 @if (showPricesWithVat == "false" && !neverShowVat) { 636 <small class="opacity-85 fst-normal">@product.Price.PriceWithVatFormatted @Translate("Incl. VAT")</small> 637 } 638 </div> 639 } 640 </div> 641 </div> 642 </a> 643 </li> 644 } 645 646 647 @helper RenderFieldValue(FieldValueViewModel field) { 648 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 649 650 fieldValue = fieldValue == "False" ? Translate("No") : fieldValue; 651 fieldValue = fieldValue == "True" ? Translate("Yes") : fieldValue; 652 653 bool isColor = false; 654 655 if (field.Value.GetType() == typeof(System.Collections.Generic.List<Dynamicweb.Ecommerce.ProductCatalog.FieldOptionValueViewModel>)) 656 { 657 int valueCount = 0; 658 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 659 int totalValues = values.Count; 660 661 foreach (FieldOptionValueViewModel option in values) 662 { 663 if (option.Value.Substring(0,1) == "#") { 664 isColor = true; 665 } 666 667 if (!isColor) { 668 @option.Name 669 } else { 670 <span class="colorbox-sm" style="background-color: @option.Value" title="@option.Value"></span> 671 } 672 673 if (valueCount != totalValues && valueCount < (totalValues - 1)) { 674 if (isColor) { 675 <text> </text> 676 } else { 677 <text>, </text> 678 } 679 } 680 valueCount++; 681 } 682 } 683 else if (fieldValue != "") 684 { 685 if (fieldValue.Substring(0,1) == "#") { 686 isColor = true; 687 } 688 689 if (!isColor) { 690 @fieldValue 691 } else { 692 <span class="colorbox-sm" style="background-color: @fieldValue" title="@fieldValue"></span> 693 } 694 } 695 } 696 697 698 699 @helper RenderCheckboxOption(FacetViewModel facet, FacetOptionViewModel facetOption) 700 { 701 string facetLabel = HtmlEncoder.HtmlEncode(facetOption.Label); 702 string disabled = facetOption.Count <= 0 ? "disabled" : ""; 703 string selected = facetOption.Selected ? "checked" : ""; 704 705 if (facetLabel.ToLower() == "true") 706 { 707 facetLabel = Translate("Yes"); 708 } 709 710 if (facetLabel.ToLower() == "false") 711 { 712 facetLabel = Translate("No"); 713 } 714 715 <label class="form-check mb-1" @disabled> 716 <input type="checkbox" onclick="swift.PageUpdater.Update(event)" class="form-check-input" name="@facet.QueryParameter" value="[@facetOption.Value]" data-filter-value="@facetLabel" @selected> 717 <span class="form-check-label d-flex align-items-center"> 718 <span class="flex-fill">@facetLabel </span> 719 <small class="opacity-85">@facetOption.Count</small> 720 </span> 721 </label> 722 } 723 724 @helper RenderColorOption(FacetViewModel facet, FacetOptionViewModel facetOption) 725 { 726 string facetLabel = HtmlEncoder.HtmlEncode(facetOption.Label); 727 string disabled = facetOption.Count <= 0 ? "disabled" : ""; 728 string selected = facetOption.Selected ? "checked" : ""; 729 730 string image = facetOption.Value; 731 string colorCode = facetOption.Value; 732 733 var variantOption = Dynamicweb.Ecommerce.Services.VariantOptions.GetVariantOption(facetOption.Value.ToString(), Dynamicweb.Ecommerce.Common.Context.LanguageID); 734 if (variantOption != null) 735 { 736 image = variantOption.LargeImage; 737 colorCode = variantOption.Color; 738 } 739 740 <div class="colorbox"> 741 <input type="checkbox" onclick="swift.PageUpdater.Update(event)" class="@disabled @selected" name="@facet.QueryParameter" value="[@facetOption.Value]" data-filter-value="@facetLabel" @selected title="@facetOption.Label"> 742 @if (colorCode.Contains("#")) 743 { 744 <span class="colorbox-background" style="background-color: @colorCode"></span> 745 } 746 else 747 { 748 <img class="colorbox-background" src="/Admin/Public/GetImage.ashx?width=25&height=25&image=@image" /> 749 } 750 </div> 751 } 752