DETAIL7752
DETAIL7785
DETAIL3705
DETAIL3704
DETAIL3706
DETAIL3707
DETAIL3708
DETAIL3711
DETAIL3712
DETAIL3713
DETAIL3714
DETAIL3715
DETAIL7849
DETAIL7753
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_22a774a1daee49869dee8a017f5ac0ab.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

Omschrijving:           

Voel je vrij om overal naar toe te gaan met de PIPA next. Licht genoeg om te dragen tijdens het winkelen - slechts 2,8 kg*! Veelzijdig genoeg om in een taxi of in je eigen auto te gebruiken dankzij de mogelijkheid om met de autogordel of met de base te installeren.

Hij is i-Size goedgekeurd met alle details voor een luxe reis zoals een verstelbare hoofdsteun, meegroeiende gordels, een droomdekentje en superieure zijwaartse bescherming op de base met ingebouwde vleugels die automatisch uitklappen als de stoel wordt geïnstalleerd.

Alles waar je van droomt om je leven met een baby makkelijker te maken.

*Zonder zonnekap of verkleinkussen.

Indicatie:                   

-          Automatische zijwaartse bescherming.

-          3-puntsgordel.

-          ISOFIX en gekleurde installatie indicatoren.

-          Extra installatie indicator.

-          Stalen stabiliteitspoot.

-          Indicator stabiliteitspoot.

-          Kreukelzone.

-          Certificaat voor gebruik in een vliegtuig.

-          Voldoet aan de Europese norm: ECE R129.  

-          Fabriek is ISO 14001, ISO 9001 en OHSAS 18001 gecertificeerd.

Eigenschappen:

-          Super comfortabel voor je baby. Premium I-size bescherming voor je gemoedsrust.

-          Lichtgewicht, beschermend en draagbaar. Slechts 2.8kg*.

-          Driepuntsgordel die met je kind meegroeit is met één hand te verstellen.

-          Vijf-seconden, True lock™ base installatie zorgt voor snelle, eenvoudige en veilige installatie, met behulp van de ISOFIX punten in de auto.

-          Bescherming tegen zijwaartse botsingen voor ultieme veiligheid.

-          Kreukelzone in de stabiliteitspoot absorbeert en minimaliseert de krachten op je baby.

-          Gepatenteerd Tailor tech™ geheugenschuim in de hoofdsteun zorgt voor perfecte pasvorm.

-          Uitneembare inlegjes zorgen voor perfecte pasvorm. Als de baby groter wordt, kunnen ze eenvoudig worden verwijderd.

-          Zevenvoudig,  met één hand verstelbare hoofdsteun.

-          Droomdeken wordt geluidloos bevestigd met magneten.

Samenstelling:

-          Droomdeken.

-          Gordelgeleider.

-          Stalen stabiliteitspoot.

-          Kreukelzone.

Structuur:

-          Geweven polyester vezels creëren een subtiele textuur, terwijl de Merino wol en TENCEL™*lyocell stof een natuurlijk en warm gevoel geven.

-          Merino wol en TENCEL™**lyocell vezels zijn zacht, nemen vocht op en zijn milieuvriendelijk.

Gebruik:

-          Uitsluitend achterwaarts: 40-83cm, geboorte tot 13 kg.

-          De gordelgeleider op de stoel geeft je een keuze qua installatiemethode. Zet hem vast met de gordel in de taxi of installeer hem op de base in je gezinsauto. PIPA next is altijd klaar voor vertrek en heeft zelfs een certificaat voor gebruik in een vliegtuig.

-          Wanneer de PIPA next op de base* wordt gezet, klappen de zijwaartse beschermvleugels automatisch uit, en voegen zo een extra laag veiligheid toe. Met True lock™ installatie kan de base in je auto worden vastgezet, met 13 ISOFIX posities voor de beste pasvorm. Gekleurde indicatoren bevestigen als de installatie correct is - geen ruimte voor twijfel.

-          Te gebruiken in combinatie met alle Nuna kinderwagens.

Specificaties

Kleur
Granite
Afneembare hoes
JA
Draagvermogen (Kg)
13
Harnas in hoogte verstelbaar
JA
Leeftijd
0m+
Met Isofix te gebruiken
JA
Met verkleinkussen
JA
Rijrichting
Tegen de rijrichting
Type harnas
3-punts-gordel
Verstelbaar zitje
JA
Wasbaar
JA
Video
https://www.youtube.com/@NunaGlobal/videos
By clicking 'Accept All' you consent that we may collect information about you for various purposes, including: Functionality, Statistics and Marketing