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_bcd8f29bb71e47599c414c62e0bd85fb.Execute() in D:\dynamicweb.net\Solutions\Dynamicweb\bomedys.cloud.dynamicweb-cms.com\files\Templates\Designs\Swift\Paragraph\Swift_ProductDetailsInfo.cshtml:line 399 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 @* Product stock state *@ 153 double? currentStockLevel = product.StockLevel; 154 155 156 string stockStateLabel = !string.IsNullOrEmpty(product.StockStatus) ? product.StockStatus : ""; 157 158 string stockStateCss = currentStockLevel > 0 ? "text-success" : "text-danger"; 159 string stockStateIconCss = currentStockLevel > 0 ? "bg-success" : "bg-danger"; 160 } 161 162 @if (!string.IsNullOrWhiteSpace(googleAnalyticsMeasurementID) && allowTracking) 163 { 164 <script> 165 gtag("event", "view_item", { 166 currency: "@product.Price.CurrencyCode", 167 value: @product.Price.Price, 168 items: [ 169 { 170 item_id: "@product.Number", 171 item_name: "@product.Name", 172 currency: "@product.Price.CurrencyCode", 173 price: @product.Price.Price 174 } 175 ] 176 }); 177 </script> 178 } 179 180 <div class="h-100 @(contentPadding) @(theme) [email protected]()" @productInfoFeed> 181 <div class="d-flex flex-column gap-4 js-product" data-product-id="@product.Id"> 182 @if (showBadges) { 183 <div class="swift_badge-collection"> 184 @RenderPartial("Components/EcommerceBadge.cshtml", product, badgeParms) 185 </div> 186 } 187 188 <div class="d-flex flex-column gap-2"> 189 <h1 class="@titleFontSize m-0" itemprop="name">@product.Name</h1> 190 @if (!Model.Item.GetBoolean("HideProductNumber")) 191 { 192 @RenderPartial("Paragraph/Swift_ProductNumber.cshtml", Model) 193 } 194 </div> 195 196 @if (!hidePrice && !isDiscontinued) 197 { 198 @RenderPartial("Paragraph/Swift_ProductPrice.cshtml", Model, priceParms) 199 200 if (isLazyLoadingForProductInfoEnabled) 201 { 202 <div class="product-prices-container @liveInfoClass d-none" data-show-if="LiveProductInfo.product.Prices.length > 0"> 203 @if (quantityPricesLayout == "list") 204 { 205 <div class="mt-3 product-prices"> 206 <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> 207 </div> 208 } 209 else if (quantityPricesLayout == "table") 210 { 211 <div class="grid"> 212 <table class="table table-sm mt-3 g-col-12 g-col-lg-6"> 213 <thead> 214 <tr> 215 <td>@Translate("QTY")</td> 216 <td>@Translate("pr. PCS")</td> 217 </tr> 218 </thead> 219 <tbody class="product-prices"> 220 <tr class="product-prices-template"> 221 <td class="js-text-price-quantity"></td> 222 <td class="js-text-price-price"></td> 223 </tr> 224 </tbody> 225 </table> 226 </div> 227 } 228 </div> 229 } 230 else 231 { 232 if (product.Prices.Count > 0) 233 { 234 <div> 235 @if (quantityPricesLayout == "list") 236 { 237 <div class="mt-3"> 238 @foreach (PriceListViewModel quantityPrice in product.Prices) 239 { 240 string quantityLabel = Translate("PCS"); 241 string quantityPriceSuffix = quantityPrice.Quantity > 1 ? Translate("pr. PCS") : ""; 242 243 <small class="d-block opacity-75"><span>@quantityPrice.Quantity @quantityLabel</span> - <span class="fw-bold">@quantityPrice.Price.PriceFormatted @quantityPriceSuffix</span></small> 244 } 245 </div> 246 } 247 else if (quantityPricesLayout == "table") 248 { 249 <div class="grid"> 250 <table class="table table-sm mt-3 g-col-12 g-col-lg-6"> 251 <thead> 252 <tr> 253 <td>@Translate("QTY")</td> 254 <td>@Translate("pr. PCS")</td> 255 </tr> 256 </thead> 257 <tbody> 258 @foreach (PriceListViewModel quantityPrice in product.Prices) 259 { 260 <tr> 261 <td>@quantityPrice.Quantity</td> 262 <td>@quantityPrice.Price.PriceFormatted</td> 263 </tr> 264 } 265 </tbody> 266 </table> 267 </div> 268 } 269 </div> 270 } 271 } 272 } 273 274 @RenderPartial("Paragraph/Swift_ProductShortDescription.cshtml", Model) 275 276 @if (mainFeatures.Count > 0) 277 { 278 foreach (CategoryFieldViewModel mainFeatureGroup in mainFeatures) 279 { 280 <dl class="grid gap-0"> 281 @foreach (var field in mainFeatureGroup.Fields) 282 { 283 @RenderField(field.Value) 284 } 285 </dl> 286 } 287 } 288 289 @if (product.VariantInfo.VariantInfo != null && !Model.Item.GetBoolean("HideVariantSelector")) 290 { 291 int groupNumber = 1; 292 293 string baseUrl = $"Default.aspx?ID={GetPageIdByNavigationTag("Shop")}&GroupID={product.PrimaryOrDefaultGroup.Id}&ProductID={product.Id}"; 294 string variantUrl = ""; 295 if (!string.IsNullOrEmpty(product.VariantId)) 296 { 297 variantUrl = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl($"Default.aspx?ID={GetPageIdByNavigationTag("Shop")}&GroupID={product.PrimaryOrDefaultGroup.Id}&ProductID={product.Id}&VariantID={product.VariantId}"); 298 } 299 300 <form class="js-variant-selector" data-combinations="@string.Join(",", product.VariantCombinations())" data-base-url="@baseUrl" data-friendly-url="@variantUrl"> 301 <input type="hidden" name="variantid" /> 302 303 @foreach (var variantGroup in product.VariantGroups()) 304 { 305 VariantGroupViewModel group = variantGroup; 306 307 <h3 class="h6">@group.Name</h3> 308 <div class="d-flex gap-2 flex-wrap js-variant-group" data-group-id="@groupNumber"> 309 @foreach (var option in group.Options) 310 { 311 string active = variantId.Contains(option.Id) ? "active" : ""; 312 313 if (!string.IsNullOrEmpty(option.Color)) 314 { 315 string contrastColor = GetContrastColor(option.Color); 316 <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> 317 } 318 else if (!string.IsNullOrEmpty(option.Color) && !string.IsNullOrEmpty(option.Image.Value)) 319 { 320 <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"> 321 <img src="/Admin/Public/GetImage.ashx?image=@(option.Image.Value)&width=42&Format=WebP&Quality=70" /> 322 </button> 323 } 324 else 325 { 326 <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"> 327 @option.Name 328 </button> 329 } 330 } 331 </div> 332 333 groupNumber++; 334 } 335 </form> 336 } 337 338 <div class="d-flex flex-row flex-nowrap gap-2"> 339 @if (!hideAddToCart) 340 { 341 <form method="post" action="@url" class="flex-fill"> 342 <input type="hidden" name="redirect" value="false" /> 343 <input type="hidden" name="ProductId" value="@product.Id" /> 344 <input type="hidden" name="ProductName" value="@product.Name" /> 345 <input type="hidden" name="ProductPrice" value="@product.Price.Price" /> 346 <input type="hidden" name="ProductCurrency" value="@product.Price.CurrencyCode" /> 347 <input type="hidden" name="ProductReferer" value="product_details_info"> 348 <input type="hidden" name="cartcmd" value="add" /> 349 350 @if (!string.IsNullOrEmpty(product.VariantId)) 351 { 352 <input type="hidden" name="VariantId" value="@product.VariantId" /> 353 } 354 @if (!Model.Item.GetBoolean("QuantitySelector")) 355 { 356 <input id="[email protected]" name="Quantity" value="@valueQty" type="hidden"> 357 <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> 358 } else { 359 <div class="input-group input-primary-button-group js-input-group d-flex flex-row flex-nowrap"> 360 <label for="Quantity_@(product.Id)" class="visually-hidden">@Translate("Quantity")</label> 361 <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)"> 362 <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> 363 </div> 364 365 if (stepQty != "1") 366 { 367 <div class="invalid-feedback d-none"> 368 @Translate("Please select a quantity that is dividable by") @stepQty 369 </div> 370 } 371 } 372 </form> 373 if (!anonymousUser && !hideFavoritesSelector) 374 { 375 @RenderPartial("Components/ToggleFavorite.cshtml", product, favoriteParameters) 376 } 377 } 378 else if (!anonymousUser && !hideFavoritesSelector && !isDiscontinued) 379 { 380 <div class="flex-fill" id="[email protected]"> 381 @Translate("Add to favorites") @RenderPartial("Components/ToggleFavorite.cshtml", product, favoriteParameters) 382 </div> 383 } 384 385 @if (isDiscontinued && product.ReplacementProduct != null) { 386 List<ProductInfoViewModel> replacementProductList = new List<ProductInfoViewModel>(); 387 replacementProductList.Add(product.ReplacementProduct); 388 var replacementProduct = replacementProductList.GetProducts().FirstOrDefault(); 389 390 if ((product.DiscontinuedAction == 0 || product.DiscontinuedAction == 1) && product?.ReplacementProduct.ProductId != null) { 391 var parms = new Dictionary<string, object>(); 392 parms.Add("cssClass", "d-block mw-100 mh-100 m-auto"); 393 parms.Add("fullwidth", true); 394 parms.Add("columns", Model.GridRowColumnCount); 395 396 string imagePath = replacementProduct?.DefaultImage?.Value != null ? replacementProduct.DefaultImage.Value : ""; 397 398 string link = "Default.aspx?ID=" + GetPageIdByNavigationTag("Shop"); 399 link += $"&GroupID={replacementProduct.PrimaryOrDefaultGroup.Id}"; 400 link += $"&ProductID={replacementProduct.Id}"; 401 link += !string.IsNullOrEmpty(replacementProduct.VariantId) ? $"&VariantID={replacementProduct.VariantId}" : ""; 402 link = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl(link); 403 404 <div class="w-100"> 405 <div class="fw-bold w-100">@Translate("Sorry, this product is no longer available").</div> 406 <div>@Translate("We recommend this replacement product instead"):</div> 407 408 <a href="@link"> 409 @RenderPartial("Components/Image.cshtml", new FileViewModel { Path = imagePath }, parms) 410 </a> 411 412 <div>@replacementProduct.Name</div> 413 414 @if (!hidePrice) 415 { 416 <div class="mb-3"> 417 <div class="h4" itemprop="offers" itemscope itemtype="https://schema.org/Offer"> 418 @if (showPricesWithVat == "false" && !neverShowVat) 419 { 420 if (isLazyLoadingForProductInfoEnabled) 421 { 422 <span itemprop="price" content="" class="d-none"></span> 423 <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> 424 } 425 else 426 { 427 string beforePrice = product.PriceBeforeDiscount.PriceWithoutVatFormatted; 428 429 <span itemprop="price" content="@product.Price.PriceWithoutVat" class="d-none"></span> 430 if (product.Price.Price != product.PriceBeforeDiscount.Price) 431 { 432 <span class="text-decoration-line-through opacity-75 me-3">@beforePrice</span> 433 } 434 } 435 } 436 else 437 { 438 if (isLazyLoadingForProductInfoEnabled) 439 { 440 <span itemprop="price" content="" class="d-none"></span> 441 <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> 442 } 443 else 444 { 445 string beforePrice = product.PriceBeforeDiscount.PriceFormatted; 446 447 <span itemprop="price" content="@product.Price.Price" class="d-none"></span> 448 if (product.Price.Price != product.PriceBeforeDiscount.Price) 449 { 450 <span class="text-decoration-line-through opacity-75 me-3">@beforePrice</span> 451 } 452 } 453 } 454 455 @if (showPricesWithVat == "false" && !neverShowVat) 456 { 457 if (isLazyLoadingForProductInfoEnabled) 458 { 459 <span class="text-price js-text-price"><div class="spinner-border" role="status"></div></span> 460 } 461 else 462 { 463 string price = product.Price.PriceWithoutVatFormatted; 464 if (product?.VariantInfo?.VariantInfo != null) 465 { 466 priceMin = product?.VariantInfo?.PriceMin?.PriceWithoutVatFormatted != null ? product.VariantInfo.PriceMin.PriceWithoutVatFormatted : ""; 467 priceMax = product?.VariantInfo?.PriceMax?.PriceWithoutVatFormatted != null ? product.VariantInfo.PriceMax.PriceWithoutVatFormatted : ""; 468 } 469 if (priceMin != priceMax) 470 { 471 price = priceMin + " - " + priceMax; 472 } 473 <span class="text-price">@price</span> 474 } 475 } 476 else 477 { 478 if (isLazyLoadingForProductInfoEnabled) 479 { 480 <span class="text-price js-text-price"><div class="spinner-border" role="status"></div></span> 481 } 482 else 483 { 484 string price = product.Price.PriceFormatted; 485 if (product?.VariantInfo?.VariantInfo != null) 486 { 487 priceMin = product?.VariantInfo?.PriceMin?.PriceFormatted != null ? product.VariantInfo.PriceMin.PriceFormatted : ""; 488 priceMax = product?.VariantInfo?.PriceMax?.PriceFormatted != null ? product.VariantInfo.PriceMax.PriceFormatted : ""; 489 } 490 if (priceMin != priceMax) 491 { 492 price = priceMin + " - " + priceMax; 493 } 494 <span class="text-price">@price</span> 495 } 496 } 497 </div> 498 499 @if (showPricesWithVat == "false" && !neverShowVat) 500 { 501 if (isLazyLoadingForProductInfoEnabled) 502 { 503 <small class="opacity-85 fst-normal js-text-price-with-vat d-none" data-suffix="@Translate("Incl. VAT")"></small> 504 } 505 else 506 { 507 string price = product.Price.PriceWithVatFormatted; 508 if (product?.VariantInfo?.VariantInfo != null) 509 { 510 priceMin = product?.VariantInfo?.PriceMin?.PriceWithVatFormatted != null ? product.VariantInfo.PriceMin.PriceWithVatFormatted : ""; 511 priceMax = product?.VariantInfo?.PriceMax?.PriceWithVatFormatted != null ? product.VariantInfo.PriceMax.PriceWithVatFormatted : ""; 512 } 513 if (priceMin != priceMax) 514 { 515 price = priceMin + " - " + priceMax; 516 } 517 <small class="opacity-85 fst-normal">@price @Translate("Incl. VAT")</small> 518 } 519 } 520 </div> 521 } 522 523 <a href="@link" class="btn btn-primary w-100">@Translate("Go to the replacement")</a> 524 </div> 525 } 526 } 527 </div> 528 </div> 529 @if (!hideStock) 530 { 531 <div class="js-stock-state [email protected]()"> 532 <div class="small"> 533 <span class="@stockStateCss">@stockStateLabel </span> 534 </div> 535 </div> 536 } 537 </div> 538 539 @helper RenderField(FieldValueViewModel field) 540 { 541 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 542 bool noValues = false; 543 544 if (!string.IsNullOrEmpty(fieldValue)) 545 { 546 if (field.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 547 { 548 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 549 noValues = values.Count > 0 ? false : true; 550 } 551 } 552 553 if (!string.IsNullOrEmpty(fieldValue) && noValues == false) 554 { 555 <dt class="g-col-12 g-col-sm-4 g-col-lg-12 fw-bold m-0">@field.Name</dt> 556 <dd class="g-col-12 g-col-sm-8 g-col-lg-12 mb-3"> 557 @RenderFieldValue(field) 558 </dd> 559 } 560 } 561 562 @helper RenderFieldValue(FieldValueViewModel field) 563 { 564 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 565 566 fieldValue = fieldValue == "False" ? Translate("No") : fieldValue; 567 fieldValue = fieldValue == "True" ? Translate("Yes") : fieldValue; 568 569 bool isColor = false; 570 571 if (field.Value.GetType() == typeof(System.Collections.Generic.List<Dynamicweb.Ecommerce.ProductCatalog.FieldOptionValueViewModel>)) 572 { 573 int valueCount = 0; 574 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 575 int totalValues = values.Count; 576 577 foreach (FieldOptionValueViewModel option in values) 578 { 579 if (option.Value.Substring(0, 1) == "#") 580 { 581 isColor = true; 582 } 583 584 if (!isColor) 585 { 586 @option.Name 587 } 588 else 589 { 590 <span class="colorbox-sm" style="background-color: @option.Value" title="@option.Value"></span> 591 } 592 593 if (valueCount != totalValues && valueCount < (totalValues - 1)) 594 { 595 if (isColor) 596 { 597 <text> </text> 598 } 599 else 600 { 601 <text>, </text> 602 } 603 } 604 valueCount++; 605 } 606 } 607 else 608 { 609 if (fieldValue.Substring(0, 1) == "#") 610 { 611 isColor = true; 612 } 613 614 if (!isColor) 615 { 616 @fieldValue 617 } 618 else 619 { 620 <span class="colorbox-sm" style="background-color: @fieldValue" title="@fieldValue"></span> 621 } 622 } 623 } 624
Product beschrijving
Ervaar de Nuna SWIV. De ultieme moderne kinderwagen met 360° zwenkwielen en een gestroomlijnd, met koolstofvezel versterkt aluminium frame.
Het dagelijkse ritme van ouderschap pulseert met ontelbare momenten van beweging. Sommige alledaags en sommige magisch. En aan het eind van de dag komen ze samen om een levendige soundtrack van het leven te creëren.
Stel je een choreografie van beweging voor, georkestreerd door de 360 graden draaiende wielen van je kinderwagen.
Terwijl je over drukke trottoirs rijdt en door drukke ruimtes weeft, glijden de wielen van de SWIV moeiteloos in richtingen die je je nooit had kunnen voorstellen voor een kinderwagen. Een simpele druk op de knop laat ze pirouetten en draaien als een betoverende dans.
Met elke wielomwenteling creëert de SWIV harmonie met de beweging van jouw dag en stelt je in staat om de spontaniteit van het ouderschap met vertrouwen en gratie te omarmen - door elke bocht te nemen zoals hij komt en in gloednieuwe richtingen te draaien.
Eigenschappen:
- 360° draaien op alle wielen: Ontsluit grenzeloze verkenningstochten met de innovatieve zijwaartse beweging van de SWIV die wordt aangedreven door de vier 360° zwenkwielen die direct in nieuwe richtingen draaien zonder de beperkingen van traditionele kinderwagenbesturing.
- Met koolstofvezel versterkt aluminium frame: De unieke framesamenstelling van de SWIV combineert de ongeëvenaarde kracht en het vederlichte karakter van koolstofvezel met de duurzame veerkracht van aluminium, waardoor hij gelijke tred kan houden met de eisen van het ouderschap.
- Alle extra's: Met veel aandacht voor elk detail wordt de SWIV geleverd met elk accessoire dat je nodig hebt voor onderweg, zoals een bekerhouder, een regenhoes, een draagtas en een verstelbare kantelstokadapter om klaar te zijn voor het reissysteem.
- Handgreep met flair: Ontdek ongeëvenaarde aanpassingsmogelijkheden met de in hoogte verstelbare, in 3 standen draaibare handgreep van de SWIV, die comfort en gemak garandeert voor gebruikers van verschillende lengtes.
- Soepel wandelen: Innovatieve veerveringstechnologie is ingebouwd in het SWIV zitje om soepele ritten te maken door energie te absorberen die veroorzaakt wordt door oneffen terrein zoals kinderkopjes, trottoirs en alles wat daartussen zit.
Eigenschappen:
- Droomdoek™
- Met koolstofvezel versterkt aluminium frame
- Lichtgewicht en sterk
- 360° rotatie op alle wielen
- Directe pivotnavigatie
- Zijwaartse beweging
- In hoogte verstelbare 3-positie zwenkbare handgreep
- Klaar voor reissysteem
- Zitting in beide richtingen
- Zitting met verende stoel
- Grote opbergmand met ritsvak
- 10 kg mandgewicht
- Waterafstotende UPF 50+ kap
- Kiekeboe-venster
- Uitklapbare oogschaduw
- Zak met rits aan de achterkant van de zitting
- Inclusief: bekerhouder, regenhoes, draagtas & reissysteemadapter
- Draaibare en afneembare armbar
- 3 tot 5-punts gordel zonder schroefdraad
- Rugleuning met 3 standen
- Bijna vlakke rugleuning
- MagneTech secure snap™ gesp
- Merino wol inzetstuk
- Gemakkelijk met 1 hand te vouwen
- Staat op zichzelf wanneer opgevouwen
- Naar voren of naar achteren vouwen
- In 2 posities verstelbare kuitsteun
- Op alle wielen geveerd
- Met EVA-schuim gevulde banden
- Luxe kunstlederen armbar en pushbar
- 1-touch rem
- All-season stoel
Productgegevens gebruik:
- Met de knop activeer je 360° rotatie op alle 4 de wielen en kom je in gloednieuwe richtingen
- Houd de knop op de duwstang ingedrukt om de zijwaartse beweging en directe zwenknavigatie te activeren. Laat de knop los om te deactiveren en terug te keren naar de traditionele wandelmodus.
- In it for the long haul het verstrekken van innovatieve wandelingen vanaf de geboorte tot 22 kg
- Het zitje is naar beide kanten gericht en kan plat worden gevouwen, ongeacht de richting waarin de baby kijkt
- Afneembare en draaibare armbar voor gemakkelijker in- en uitstappen
- Perfect te combineren met alle Nuna baby-autostoeltjes en de LYTL™ en CARI™ volgende reiswieg
- Klaar voor het reissysteem: bevestig eenvoudig een Nuna baby-autostoeltje met de meegeleverde paaladapter
- Gemakkelijk met 1 hand op te vouwen en staat op zichzelf wanneer opgevouwen
Veiligheid:
- Zelfgeleidende MagneTech secure snap™ gespen vergrendelen automatisch op hun plaats
- 3 tot 5-punts gordel zonder schroefdraad maakt het gemakkelijk om ze vast te maken
- Eenvoudig 1-touch remsysteem op de achterwielen
Comfort:
- De in de zitting ingebouwde veringstechnologie zorgt voor soepele ritten door energie te absorberen die wordt veroorzaakt door ongelijk terrein
- Rugleuning met 1 hand biedt 3 posities voor onderweg, waaronder een bijna vlakke optie voor comfort voor pasgeborenen
- De UPF 50+ waterafstotende kap is uitschuifbaar en heeft een uitklapbare oogschelp en kiekeboe-venster
- Het zitje voor alle seizoenen houdt baby warm in de winter en kan in de zomer eenvoudig worden omgevormd tot een netzitje
- In 2 posities verstelbare kuitsteun voor groeiende benen
Duurzame voetsteun biedt een rustplaats voor vermoeide voeten - De vering op alle wielen en de duurzame, met EVA-schuim gevulde banden zijn klaar voor elk terrein
Premuim details:
- Kijkvenster van gaas om baby in de gaten te houden
- Met koolstofvezel versterkt aluminium frame biedt ongeëvenaarde sterkte en duurzaamheid met behoud van een opmerkelijk lichtgewicht profiel
- Het unieke weefpatroon van koolstofvezel op het frame creëert een visueel opvallend effect met een moderne esthetiek
- In hoogte verstelbare 3-positie draaibare handgreep voor comfortabel wandelen, ongeacht je lengte
- Gemakkelijk verwijderbare Merino wol en TENCEL™ lyocell insert zorgt voor ultrazacht comfort (TENCEL™ is een handelsmerk van Lenzing AG)
- In de grote mand met een inhoud van 10 kg past alles wat je nodig hebt voor onderweg
- Zakje met rits op achterkant zitting (en een geheime in de opbergmand) voor waardevolle spullen
- Luxe met kunstleer geaccentueerde pushbar en armbar voegen stijl toe aan je wandelingen
- Inclusief alle extra's: bekerhouder, regenhoes, draagtas en reissysteemadapter
Testcertificering: EN 1888-2:2018+A1:2022
Aanbevolen gebruik:
- Geboorte tot 22 kg
Afmetingen open: L 94 x B 54 x H 103 cm
Afmetingen gevouwen: L 30 x B 54 x H 78 cm
Gewicht: 9,5 kg (zonder armbar, inzetstuk of regenhoes)
Wielmaat:
- Voorkant 16,5 cm
- Achter: 20 cm
Materialen:
- Koolstofvezel
- Aluminium
- Kunststof
- Polyester
- Merinoswol
- Rubber
- Karton gemaakt vangerecycled materiaal
Onderhoudsinstructies:
Gemakkelijk schoon te maken
Wassen in koud water, fijnwasprogramma
Niet bleken
Niet in de droger
Druppeldrogen
Niet strijken
Niet chemisch reinigen
Specificaties
- Draagvermogen (Kg)
- 22
- Inclusief regenhoes
- JA
- Inclusief veiligheidsbar
- JA
- Materiaal frame
- Aluminium
- Met zonnekap
- JA
- Video
- https://www.youtube.com/@NunaGlobal/videos
- Wasbaar
- JA
- Wat zit er in de doos
- Kinderwagen, Draagtas, Verstelbare kantelpaaladapter, Bekerhouder, Regenhoes
- Bestel beleid
- Order
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.