Error executing template "/Designs/Swift/Paragraph/Swift_ProductDetailsInfo.cshtml"
System.NullReferenceException: Object reference not set to an instance of an object.
   at CompiledRazorTemplates.Dynamic.RazorEngine_a7bb22bf54fc4da3937659fbd9f59388.Execute() in D:\dynamicweb.net\Solutions\Dynamicweb\bomedys.cloud.dynamicweb-cms.com\files\Templates\Designs\Swift\Paragraph\Swift_ProductDetailsInfo.cshtml:line 391
   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 Dynamicweb.Ecommerce.Products.FieldDisplayGroups 5 @using Dynamicweb.Frontend 6 @using Dynamicweb.Core 7 @using System.Drawing 8 @using Dynamicweb.Environment 9 10 @functions { 11 //Find contrast color (white, black) 12 public static string GetContrastColor(string hexString) 13 { 14 System.Drawing.Color bg = System.Drawing.ColorTranslator.FromHtml(hexString); 15 16 int nThreshold = 105; 17 int bgDelta = Convert.ToInt32((bg.R * 0.299) + (bg.G * 0.587) + 18 (bg.B * 0.114)); 19 20 string foreColor = (255 - bgDelta < nThreshold) ? "#333" : "#fff"; 21 return foreColor; 22 } 23 } 24 25 @{ 26 string googleAnalyticsTrackingID = Pageview.AreaSettings.GetString("GoogleAnalyticsTrackingID"); 27 string googleAnalyticsMeasurementID = Pageview.AreaSettings.GetString("GoogleAnalyticsMeasurementID"); 28 var cookieOptInLevel = CookieManager.GetCookieOptInLevel(); 29 bool allowTracking = cookieOptInLevel == CookieOptInLevel.All || (cookieOptInLevel == CookieOptInLevel.Functional && CookieManager.GetCookieOptInCategories().Contains("Statistical")); 30 31 ProductViewModel product = new ProductViewModel(); 32 33 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 34 { 35 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 36 } 37 38 string anonymousUsersLimitations = Pageview.AreaSettings.GetRawValueString("AnonymousUsers", ""); 39 bool anonymousUser = Pageview.User == null; 40 bool isErpConnectionDown = !Dynamicweb.Ecommerce.DynamicwebLiveIntegration.TemplatesHelper.IsWebServiceConnectionAvailable(); 41 bool hideAddToCart = anonymousUsersLimitations.Contains("cart") && anonymousUser || Pageview.AreaSettings.GetBoolean("ErpDownHideAddToCart") && isErpConnectionDown; 42 hideAddToCart = product?.VariantInfo?.VariantInfo != null && Model.Item.GetBoolean("HideVariantSelector") ? true : hideAddToCart; 43 bool hideStock = Model.Item.GetBoolean("HideStockState") || (Pageview.AreaSettings.GetBoolean("ErpDownHideStock") && isErpConnectionDown); 44 bool hidePrice = anonymousUsersLimitations.Contains("price") && anonymousUser || Pageview.AreaSettings.GetBoolean("ErpDownHidePrices") && isErpConnectionDown; 45 bool hideFavoritesSelector = !string.IsNullOrEmpty(Model.Item.GetString("HideFavoritesSelector")) ? Model.Item.GetBoolean("HideFavoritesSelector") : false; 46 47 bool isDiscontinued = product.Discontinued; 48 bool IsNeverOutOfStock = product.NeverOutOfstock; 49 string[] variantId = { }; 50 51 if (product?.VariantId != null) { 52 variantId = product.VariantId.Split('.'); 53 } 54 55 string disableAddToCart = (product.StockLevel <= 0) ? "disabled" : ""; 56 disableAddToCart = isDiscontinued ? "disabled" : disableAddToCart; 57 disableAddToCart = IsNeverOutOfStock ? "" : disableAddToCart; 58 59 // Does product has a expected delivery data 60 bool hasExpectedDelivery = product.ExpectedDelivery != null && product.ExpectedDelivery > DateTime.Now; 61 string expectedDeliveryDate = product.ExpectedDelivery?.ToShortDateString() ?? ""; 62 63 string url = "/Default.aspx?ID=" + (GetPageIdByNavigationTag("CartService")); 64 if (!url.Contains("LayoutTemplate")) 65 { 66 url += url.Contains("?") ? "&LayoutTemplate=Swift_MiniCart.cshtml" : "?LayoutTemplate=Swift_MiniCart.cshtml"; 67 } 68 69 IEnumerable<string> selectedDisplayGroups = Model.Item.GetRawValueString("MainFeatures").Split(',').ToList(); 70 List<CategoryFieldViewModel> mainFeatures = new List<CategoryFieldViewModel>(); 71 72 foreach (var selection in selectedDisplayGroups) 73 { 74 foreach (CategoryFieldViewModel group in product.FieldDisplayGroups.Values) 75 { 76 if (selection == group.Id) 77 { 78 mainFeatures.Add(group); 79 } 80 } 81 } 82 83 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 84 85 string titleFontSize = Model.Item.GetRawValueString("TitleFontSize", "display-6"); 86 87 string contentPadding = Model.Item.GetRawValueString("ContentPadding", ""); 88 contentPadding = contentPadding == "small" ? "p-2 p-md-3" : contentPadding; 89 contentPadding = contentPadding == "large" ? "p-4 p-md-5" : contentPadding; 90 91 string quantityPricesLayout = Model.Item.GetRawValueString("QuantityPricesLayout", "list"); 92 93 string minQty = product.PurchaseMinimumQuantity != 1 ? "min=\"" + product.PurchaseMinimumQuantity.ToString() + "\"" : "min=\"1\""; 94 string stepQty = product.PurchaseQuantityStep > 1 ? product.PurchaseQuantityStep.ToString() : "1"; 95 string valueQty = product.PurchaseMinimumQuantity > product.PurchaseQuantityStep ? product.PurchaseMinimumQuantity.ToString() : stepQty; 96 string qtyValidCheck = stepQty != "1" ? "onkeyup=\"swift.Cart.QuantityValidate(event)\"" : ""; 97 98 string showPricesWithVat = Pageview.Area.EcomPricesWithVat.ToLower(); 99 bool neverShowVat = string.IsNullOrEmpty(showPricesWithVat); 100 101 string priceMin = ""; 102 string priceMax = ""; 103 104 var favoriteParameters = new Dictionary<string, object>(); 105 if (!anonymousUser && !hideFavoritesSelector) 106 { 107 IEnumerable<FavoriteList> favoreiteLists = Pageview.User.GetFavoriteLists(); 108 int defaultFavoriteListId = 0; 109 110 if (favoreiteLists.Count() == 1) { 111 foreach (FavoriteList list in favoreiteLists) { 112 defaultFavoriteListId = list.ListId; 113 } 114 } 115 116 favoriteParameters.Add("ListId", defaultFavoriteListId); 117 } 118 119 var priceParms = new Dictionary<string, object>(); 120 priceParms.Add("theme", ""); 121 122 var badgeParms = new Dictionary<string, object>(); 123 badgeParms.Add("size", "h7"); 124 badgeParms.Add("saleBadgeType", Model.Item.GetRawValue("SaleBadgeType")); 125 badgeParms.Add("saleBadgeCssClassName", Model.Item.GetRawValue("SaleBadgeDesign")); 126 badgeParms.Add("newBadgeCssClassName", Model.Item.GetRawValue("NewBadgeDesign")); 127 badgeParms.Add("newPublicationDays", Model.Item.GetInt32("NewPublicationDays")); 128 badgeParms.Add("campaignBadgesValues", Model.Item.GetRawValueString("CampaignBadges")); 129 130 bool saleBadgeEnabled = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("SaleBadgeDesign")) && Model.Item.GetRawValueString("SaleBadgeDesign") != "none" ? true : false; 131 bool newBadgeEnabled = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("NewBadgeDesign")) && Model.Item.GetRawValueString("NewBadgeDesign") != "none" ? true : false; 132 DateTime createdDate = product.Created.Value; 133 bool showBadges = saleBadgeEnabled && product.Discount.Price != 0 ? true : false; 134 showBadges = (newBadgeEnabled && Model.Item.GetInt32("NewPublicationDays") == 0) || (newBadgeEnabled && (createdDate.AddDays(Model.Item.GetInt32("NewPublicationDays")) > DateTime.Now)) ? true : showBadges; 135 showBadges = !string.IsNullOrEmpty(Model.Item.GetRawValueString("CampaignBadges")) ? true : showBadges; 136 137 string liveInfoClass = ""; 138 string productInfoFeed = ""; 139 bool isLazyLoadingForProductInfoEnabled = Dynamicweb.Ecommerce.DynamicwebLiveIntegration.TemplatesHelper.IsLazyLoadingForProductInfoEnabled; 140 if (isLazyLoadingForProductInfoEnabled) 141 { 142 if (Dynamicweb.Context.Current.Items.Contains("ProductInfoFeed")) 143 { 144 productInfoFeed = Dynamicweb.Context.Current.Items["ProductInfoFeed"]?.ToString(); 145 if (!string.IsNullOrEmpty(productInfoFeed)) 146 { 147 productInfoFeed = $"data-product-info-feed=\"{productInfoFeed}\""; 148 } 149 } 150 liveInfoClass = "js-live-info"; 151 } 152 } 153 154 @if (!string.IsNullOrWhiteSpace(googleAnalyticsMeasurementID) && allowTracking) 155 { 156 <script> 157 gtag("event", "view_item", { 158 currency: "@product.Price.CurrencyCode", 159 value: @product.Price.Price, 160 items: [ 161 { 162 item_id: "@product.Number", 163 item_name: "@product.Name", 164 currency: "@product.Price.CurrencyCode", 165 price: @product.Price.Price 166 } 167 ] 168 }); 169 </script> 170 } 171 172 <div class="h-100 @(contentPadding) @(theme) [email protected]()" @productInfoFeed> 173 <div class="d-flex flex-column gap-4 js-product" data-product-id="@product.Id"> 174 @if (showBadges) { 175 <div class="swift_badge-collection"> 176 @RenderPartial("Components/EcommerceBadge.cshtml", product, badgeParms) 177 </div> 178 } 179 180 <div class="d-flex flex-column gap-2"> 181 <h1 class="@titleFontSize m-0" itemprop="name">@product.Name</h1> 182 @if (!Model.Item.GetBoolean("HideProductNumber")) 183 { 184 @RenderPartial("Paragraph/Swift_ProductNumber.cshtml", Model) 185 } 186 </div> 187 188 @if (!hidePrice && !isDiscontinued) 189 { 190 @RenderPartial("Paragraph/Swift_ProductPrice.cshtml", Model, priceParms) 191 192 if (isLazyLoadingForProductInfoEnabled) 193 { 194 <div class="product-prices-container @liveInfoClass d-none" data-show-if="LiveProductInfo.product.Prices.length > 0"> 195 @if (quantityPricesLayout == "list") 196 { 197 <div class="mt-3 product-prices"> 198 <small class="d-block opacity-75 product-prices-template"><span><span class="js-text-price-quantity"></span> @Translate("PCS")</span> - <span class="fw-bold"><span class="js-text-price-price"></span> <span class="d-none" data-show-if="LiveProductInfo.productPrice.Quantity > 1">@Translate("pr. PCS")</span></span></small> 199 </div> 200 } 201 else if (quantityPricesLayout == "table") 202 { 203 <div class="grid"> 204 <table class="table table-sm mt-3 g-col-12 g-col-lg-6"> 205 <thead> 206 <tr> 207 <td>@Translate("QTY")</td> 208 <td>@Translate("pr. PCS")</td> 209 </tr> 210 </thead> 211 <tbody class="product-prices"> 212 <tr class="product-prices-template"> 213 <td class="js-text-price-quantity"></td> 214 <td class="js-text-price-price"></td> 215 </tr> 216 </tbody> 217 </table> 218 </div> 219 } 220 </div> 221 } 222 else 223 { 224 if (product.Prices.Count > 0) 225 { 226 <div> 227 @if (quantityPricesLayout == "list") 228 { 229 <div class="mt-3"> 230 @foreach (PriceListViewModel quantityPrice in product.Prices) 231 { 232 string quantityLabel = Translate("PCS"); 233 string quantityPriceSuffix = quantityPrice.Quantity > 1 ? Translate("pr. PCS") : ""; 234 235 <small class="d-block opacity-75"><span>@quantityPrice.Quantity @quantityLabel</span> - <span class="fw-bold">@quantityPrice.Price.PriceFormatted @quantityPriceSuffix</span></small> 236 } 237 </div> 238 } 239 else if (quantityPricesLayout == "table") 240 { 241 <div class="grid"> 242 <table class="table table-sm mt-3 g-col-12 g-col-lg-6"> 243 <thead> 244 <tr> 245 <td>@Translate("QTY")</td> 246 <td>@Translate("pr. PCS")</td> 247 </tr> 248 </thead> 249 <tbody> 250 @foreach (PriceListViewModel quantityPrice in product.Prices) 251 { 252 <tr> 253 <td>@quantityPrice.Quantity</td> 254 <td>@quantityPrice.Price.PriceFormatted</td> 255 </tr> 256 } 257 </tbody> 258 </table> 259 </div> 260 } 261 </div> 262 } 263 } 264 } 265 266 @RenderPartial("Paragraph/Swift_ProductShortDescription.cshtml", Model) 267 268 @if (mainFeatures.Count > 0) 269 { 270 foreach (CategoryFieldViewModel mainFeatureGroup in mainFeatures) 271 { 272 <dl class="grid gap-0"> 273 @foreach (var field in mainFeatureGroup.Fields) 274 { 275 @RenderField(field.Value) 276 } 277 </dl> 278 } 279 } 280 281 @if (product.VariantInfo.VariantInfo != null && !Model.Item.GetBoolean("HideVariantSelector")) 282 { 283 int groupNumber = 1; 284 285 string baseUrl = $"Default.aspx?ID={GetPageIdByNavigationTag("Shop")}&GroupID={product.PrimaryOrDefaultGroup.Id}&ProductID={product.Id}"; 286 string variantUrl = ""; 287 if (!string.IsNullOrEmpty(product.VariantId)) 288 { 289 variantUrl = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl($"Default.aspx?ID={GetPageIdByNavigationTag("Shop")}&GroupID={product.PrimaryOrDefaultGroup.Id}&ProductID={product.Id}&VariantID={product.VariantId}"); 290 } 291 292 <form class="js-variant-selector" data-combinations="@string.Join(",", product.VariantCombinations())" data-base-url="@baseUrl" data-friendly-url="@variantUrl"> 293 <input type="hidden" name="variantid" /> 294 295 @foreach (var variantGroup in product.VariantGroups()) 296 { 297 VariantGroupViewModel group = variantGroup; 298 299 <h3 class="h6">@group.Name</h3> 300 <div class="d-flex gap-2 flex-wrap js-variant-group" data-group-id="@groupNumber"> 301 @foreach (var option in group.Options) 302 { 303 string active = variantId.Contains(option.Id) ? "active" : ""; 304 305 if (!string.IsNullOrEmpty(option.Color)) 306 { 307 string contrastColor = GetContrastColor(option.Color); 308 <button type="button" class="btn colorbox rounded-circle d-inline-block variant-option border js-variant-option @active" style="background-color: @option.Color; --variantoption-check-color: @contrastColor" onclick="swift.VariantSelector.OptionClick(event)" data-variant-id="@option.Id" id="@(product.Id)_@(option.Id)[email protected]"></button> 309 } 310 else if (!string.IsNullOrEmpty(option.Color) && !string.IsNullOrEmpty(option.Image.Value)) 311 { 312 <button type="button" class="btn p-0 d-inline-block variant-option border js-variant-option @active" onclick="swift.VariantSelector.OptionClick(event)" data-variant-id="@option.Id"> 313 <img src="/Admin/Public/GetImage.ashx?image=@(option.Image.Value)&width=42&Format=WebP&Quality=70" /> 314 </button> 315 } 316 else 317 { 318 <button type="button" class="btn btn-secondary d-inline-block variant-option js-variant-option @active" onclick="swift.VariantSelector.OptionClick(event)" data-variant-id="@option.Id"> 319 @option.Name 320 </button> 321 } 322 } 323 </div> 324 325 groupNumber++; 326 } 327 </form> 328 } 329 330 <div class="d-flex flex-row flex-nowrap gap-2"> 331 @if (!hideAddToCart) 332 { 333 <form method="post" action="@url" class="flex-fill"> 334 <input type="hidden" name="redirect" value="false" /> 335 <input type="hidden" name="ProductId" value="@product.Id" /> 336 <input type="hidden" name="ProductName" value="@product.Name" /> 337 <input type="hidden" name="ProductPrice" value="@product.Price.Price" /> 338 <input type="hidden" name="ProductCurrency" value="@product.Price.CurrencyCode" /> 339 <input type="hidden" name="ProductReferer" value="product_details_info"> 340 <input type="hidden" name="cartcmd" value="add" /> 341 342 @if (!string.IsNullOrEmpty(product.VariantId)) 343 { 344 <input type="hidden" name="VariantId" value="@product.VariantId" /> 345 } 346 @if (!Model.Item.GetBoolean("QuantitySelector")) 347 { 348 <input id="[email protected]" name="Quantity" value="@valueQty" type="hidden"> 349 <button type="button" onclick="swift.Cart.Update(event)" class="btn btn-primary w-100 js-add-to-cart-button @disableAddToCart" @disableAddToCart title="@Translate("Add to cart")" id="AddToCartButton@(product.Id)[email protected]">@Translate("Add to cart")</button> 350 } else { 351 <div class="input-group input-primary-button-group js-input-group d-flex flex-row flex-nowrap"> 352 <label for="Quantity_@(product.Id)" class="visually-hidden">@Translate("Quantity")</label> 353 <input id="[email protected]" name="Quantity" value="@valueQty" step="@stepQty" @minQty class="form-control" style="max-width: 96px; min-width:64px;" type="number" onkeydown="swift.Cart.UpdateOnEnterKey(event)"> 354 <button type="button" onclick="swift.Cart.Update(event)" class="btn btn-primary flex-fill js-add-to-cart-button @disableAddToCart" @disableAddToCart title="@Translate("Add to cart")" id="AddToCartButton@(product.Id)[email protected]">@Translate("Add to cart")</button> 355 </div> 356 357 if (stepQty != "1") 358 { 359 <div class="invalid-feedback d-none"> 360 @Translate("Please select a quantity that is dividable by") @stepQty 361 </div> 362 } 363 } 364 </form> 365 if (!anonymousUser && !hideFavoritesSelector) 366 { 367 @RenderPartial("Components/ToggleFavorite.cshtml", product, favoriteParameters) 368 } 369 } 370 else if (!anonymousUser && !hideFavoritesSelector && !isDiscontinued) 371 { 372 <div class="flex-fill" id="[email protected]"> 373 @Translate("Add to favorites") @RenderPartial("Components/ToggleFavorite.cshtml", product, favoriteParameters) 374 </div> 375 } 376 377 @if (isDiscontinued && product.ReplacementProduct != null) { 378 List<ProductInfoViewModel> replacementProductList = new List<ProductInfoViewModel>(); 379 replacementProductList.Add(product.ReplacementProduct); 380 var replacementProduct = replacementProductList.GetProducts().FirstOrDefault(); 381 382 if ((product.DiscontinuedAction == 0 || product.DiscontinuedAction == 1) && product?.ReplacementProduct.ProductId != null) { 383 var parms = new Dictionary<string, object>(); 384 parms.Add("cssClass", "d-block mw-100 mh-100 m-auto"); 385 parms.Add("fullwidth", true); 386 parms.Add("columns", Model.GridRowColumnCount); 387 388 string imagePath = replacementProduct?.DefaultImage?.Value != null ? replacementProduct.DefaultImage.Value : ""; 389 390 string link = "Default.aspx?ID=" + GetPageIdByNavigationTag("Shop"); 391 link += $"&GroupID={replacementProduct.PrimaryOrDefaultGroup.Id}"; 392 link += $"&ProductID={replacementProduct.Id}"; 393 link += !string.IsNullOrEmpty(replacementProduct.VariantId) ? $"&VariantID={replacementProduct.VariantId}" : ""; 394 link = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(link); 395 396 <div class="w-100"> 397 <div class="fw-bold w-100">@Translate("Sorry, this product is no longer available").</div> 398 <div>@Translate("We recommend this replacement product instead"):</div> 399 400 <a href="@link"> 401 @RenderPartial("Components/Image.cshtml", new FileViewModel { Path = imagePath }, parms) 402 </a> 403 404 <div>@replacementProduct.Name</div> 405 406 @if (!hidePrice) 407 { 408 <div class="mb-3"> 409 <div class="h4" itemprop="offers" itemscope itemtype="https://schema.org/Offer"> 410 @if (showPricesWithVat == "false" && !neverShowVat) 411 { 412 if (isLazyLoadingForProductInfoEnabled) 413 { 414 <span itemprop="price" content="" class="d-none"></span> 415 <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.PriceBeforeDiscount.Price"></span> 416 } 417 else 418 { 419 string beforePrice = product.PriceBeforeDiscount.PriceWithoutVatFormatted; 420 421 <span itemprop="price" content="@product.Price.PriceWithoutVat" class="d-none"></span> 422 if (product.Price.Price != product.PriceBeforeDiscount.Price) 423 { 424 <span class="text-decoration-line-through opacity-75 me-3">@beforePrice</span> 425 } 426 } 427 } 428 else 429 { 430 if (isLazyLoadingForProductInfoEnabled) 431 { 432 <span itemprop="price" content="" class="d-none"></span> 433 <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.PriceBeforeDiscount.Price"></span> 434 } 435 else 436 { 437 string beforePrice = product.PriceBeforeDiscount.PriceFormatted; 438 439 <span itemprop="price" content="@product.Price.Price" class="d-none"></span> 440 if (product.Price.Price != product.PriceBeforeDiscount.Price) 441 { 442 <span class="text-decoration-line-through opacity-75 me-3">@beforePrice</span> 443 } 444 } 445 } 446 447 @if (showPricesWithVat == "false" && !neverShowVat) 448 { 449 if (isLazyLoadingForProductInfoEnabled) 450 { 451 <span class="text-price js-text-price"><div class="spinner-border" role="status"></div></span> 452 } 453 else 454 { 455 string price = product.Price.PriceWithoutVatFormatted; 456 if (product?.VariantInfo?.VariantInfo != null) 457 { 458 priceMin = product?.VariantInfo?.PriceMin?.PriceWithoutVatFormatted != null ? product.VariantInfo.PriceMin.PriceWithoutVatFormatted : ""; 459 priceMax = product?.VariantInfo?.PriceMax?.PriceWithoutVatFormatted != null ? product.VariantInfo.PriceMax.PriceWithoutVatFormatted : ""; 460 } 461 if (priceMin != priceMax) 462 { 463 price = priceMin + " - " + priceMax; 464 } 465 <span class="text-price">@price</span> 466 } 467 } 468 else 469 { 470 if (isLazyLoadingForProductInfoEnabled) 471 { 472 <span class="text-price js-text-price"><div class="spinner-border" role="status"></div></span> 473 } 474 else 475 { 476 string price = product.Price.PriceFormatted; 477 if (product?.VariantInfo?.VariantInfo != null) 478 { 479 priceMin = product?.VariantInfo?.PriceMin?.PriceFormatted != null ? product.VariantInfo.PriceMin.PriceFormatted : ""; 480 priceMax = product?.VariantInfo?.PriceMax?.PriceFormatted != null ? product.VariantInfo.PriceMax.PriceFormatted : ""; 481 } 482 if (priceMin != priceMax) 483 { 484 price = priceMin + " - " + priceMax; 485 } 486 <span class="text-price">@price</span> 487 } 488 } 489 </div> 490 491 @if (showPricesWithVat == "false" && !neverShowVat) 492 { 493 if (isLazyLoadingForProductInfoEnabled) 494 { 495 <small class="opacity-85 fst-normal js-text-price-with-vat d-none" data-suffix="@Translate("Incl. VAT")"></small> 496 } 497 else 498 { 499 string price = product.Price.PriceWithVatFormatted; 500 if (product?.VariantInfo?.VariantInfo != null) 501 { 502 priceMin = product?.VariantInfo?.PriceMin?.PriceWithVatFormatted != null ? product.VariantInfo.PriceMin.PriceWithVatFormatted : ""; 503 priceMax = product?.VariantInfo?.PriceMax?.PriceWithVatFormatted != null ? product.VariantInfo.PriceMax.PriceWithVatFormatted : ""; 504 } 505 if (priceMin != priceMax) 506 { 507 price = priceMin + " - " + priceMax; 508 } 509 <small class="opacity-85 fst-normal">@price @Translate("Incl. VAT")</small> 510 } 511 } 512 </div> 513 } 514 515 <a href="@link" class="btn btn-primary w-100">@Translate("Go to the replacement")</a> 516 </div> 517 } 518 } 519 </div> 520 </div> 521 @if (!hideStock) 522 { 523 if (!IsNeverOutOfStock) 524 { 525 if (isLazyLoadingForProductInfoEnabled) 526 { 527 string hideStockState = string.IsNullOrEmpty(product.VariantId) && product.VariantInfo.VariantInfo != null ? "d-none" : ""; 528 <div class="js-product @liveInfoClass" data-product-id="@product.Id"> 529 <div class="mt-3 js-stock-state spinner-border @hideStockState"> 530 @if (!Model.Item.GetBoolean("HideInventory")) 531 { 532 <div class="small text-success d-none" data-show-if="LiveProductInfo.product.StockLevel > 0"> 533 <span class="js-text-stock"></span> 534 @Translate("Products available in stock") 535 </div> 536 } 537 else 538 { 539 <div class="small text-success d-none" data-show-if="LiveProductInfo.product.StockLevel > 0">@Translate("Available in stock")</div> 540 } 541 <div class="small text-danger d-none" data-show-if="LiveProductInfo.product.StockLevel <= 0">@Translate("Out of Stock")</div> 542 543 <div class="d-none" data-show-if="LiveProductInfo.product.ExpectedDelivery != null && new Date(LiveProductInfo.product.ExpectedDelivery) > new Date()"> 544 <span>@Translate("Expected back in stock:")</span> 545 <span class="js-text-expected-delivery"></span> 546 </div> 547 </div> 548 </div> 549 } 550 else 551 { 552 <div class="mt-3 js-stock-state"> 553 554 @if (product.StockLevel > 0) 555 { 556 if (!Model.Item.GetBoolean("HideInventory")) 557 { 558 <div class="small text-success">@product.StockLevel @Translate("Products available in stock")</div> 559 } 560 else 561 { 562 <div class="small text-success">@Translate("Available in stock")</div> 563 } 564 } 565 566 else 567 { 568 <div class="small text-danger">@Translate("Out of Stock")</div> 569 } 570 571 @if (hasExpectedDelivery) 572 { 573 <div> 574 <span>@Translate("Expected back in stock:")</span> 575 <span>@expectedDeliveryDate</span> 576 </div> 577 } 578 579 </div> 580 } 581 } 582 } 583 </div> 584 585 @helper RenderField(FieldValueViewModel field) 586 { 587 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 588 bool noValues = false; 589 590 if (!string.IsNullOrEmpty(fieldValue)) 591 { 592 if (field.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 593 { 594 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 595 noValues = values.Count > 0 ? false : true; 596 } 597 } 598 599 if (!string.IsNullOrEmpty(fieldValue) && noValues == false) 600 { 601 <dt class="g-col-12 g-col-sm-4 g-col-lg-12 fw-bold m-0">@field.Name</dt> 602 <dd class="g-col-12 g-col-sm-8 g-col-lg-12 mb-3"> 603 @RenderFieldValue(field) 604 </dd> 605 } 606 } 607 608 @helper RenderFieldValue(FieldValueViewModel field) 609 { 610 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 611 612 fieldValue = fieldValue == "False" ? Translate("No") : fieldValue; 613 fieldValue = fieldValue == "True" ? Translate("Yes") : fieldValue; 614 615 bool isColor = false; 616 617 if (field.Value.GetType() == typeof(System.Collections.Generic.List<Dynamicweb.Ecommerce.ProductCatalog.FieldOptionValueViewModel>)) 618 { 619 int valueCount = 0; 620 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 621 int totalValues = values.Count; 622 623 foreach (FieldOptionValueViewModel option in values) 624 { 625 if (option.Value.Substring(0, 1) == "#") 626 { 627 isColor = true; 628 } 629 630 if (!isColor) 631 { 632 @option.Name 633 } 634 else 635 { 636 <span class="colorbox-sm" style="background-color: @option.Value" title="@option.Value"></span> 637 } 638 639 if (valueCount != totalValues && valueCount < (totalValues - 1)) 640 { 641 if (isColor) 642 { 643 <text> </text> 644 } 645 else 646 { 647 <text>, </text> 648 } 649 } 650 valueCount++; 651 } 652 } 653 else 654 { 655 if (fieldValue.Substring(0, 1) == "#") 656 { 657 isColor = true; 658 } 659 660 if (!isColor) 661 { 662 @fieldValue 663 } 664 else 665 { 666 <span class="colorbox-sm" style="background-color: @fieldValue" title="@fieldValue"></span> 667 } 668 } 669 } 670

Description du produit

Display rempli de la gamma Squitos avec contenu:
12x Squitos01
10x SQSpray
6x T.BabyFriend
6x T.Mousticlick

 SQSpray:

Le spray SQ est un répulsif à insectes dont vous avez besoin pour protéger toute votre famille en protection sûre !

LA FORMULE

  • 0% DEET
  • ingrédient actif : 20% IR3535 (via Merck - Made in BE)
  • IR3535® : molécule inspirée de la nature qui fournit une substance respectueuse de la peau avec une sécurité élevée sans affecter les insectes eux-mêmes (les tient à distance)
  • soutenu par des études scientifiques 
     

LES AVANTAGES

  • efficace grâce à une protection 8h
  • environnemental : à base d'eau, sans danger pour l'homme - l'animal - l'environnement
  • excellente toxicologie : non toxique pour les organismes aquatiques tels que les poissons ou les algues et ne s'accumule pas dans l'environnement
  • insectes : contre les moustiques et les tiques

LA CIBLE

  • à partir d’1 an
  • convient également aux femmes enceintes

 

SQUITOS Autocollants

Autocollants lemon eucalyptus citronella, en particulier pour les enfants et les petits (0+)

Propriétés:

  • 24 autocollants dans une boîte pratique avec 6 animaux mignons différents 
  • garder l'emballage ouvert dans la boîte pour maintenir le bon fonctionnement des autocollants

Composition: ingrédients 100% naturels, ne contient pas de deet, combinaison de citronnelle et d'eucalyptus, huiles essentielles diluées (pas de danger si l'autocollant entre en contact avec la bouche ou les yeux) - contrairement à un spray, l'odeur de l'autocollant ne s'évapore pas et est donc très durable

Usage: - des autocollants d'animaux joyeux à coller sur les vêtements, le lit ou le buggy (visibles ou non visibles). Ne laisse aucune trace sur les vêtements.


 BABYFRIEND:

Dispositif anti-moustique écologique avec veilleuse basé sur des vibrations ultrasoniques, sans produits chimiques.

Description: appareil électronique progressif qui vous protège discrètement sans répandre d'odeurs désagréables ou de substances toxiques. Indication: pour éloigner les moustiques (bébés / enfants / adultes).

Caractéristiques:

  • éloigne les moustiques grâce à des signaux ultrasonores inaudibles
  • diffuse un large spectre de sons ultrasoniques inaudibles aux humains
  • 22 à 28KHz pour éviter l'accoutumance des moustiques ne répandez aucune substance dans l'air
  • la solution la plus écologique contre les moustiques
  • vous n'avez pas besoin d'aérer la pièce avant d'entrer
  • ami idéal pour les bébés et les enfants, grâce à la veilleuse relaxante et réconfortante
  • vous pouvez le laisser brûler pendant la journée et la nuit

Utilisation: branchez Babyfriend dans la prise de la pièce que vous souhaitez protéger contre les moustiques.

  • pour une meilleure diffusion des ultrasons, allumez l'appareil par précaution avant la tombée de la nuit
  • faible consommation d'énergie: en 150 heures, Babyfriend ne consomme pas plus d'une lampe à incandescence de 60 W en 10 minutes
  • dans les pièces de plus de 15 m², nous recommandons l'utilisation de 2 appareils en même temps, également pour les pièces avec tapis, revêtements muraux en tissu ou rideaux épais car ils peuvent absorber une partie des signaux ultrasonores
  • garantit que la prise n'est pas couverte par des meubles ou des rideaux
  • peut être utilisé lorsque la fenêtre est ouverte, mais l'appareil ne doit pas être dans le «courant d'air» et doit être orienté vers l'intérieur
  • si vous avez plusieurs prises, utilisez la plus haute de la pièce

Études: Une étude indépendante et comparative avec d'autres dispositifs anti-moustiques montre que Babyfriend est 30 000x plus puissant que le concurrent le plus proche.

 

Caractéristiques techniques: 110 / 230V Garantie de 2 ans. 

 

 MOUSTICLICK

Un appareil médical à base de piézoélectricité, sans produits chimiques

Indication : adoucit les démangeaisons, réduit les gonflements des piqûres moustiques (bébés >6mois / enfants / adultes)

 

Caractéristiques: -

Les protéines de la salive sont considérées comme étrangères à notre système immunitaire et notre corps réagit immédiatement, l'histamine est libérée, lutte contre les matières étrangères, il apparaît un gonflement et/ou des démangeaisons. Mousti-Click aidera à décomposer la molécule étrangère avec une petite charge d’électrique.

Usage:

  • rapide, facile et sûr
  • pour de meilleurs résultats, il est recommandé de l’utiliser dès que possible après la piqûre du moustique
  • si l’envie de gratter revient, répétez l’action
  • placez le point de l'appareil avec précision sur la piqûre
  • une légère sensation de picotements se fera sentir à chaque clic (une charge statique minuscule qui se libère lorsque le bouton est pressé)
  • appuyez sur le bouton autant de fois que nécessaire
  • adultes: appliquer de 5 à 10 clics pour réduire l’envie/le gonflement de gratter la zone de la morsure 
  • enfants (plus de 6 mois) : demi dose ne pas utiliser en cas de maladie cardiaque, épilepsie, implant, femmes enceintes, sur les plaies et les muqueuses

 

Données techniques:

  • dure de vie longue: 25 000 clics (jusqu’à 4 000 piqûres) 
  • aucune batterie requise 
  • écologique, sans produits chimiques

Effets secondaires: aucun, testé cliniquement

 

Nettoyage: essuyez la surface de l'appareil avec un chiffon doux et humide

 

Caractéristiques

CNK
9611-872
Qu'y a-t-il dans la boite
1x display, 12x Squitos01,10x SQSpray, 6x T.BabyFriend, 6x T.Mousticlick
Politique de commande
Lot for lot
By clicking 'Accept All' you consent that we may collect information about you for various purposes, including: Functionality, Statistics and Marketing