DETAIL16436
DETAIL16527
DETAIL16528
DETAIL16529
DETAIL16530
DETAIL16531
DETAIL16532
DETAIL16533
DETAIL16534
DETAIL16535
DETAIL16536
DETAIL16537
DETAIL16538
DETAIL16434
DETAIL16431
DETAIL16432
DETAIL16433
DETAIL16437
DETAIL16439
DETAIL16438
DETAIL16440
DETAIL16407
DETAIL13481
DETAIL16435
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_060a05f305854baea268f631aedb0664.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

Vous ne pouvez pas contrôler votre destin, mais maintenant vous pouvez être prêt pour l’aventure qui vous attend.

Choisissez entre deux canopies interchangeables pour offrir à bébé un confort personnalisé. Notre système innovant MagneTech Secure Snap™ permet de sortir votre enfant aussi facilement et rapidement que de le mettre dedans. Et le Custom Dual Suspension™ offre la meilleure balade pour bébé et pour vous. Avec son siège quatre saisons, son élégant système de rangement et la possibilité d’en faire une poussette double, voire pour jumeaux, la poussette DEMI grow est parée à toutes les éventualités !

CARACTÉRISTIQUES & SPECS

  • Red Dot Product Design Winner: Best of the Best 2018
  • Conçue pour passer d’une poussette simple à une poussette double ou pour jumeaux: 33 modes différents
  • Facile à plier, enlevez le siège pour passer en mode nacelle ou siège auto
  • Tient debout toute seule une fois pliée
  • La technologie de suspension progressive assure une promenade confortable 
  • Le système ajustable Dual Suspension™ permet de suivre facilement le mouvement
  • Roues dures remplies de mousse tout terrain
  • Roues avant pivotantes blocables 
  • Les garde-boue protégeant de la saleté et des projections
  • Frein centralisé one-touch utra simple bloquant les roues arrières
  • Guidon effet cuir surpiqué ajustable en hauteur 
  • L'assise se dirige dans les deux directions et se plie facilement quelle que soit la direction
  • Panneaux de ventilation intégrés
  • Appui-tête amovible
  • Assise quatre-saisons garde bébé au chaud en hiver et maintient bébé au frais en été
  • MagneTech Secure Snap™, la fermeture magnétique du harnais qui se verrouille automatiquement - Trois positions d'inclinaison, toutes ajustables d'une main - La poussette comprend deux canopies facilement amovibles et interchangeables pour personnaliser le confort de bébé
  • Aire Protect Canopy™ protège bébé du soleil et des moustiques tout en permettant à l'air de circuler à travers les panneaux latéraux en maille. Déployez le canopy UPF 50+ pour protéger du soleil, et abaissez le filet en maille aérée pour une protection intégrale et plus d’intimité
  • Canopy classique : une protection intégrale, UPF 50+, un canopy déperlant avec une petite fenêtre, Dream drape™ et pare-soleil rabattable
  • Le pare-soleil Dream drape™ se rabat doucement et se fixe silencieusement grâce aux aimants pour ne pas interrompre le sommeil de bébé
  • Repose-jambe ajustable d'une main
  • Panier shopping amovible
  • Sa structure robuste et sa texture en tweed offre un look élégant et durable. Le mélange de laine mérinos et de fibre lyocell de marque TENCEL™* crée un toucher naturel. *TENCEL™ est une marque déposée de Lenzing AG
  • L'habillage pluie protège votre enfants des éléments lors de vos balades

CARACTÉRISTIQUES DU PRODUIT UTILISATION RECOMMANDÉE :

de 6 mois à 15 kg Avec nacelle : de la naissance à 9 kg Conforme à la norme européenne : EN 1888 Certification de l'usine ISO 14001 ISO 9001 OHSAS 18001

Dimensions : L98 L62 H 112 cm

Pliée : L 55 L62 H 89 cm

POIDS : 13,80 kg (Poids sans siège d'hiver, ni capote, ni arceau de sécurité)

 

Caractéristiques

Housse amovible
OUI
Compatibilité siège auto
Pipa Urbn
Capacite de transport
15
Harnais réglable en hauteur
OUI
Comprend un adaptateur pour siège auto
OUI
Y compris panier d'achat
OUI
Comprend une housse de pluie
OUI
Comprend une barre de sécurité
OUI
Matériau du cadre
Aluminium
Avec suspension
OUI (avant et arrière)
Avec chancelière
OUI
Avec pare-soleil
OUI
Direction du voyage
Avec/contre le sens de la marche
Type de harnais
ceinture 5 points
Siège réglable
OUI
Lavable
OUI
Couleur
Caviar
Qu'y a-t-il dans la boite
1 pousette
Âge
6m+
Video
https://www.youtube.com/@NunaGlobal/videos

GPSR EU-Regulation

EU Authorised Representative - Address
Van der Valk Boumanweg 178 C, 2352 JD Leiedorp, Nederland
EU Authorised Representative - Email
[email protected]
Manufacturer information - Address
Van der Valk Boumanweg 178 C, 2352 JD Leiedorp, Nederland
Manufacturer information - Trade name
Nuna International B.V.
By clicking 'Accept All' you consent that we may collect information about you for various purposes, including: Functionality, Statistics and Marketing