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_3be0b3fa0a4347b59a8d6ec7272c32af.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

Product beschrijving

Filled display of the Squitos range containing:
12x Squitos01
10x SQSpray
6x T.BabyFriend
6x T.Mousticlick

SQSpray

SQ spray is the insect repellent you need to protect your entire family safely!

FORMULA

  • 0% DEET
  • active ingredient: 20% IR3535 (via Merck - Made in BE)
  • IR3535®: nature-inspired molecule that provides a skin-friendly substance with high safety without affecting the insects themselves (keeps them at a distance)
  • with substantiated scientific studies

ADVANTAGES

  • efficient thanks to 8h protection
  • environment: water-based: safe for humans - animals - environment
  • excellent toxicological: is not toxic to aquatic organisms such as fish or algae and does not accumulate in the environment.
  • insects: against mosquitoes & ticks

TARGET GROUP

  • from 1 year
  • also suitable for pregnant women

SQUITOS Stickers

  • Lemon eucalyptus citronella stickers especially for children & the littlest ones (0+)

Properties:

  • 24 stickers in a handy tin with 6 different fun animals
  • store opened packaging in tin to maintain good functioning of stickers

Composition: 100% natural ingredients, contains 0% deet, combination of citronella and eucalyptus, diluted essential oils (no danger if sticker comes into contact with mouth or eyes) - unlike a spray, the smell of the sticker does not evaporate and is therefore extra effective for a long time

Use: cheerful animal stickers that you stick on clothing, bed or buggy (visible or not visible). Leaves no traces on clothing.

BABYFRIEND:

Ecological anti-mosquito device with night light based on ultrasonic vibrations, without chemicals.

Description: advanced electronic device that protects you discreetly without spreading unpleasant odors or toxic substances. Indication: to keep mosquitoes at bay (babies/children/adults).

Features:

  • keeps mosquitoes at bay with inaudible ultrasonic signals
  • spreads a broad spectrum of ultrasonic sounds that are inaudible to humans
  • 22 to 28KHz to prevent mosquitoes from getting used to it
    does not spread any substances in the air
  • the most environmentally friendly solution in the fight against mosquitoes.
  • you do not need to ventilate the room before coming in
    ideal friend for babies and children, thanks to the relaxing and reassuring night light
  • you can leave it on during the day and at night

Use: plug Babyfriend into the socket of the room you want to protect against mosquitoes.

  • for better ultrasonic diffusion, switch on the device as a precaution before nightfall
  • low energy consumption: at 150 hours, Babyfriend consumes no more than a 60W light bulb in 10 minutes
  • in rooms larger than 15m², we recommend using 2 devices at the same time, also for rooms with carpets, fabric wall
  • coverings or heavy curtains because they can absorb part of the ultrasonic signals
  • ensures that the socket is not covered by furniture or curtains
  • can be used when the window is open, but the device must not be in a "draft" and must be facing inwards
  • if you have multiple sockets, use the highest one in the room

Studies: independent, comparative study with other anti-mosquito devices shows that Babyfriend is 30,000x more powerful than the nearest competitor.

Technical specifications: 110/230V 2-year warranty.

MOUSTICLICK

Medical device based on piezoelectricity generation, without chemicals

Indication: soothes itching, reduces swelling in mosquito bites (babies from 6 months / kids / adults)

Properties:

Proteins from mosquito saliva are considered foreign to our immune system, causing our body to react immediately, histamine is released, fights the foreign substance and swelling and/or itching occurs. Mousti-Click will help break down the foreign molecule with a small electrical charge.

Use:

  • fast, easy and safe
  • for the best results it is recommended to use it as soon as possible after the mosquito bite.
  • if the urge to scratch returns, repeat the action if necessary
  • place the tip of the device precisely on the bite
  • a slight tingling sensation will be felt with each click (small static charge released by piezoelectricity)
  • press the button as many times as necessary
    adults: 5 to 10 clicks to reduce itching/swelling
  • children (from 6 months): half dose do not use in case of heart disease, epilepsy, implantation, pregnant women, on ulcers and open wounds

Technical characteristics: -

  • long life: 25,000 clicks for approximately 4,000 mosquito bites
  • no batteries required
  • ecological, without chemicals

Side effects: none, clinically tested

Cleaning: wipe the surface of the device with a soft, damp cloth

Specificaties

CNK nr.
9611-872
What's in the box
1x display, 12x Squitos01,10x SQSpray, 6x T.BabyFriend, 6x T.Mousticlick
Order policy
Lot for lot
By clicking 'Accept All' you consent that we may collect information about you for various purposes, including: Functionality, Statistics and Marketing