0
Din indkøbskurv

Opdaterer kurv

stk. a

-
+

Din kurv i alt (ex. fragt)

Handel videre

Gå til kassen
VISA/DK VISA/DK VISA/DK VISA/DK VISA/DK
Find forhandler

,

Tlf.

Se alle
Error executing template "Designs/Mobler2018/eCom/Product/Product.cshtml"
System.NullReferenceException: Object reference not set to an instance of an object.
   at CompiledRazorTemplates.Dynamic.RazorEngine_4ccc5b57b4234850b0b1442dd314e734.Execute() in D:\dynamicweb.net\Solutions\mobler.LIVE\Files\Templates\Designs\Mobler2018\eCom\Product\Product.cshtml:line 991
   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.b__0(TextWriter writer)
   at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter)
   at Dynamicweb.Rendering.Template.RenderRazorTemplate()

1 @using System.Web 2 @using Mobler.Website.CustomModules.MoblerHelpers 3 @using System.Text.RegularExpressions 4 @using CampaignModule.Models 5 @using Group = Dynamicweb.Ecommerce.Products.Group 6 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 7 8 9 @{ 10 string shopname = MoblerHelpers.GetShopName(); 11 string SelectPlaceholder = Translate("ShopSelectPlaceholder", "Indtast by, postnummer eller adresse"); 12 var shopInfo = MoblerHelpers.ShopInfo(); 13 int ShopPageId = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetInt("ShopPageId"); 14 var AllShops = Firstweb.Custom.CustomCode.Frontend.Helpers.Shops.GetAllShops(ShopPageId); 15 int AjaxCartPageId = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetInt("AjaxCartPageId"); 16 int CustomersAlsoSawPageId = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetInt("CustomersAlsoSawPageId"); 17 string CartPage = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetString("CartPage"); 18 string VariantsEndpoint = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetString("VariantsUrl"); 19 string VariantDetailsEndpoint = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetString("VariantDetailsUrl"); 20 string BlackFridayTheme = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetString("BlackFridayTheme"); 21 string ProductID = GetString("Ecom:Product.ID"); 22 string GroupID = Firstweb.Custom.CustomCode.Frontend.Helpers.EcomGroups.GetProductDefaultShopGroupID(ProductID); //GetString("Ecom:Product.PrimaryOrFirstGroupID"); 23 string DefaultVariantID = GetString("Ecom:Product.DefaultVariantComboID"); 24 string ProductImage = MoblerHelpers.GetProductListImage(ProductID, DefaultVariantID); 25 string ProductName = GetString("Ecom:Product.Name"); 26 string ProductNumber = GetString("Ecom:Product.Number"); 27 string ProductCatalogLink = !String.IsNullOrEmpty(GetString("Ecom:Product:Field.ProductCatelog.Value.Clean")) ? GetString("Ecom:Product:Field.ProductCatelog.Value.Clean") : ""; 28 string VariantId = GetString("Ecom:Product.VariantID"); 29 string ShortDescription = GetString("Ecom:Product.ShortDescription"); 30 string LongDescription = GetString("Ecom:Product.LongDescription").Replace("||", "<br/>"); 31 string CurrentVariantName = GetString("Ecom:Product.SelectedVariantComboName"); 32 var FaqQuestions = MoblerHelpers.GetProductFAQs(ProductID, GroupID); 33 34 35 Mobler.Website.CustomCode.Frontend.PayeverHelper payeverHelper = new Mobler.Website.CustomCode.Frontend.PayeverHelper(); 36 Mobler.Website.CustomCode.Models.PayeverWidget PayeverWidget = payeverHelper.GetPayeverWidgetInformation(); 37 38 string MetaDescription = GetString("Ecom:Product.MetaDescription"); 39 40 if (string.IsNullOrEmpty(MetaDescription)) 41 { 42 MetaDescription = Mobler.Website.CustomCode.Frontend.Helpers.Text.GetFirstLine(LongDescription.Replace("<br/>", " ")); 43 } 44 else 45 { 46 MetaDescription = ""; //Meta data description bliver sat af DW, hvis dette felt er udfyldt, så vi skal ikke opsætte noget. 47 } 48 49 50 var RelatedBlogs = Firstweb.Custom.CustomCode.Frontend.Helpers.Blogs.GetBlogsRelatedToProduct(ProductID); 51 bool NewItem = GetBoolean("Ecom:Product:Field.NewItem"); 52 DateTime NewItemExpiryDate = GetDate( "Ecom:Product:Field.NewItemExpiryDate" ); 53 bool LowPrice = GetBoolean("Ecom:Product:Field.Splash3"); 54 55 56 Mobler.Website.CustomCode.Frontend.ProductsDisplayVariant productsDisplayVariant = Mobler.Website.CustomCode.Frontend.ProductsDisplayVariant.Instance(); 57 58 bool ForSale = !GetBoolean("Ecom:Product:Field.NotForSaleOnline"); 59 60 var MainProdNr = string.Empty; 61 var VariantNr = string.Empty; 62 string FirstImage = ""; 63 if (!string.IsNullOrWhiteSpace(ProductNumber)) 64 { 65 string[] MainProdSplit = ProductNumber.Split('_'); 66 67 68 69 if (MainProdSplit.Length > 1) 70 { 71 MainProdNr = MainProdSplit[0]; 72 VariantNr = MainProdSplit[1]; 73 } 74 else 75 { 76 MainProdNr = ProductNumber; 77 } 78 } 79 var Images = MoblerHelpers.GetProductImages(GetString("Ecom:Product.ID"), VariantId); 80 bool First = true; 81 bool FirstIndicator = true; 82 int IndicatorIncrementer = 0; 83 string ProductLink = GetString("Ecom:Product.Link.Clean"); 84 85 double ActualPrice = GetDouble("Ecom:Product.Price.Price"); 86 double spar = 0; 87 double price = 0; 88 double normalPrice = 0; 89 90 string priceFormatted = ""; 91 string sparFormatted = ""; 92 string normalPriceFormatted = ""; 93 94 string campaignColor = ""; 95 string campaignText = ""; 96 string campaignDate = ""; 97 98 99 string campaignDateStart = ""; 100 string campaignDateEnd = ""; 101 102 103 bool CampaignActiveOnProduct = GetBoolean("CampaignModule:Product.CampaignActiveOnProduct"); 104 if (!CampaignActiveOnProduct) 105 { 106 price = ActualPrice; 107 priceFormatted = MoblerHelpers.formatPrice(price); 108 } 109 else 110 { 111 normalPrice = GetDouble("CampaignModule:Product.CampaignProduct.NormalPrice"); 112 normalPriceFormatted = GetString("CampaignModule:Product.CampaignProduct.NormalPrice.FormattedRetail"); 113 114 price = GetDouble("CampaignModule:Product.CampaignProduct.CampaignPrice"); 115 priceFormatted = GetString("CampaignModule:Product.CampaignProduct.CampaignPrice.FormattedRetail"); 116 117 spar = GetDouble("CampaignModule:Product.CampaignProduct.DiscountAmount"); 118 sparFormatted = GetString("CampaignModule:Product.CampaignProduct.DiscountAmount.FormattedRetail"); 119 120 campaignColor = GetString("CampaignModule:Product.Campaign.Color"); 121 campaignText = GetString("CampaignModule:Product.Campaign.Text"); 122 123 campaignDateStart = GetString("CampaignModule:Product.CampaignProduct.Campaign.Start"); 124 campaignDateEnd = GetString("CampaignModule:Product.CampaignProduct.Campaign.End"); 125 } 126 127 128 string DataLayerPrice = ActualPrice.ToString().Replace(".", "").Replace(",", "."); 129 System.Web.HttpContext.Current.Items["OverrideOgTags"] = true; 130 string OgImage = "https://mobler.dk" + Images.FirstOrDefault(); 131 132 string TrimmedTeaser = Firstweb.Custom.CustomCode.Frontend.Helpers.JSFormatting.TrimLinebreaks(ShortDescription); 133 string TrimmedName = Firstweb.Custom.CustomCode.Frontend.Helpers.JSFormatting.TrimLinebreaks(ProductName); 134 135 var ParentGroups = Firstweb.Custom.CustomCode.Frontend.Helpers.EcomGroups.getBreadCrumbGroupList(GroupID, true); 136 var DataLayerParentGroup = ParentGroups.Last().Name; 137 List<string> DataLayerParentGroupStrings = ParentGroups.Select(group => group.Name).ToList(); 138 string DataLayerParentGroups = string.Join(" > ", DataLayerParentGroupStrings); 139 140 string ShowOnPageUrl = ""; 141 string GetCartEndpoint = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetString("GetCartJson"); 142 143 string QuickDeliveryColor = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetString("QuickDeliveryColor"); 144 string QuickDeliveryDescription = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetString("QuickDeliveryDescription"); 145 string NormalDeliveryDescription = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetString("NormalDeliveryDescription"); 146 string BrandName = GetString("Ecom:Product:Field.Maerkevarer.Value.Clean"); 147 string DeliveryTime = Translate("DeliveryTime." + BrandName, "Gns. leveringstid 3-12 dage"); 148 bool HideDelivery = DeliveryTime == "Skjul"; 149 string DeliveryColor = "#00AB5D"; 150 bool QuickDelivery = GetBoolean("Ecom:Product:Field.QuickDelivery.Value.Clean"); 151 string CustomDelivery = GetString("Ecom:Product:Field.CustomDeliveryTime.Value.Clean"); 152 if (QuickDelivery) 153 { 154 DeliveryColor = QuickDeliveryColor; 155 DeliveryTime = Translate("DeliveryTime.QuickDelivery", "Ekstra hurtig levering"); 156 } 157 else if (!String.IsNullOrEmpty(CustomDelivery)) 158 { 159 DeliveryTime = CustomDelivery; 160 } 161 string DeliveryFontWeightModifier = QuickDelivery ? "font-weight-bold" : ""; 162 bool DisplayAverageDeliveryTime = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetBoolean("DisplayAverageDeliveryTime"); 163 164 double CostPrice = GetDouble("Ecom:Product:Field.FirstwebCostPrice.Value.Raw"); 165 string DailyPriceBackgroundColor = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetString("AktuelDagsprisBackgroundColor"); 166 string DailyPriceTextColor = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetString("AktuelDagsprisTextColor"); 167 string EAN = GetString("Ecom:Product:Field.FirstEan.Value"); 168 169 string productionDescription = GetString("Ecom:Product:Field.FirstwebProductionDescription"); 170 171 172 Mobler.Website.CustomCode.RelewiseCustom.RelewiseCaller relewiseCaller = new Mobler.Website.CustomCode.RelewiseCustom.RelewiseCaller(); 173 relewiseCaller.TrackProductView(ProductID, VariantId); 174 175 } 176 177 178 @SnippetStart("ProductDetailsMeta") 179 @if (!string.IsNullOrEmpty(MetaDescription)) 180 { 181 <meta name="description" content="@MetaDescription" /> 182 } 183 @SnippetEnd("ProductDetailsMeta") 184 185 @SnippetStart("OgTags") 186 <meta property="og:type" content="product" /> 187 <meta property="og:description" content="@Regex.Replace(ShortDescription, "<.*?>", String.Empty)" /> 188 <meta property="og:image" content="@OgImage" /> 189 @SnippetEnd("OgTags") 190 191 @using System.Collections 192 @using Dynamicweb.Core 193 @using Dynamicweb.Ecommerce 194 @using Mobler.Website.CustomModules.MoblerHelpers 195 @using Dynamicweb.Ecommerce.Products 196 @using Dynamicweb.Ecommerce.Variants 197 @using Humanizer 198 @using Mobler.Website.CustomCode 199 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 200 201 @using Mobler.Website.CustomModules.MoblerHelpers 202 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 203 204 @helper RenderPricing(LoopItem product, bool hasVariants) 205 { 206 // Theming 207 string blackFridayTheme = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetString("BlackFridayTheme"); 208 209 // Pricing 210 DateTime newItemExpiryDate = product.GetDate( "Ecom:Product:Field.NewItemExpiryDate" ); 211 bool hasNewItemExpiryDate = newItemExpiryDate.Date > DateTime.Now.Date; 212 bool newItem = product.GetBoolean("Ecom:Product:Field.NewItem") && hasNewItemExpiryDate; 213 bool LowPrice = product.GetBoolean("Ecom:Product:Field.Splash3"); 214 double CostPrice = product.GetDouble("Ecom:Product:Field.FirstwebCostPrice.Value.Raw"); 215 string PriceSaving = product.GetString("Ecom:Product:Field.Spar.Value"); 216 double ActualPrice = product.GetDouble("Ecom:Product.Price.Price"); 217 218 // Initialize variables 219 double spar = 0; 220 double price = 0; 221 double normalPrice = 0; 222 223 string priceFormatted = ""; 224 string sparFormatted = ""; 225 string normalPriceFormatted = ""; 226 227 string campaignColor = ""; 228 string campaignText = ""; 229 string campaignDate = ""; 230 231 bool CampaignActiveOnProduct = product.GetBoolean("CampaignModule:Product.CampaignActiveOnProduct"); 232 if (!CampaignActiveOnProduct) 233 { 234 price = ActualPrice; 235 priceFormatted = MoblerHelpers.formatPrice(price); 236 } 237 else 238 { 239 normalPrice = product.GetDouble("CampaignModule:Product.CampaignProduct.NormalPrice"); 240 normalPriceFormatted = product.GetString("CampaignModule:Product.CampaignProduct.NormalPrice.FormattedRetail"); 241 242 price = product.GetDouble("CampaignModule:Product.CampaignProduct.CampaignPrice"); 243 priceFormatted = product.GetString("CampaignModule:Product.CampaignProduct.CampaignPrice.FormattedRetail"); 244 245 spar = product.GetDouble("CampaignModule:Product.CampaignProduct.DiscountAmount"); 246 sparFormatted = product.GetString("CampaignModule:Product.CampaignProduct.DiscountAmount.FormattedRetail"); 247 248 campaignColor = product.GetString("CampaignModule:Product.Campaign.Color"); 249 campaignText = product.GetString("CampaignModule:Product.Campaign.Text"); 250 } 251 252 // Set Splash Types 253 string splashType = ""; 254 if (campaignText == "KOMBI") 255 { 256 splashType = "combo"; 257 } 258 else if (CostPrice > 0) 259 { 260 splashType = "priceshape"; 261 } 262 else if (spar > 0) 263 { 264 splashType = "offer"; 265 } 266 else if (newItem) 267 { 268 splashType = "new"; 269 } 270 else if (LowPrice) 271 { 272 splashType = "low"; 273 } 274 275 <div> 276 <p class="product-item__price fs3 font-weight-bold"> 277 @if (hasVariants) 278 { 279 <span class="font-weight-semibold fs0 mr-2">@Translate("ProductPrice.From", "Fra")</span> 280 } 281 @priceFormatted 282 </p> 283 @if (splashType == "combo") 284 { 285 <div class="splash splash--on-top"> 286 <p class="m-0">@Translate("ProductCombinationOffer", "Sætpris")</p> 287 </div> 288 <div class="d-flex justify-content-between mb-2"> 289 <p class="color-subtle fs0 m-0 text-uppercase">@Translate("PriceBefore", "Før") @normalPriceFormatted</p> 290 <p class="splash fs0 text-uppercase m-0 px-2">@Translate("PriceSaving", "Spar") @sparFormatted</p> 291 </div> 292 } 293 else if (splashType == "priceshape") 294 { 295 string DailyPriceBackgroundColor = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetString("AktuelDagsprisBackgroundColor"); 296 string DailyPriceTextColor = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetString("AktuelDagsprisTextColor"); 297 298 <div class="splash splash--on-top price-shape" style="background-color: @DailyPriceBackgroundColor"> 299 <p class="m-0" style="color: @DailyPriceTextColor;">@Translate("ProductDailyPriceSplash", "Dagspris")</p> 300 </div> 301 } 302 else if (splashType == "offer") 303 { 304 if (blackFridayTheme == "True") 305 { 306 <div class="splash splash--on-top bf-bg-black bf-color-white"> 307 <p class="m-0">@Translate("ProductOffer", "Tilbud")</p> 308 </div> 309 } 310 else 311 { 312 <div class="splash splash--on-top p-1"> 313 <p class="m-0">@Translate("ProductOffer", "Tilbud")</p> 314 </div> 315 } 316 <div class="d-flex justify-content-between mb-2"> 317 <p class="color-subtle fs0 m-0 text-uppercase">@Translate("PriceBefore", "Før") @normalPriceFormatted</p> 318 <p class="splash fs0 m-0 text-uppercase px-2">@Translate("PriceSaving", "Spar") @sparFormatted</p> 319 </div> 320 } 321 else if (splashType == "new") 322 { 323 <div class="splash splash--on-top new-item"> 324 <p class="m-0">@Translate("ProductNew", "Nyhed")</p> 325 </div> 326 } 327 else if (splashType == "low") 328 { 329 <div class="splash splash--on-top low-price"> 330 <p class="m-0">@Translate("ProductLowPrice", "Fast lavpris")</p> 331 </div> 332 } 333 </div> 334 } 335 336 337 @helper RenderProduct(LoopItem product) 338 { 339 // Group Specific - Exclude Bed Accessories 340 bool excludeBedAccessories = product.GetBoolean("Ecom:Product.CategoryField.Senge.ExcludeBedAccessories.Value"); 341 342 // Product General Info 343 string productId = product.GetString("Ecom:Product.ID"); 344 string productName = product.GetString("Ecom:Product.Name"); 345 string productLink = product.GetString("Ecom:Product.Link.Clean"); 346 string shortDescription = product.GetString("Ecom:Product.ShortDescription"); 347 string languageId = product.GetString("Ecom:Product.LanguageID"); 348 349 // Variants 350 string defaultVariantId = product.GetString("Ecom:Product.DefaultVariantComboID"); 351 string variantId = product.GetString("Ecom:Product.VariantID"); 352 if (String.IsNullOrEmpty(variantId)) { 353 variantId = defaultVariantId; 354 } 355 if (!String.IsNullOrEmpty(variantId)) { 356 productLink = productLink + "&variantid=" + variantId; 357 } 358 359 // Product Images 360 List<string> images = MoblerHelpers.GetProductImages(productId, variantId); 361 string productImage = string.Format("/Admin/Public/GetImage.ashx?Image={0}&Width=280&height=220&Format=png&Crop=5&resolution=50", images.FirstOrDefault()); //MoblerHelpers.GetProductListImageWithMainImage(ProductID, ProductNumber); 362 363 // Product Dimensions 364 string productDepth = product.GetString("Ecom:Product:Field.dybdeint.Value.Clean"); 365 string productHeight = product.GetString("Ecom:Product:Field.hoejdeint.Value.Clean"); 366 string productWidth = product.GetString("Ecom:Product:Field.breddeint.Value.Clean"); 367 bool hasProductDepth = !string.IsNullOrWhiteSpace(productDepth) && productDepth != "0"; 368 bool hasProductHeight = !string.IsNullOrWhiteSpace(productHeight) && productHeight != "0"; 369 bool hasProductWidth = !string.IsNullOrWhiteSpace(productWidth) && productWidth != "0"; 370 371 // Campaign 372 string campaignDateStart = ""; 373 string campaignDateEnd = ""; 374 375 bool campaignActiveOnProduct = product.GetBoolean("CampaignModule:Product.CampaignActiveOnProduct"); 376 if (campaignActiveOnProduct) 377 { 378 campaignDateStart = product.GetString("CampaignModule:Product.CampaignProduct.Campaign.Start"); 379 campaignDateEnd = product.GetString("CampaignModule:Product.CampaignProduct.Campaign.End"); 380 } 381 382 bool hasCampaignDateStart = !string.IsNullOrWhiteSpace(campaignDateStart); 383 384 bool hasCampaignDateEnd = !string.IsNullOrWhiteSpace(campaignDateEnd); 385 string campaignText = ""; 386 if (hasCampaignDateStart && hasCampaignDateStart) 387 { 388 campaignText = $"{Translate("Campaign.BeforeDate.Text", "Gældende fra:")} {campaignDateStart} {Translate("Campaign.BeforeDate.Text2", "t.o.m.")} {campaignDateEnd}"; 389 } 390 391 <div class="col-12 col-sm-6 col-lg-3 product-item js-product-list-item"> 392 <div class="product-item__header"> 393 <a href="@productLink" class="product-item__image"> 394 <img class="js-product-image-@productId" src="@productImage" alt="@productName" loading="lazy"/> 395 </a> 396 @{ 397 int colorOptionsToShow = 4; 398 List<string> variantCombinationVariantIds = product.GetLoop("Co3VariantCombinations").Select(p => p.GetString("Ecom:VariantCombination.VariantID")).ToList(); 399 bool hasVariants = false; 400 } 401 @if (variantCombinationVariantIds.Count > 0) 402 { 403 hasVariants = true; 404 405 <div class="product-item__variants d-flex align-items-center"> 406 @foreach (LoopItem vg in product.GetLoop("VariantGroups")) 407 { 408 int variantOptionWithColorCount = 0; 409 410 @* Only show variants with hex colors *@ 411 foreach (LoopItem variantOption in vg.GetLoop("VariantAvailableOptions")) 412 { 413 <p class="unimportant-hidden">@variantOptionWithColorCount</p> 414 string variantOptionColor = variantOption.GetString("Ecom:VariantOption.ColorHex"); 415 416 // Get count of variants with color 417 if (variantOptionColor.Any()) 418 { 419 variantOptionWithColorCount++; 420 } 421 // Only show this specific amount of variants 422 if (variantOptionColor.Any() && variantOptionWithColorCount < colorOptionsToShow) 423 { 424 // Get variant option id, then compare with variant combinations, to get the link to the specific variant 425 string variantOptionId = variantOption.GetString("Ecom:VariantOption.ID"); 426 string variantIdWithColorOptionId = variantCombinationVariantIds.FirstOrDefault(vid => vid.Contains(variantOptionId)); 427 428 if (variantIdWithColorOptionId.IsNullOrEmpty() == false) 429 { 430 string variantLink = product.GetString("Ecom:Product.Link.Clean") + "&variantid=" + variantIdWithColorOptionId; 431 <a href="@variantLink" class="product-item__variant" style="background-color: @variantOptionColor;"></a> 432 } 433 } 434 else if (variantOptionColor.Any() && variantOptionWithColorCount == colorOptionsToShow) 435 { 436 <a href="@productLink" class="fs2 product-item__more-variants">+</a> 437 } 438 else 439 { 440 break; 441 } 442 } 443 } 444 @if (hasVariants) 445 { 446 <a href="@productLink" class="ml-4 fs-s"> 447 <i class="fas fa-pen mr-1 fs-2"></i> 448 @Translate("Ecom:Product.Pricing.Designer", "Design selv") 449 </a> 450 } 451 </div> 452 } 453 </div> 454 455 <div class="product-item__body"> 456 <a href="@productLink" class="product-item__title"> 457 <h3 class="fs0">@productName</h3> 458 </a> 459 <div class="product-item__description fs0 color-subtle">@shortDescription</div> 460 @if (hasProductDepth || hasProductHeight || hasProductWidth) 461 { 462 <p class="product-item__dimensions fs0 color-subtle"> 463 @if (hasProductDepth) 464 { 465 <span>D/L: @productDepth</span> 466 } 467 @if (hasProductHeight) 468 { 469 <span>H: @productHeight</span> 470 } 471 @if (hasProductWidth) 472 { 473 <span>B: @productWidth</span> 474 } 475 </p> 476 } 477 </div> 478 479 <div class="product-item__footer"> 480 @RenderPricing(product, hasVariants) 481 482 @if (excludeBedAccessories) 483 { 484 <p class="color-subtle fs-s m-0">@Translate("Ecom:Product.Pricing.Excludes.Beds", "Prisen er ekskl. ben og gavl.")</p> 485 } 486 @if (hasVariants) 487 { 488 <div class="variant-price-disclaimer color-subtle fs-s">@Translate("VariantPriceDisclaimer", "Prisen kan variere efter materialevalg")</div> 489 } 490 @if (hasCampaignDateStart && hasCampaignDateEnd) 491 { 492 <div class="product-item__campaign"> 493 <p class="color-subtle fs-s">@campaignText</p> 494 </div> 495 } 496 </div> 497 </div> 498 } 499 500 @using Mobler.Website.CustomModules.MoblerHelpers 501 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 502 503 @helper RenderBlogTeaser(Firstweb.Custom.CustomCode.Frontend.Helpers.Blog Blog) 504 { 505 string PageId = GetGlobalValue( "Global:Page.ID" ); 506 string CleanLink = Blog.Link.Replace("default.aspx?id", "Default.aspx?Id"); 507 <div class="col-12 col-md-4 px-0 px-md-3 mb-4"> 508 <a href="@CleanLink" class="blog d-block"> 509 <div class="image" style="background-image:url('@Blog.Image')"> 510 <img class="d-none" src="@Blog.Image" alt="Alternate Text" /> 511 </div> 512 <div class="text"> 513 <div class="positioning"> 514 <h4 class="col-10 col-md-9 px-2 pt-3 bg-white font-weight-bold text-center mx-auto">@Blog.Header</h4> 515 @if ( PageId != "7613" ) 516 { 517 <p class="text-center color-subtle">@Blog.Date</p> 518 } 519 <p class="text-center font-weight-bold m-0 color-primary">@Translate("BlogReadMore", "L&aelig;s mere her")</p> 520 </div> 521 </div> 522 </a> 523 </div> 524 } 525 526 @helper RenderLargeBlogTeaser(Firstweb.Custom.CustomCode.Frontend.Helpers.Blog Blog, string ImagePosition) 527 { 528 string ImageClass = ImagePosition == "Left" ? "" : "offset-md-4"; 529 string TextClass = ImagePosition == "Left" ? "" : "left"; 530 string Image = "/Admin/Public/GetImage.ashx?Image=" + Blog.Image + "&Height=400&Crop=0"; 531 string CleanLink = Blog.Link.Replace("default.aspx?id", "Default.aspx?Id"); 532 <div class="col-12 blog"> 533 <div class="row"> 534 <div class="col-12 col-md-8 px-0 px-md-3 @ImageClass"> 535 <div class="image-container" style="background-image:url('@Image')"> 536 <img class="img-fluid" src="@Image" alt="@Blog.Header" /> 537 </div> 538 </div> 539 <div class="col-12 col-md-6 text-container mb-5 mb-md-0 @TextClass"> 540 <div class="text bg-white p-3"> 541 <div> 542 <h4>@Blog.Header</h4> 543 @Blog.Teaser 544 </div> 545 <a class="font-weight-bold" href="@CleanLink">@Translate("BlogReadMore", "L&aelig;s mere her")</a> 546 </div> 547 </div> 548 </div> 549 </div> 550 } 551 552 @helper RenderLatestBlogsTeasers() 553 { 554 var LatestBlogs = Firstweb.Custom.CustomCode.Frontend.Helpers.Blogs.GetLatestBlogs(); 555 foreach (var Blog in LatestBlogs) 556 { 557 @RenderBlogTeaser(Blog) 558 } 559 } 560 561 562 <div class="container pt-3 d-none d-md-block"> 563 564 <div class="bread"> 565 <p class="color-subtle">@Translate("Breadcrumb.CurrentPage", "Her er du:")</p> 566 <p class="bread-item color-subtle"> 567 <a href="/"> 568 @Translate("Breadcrumb.Frontpage", "Forside") 569 </a> 570 </p> 571 @foreach (var Group in ParentGroups) 572 { 573 <p class="bread-item color-subtle"> 574 @if (Group == ParentGroups.First()) 575 { 576 @Group.Name 577 ShowOnPageUrl = Group.ProductGroupFieldValues.GetProductGroupFieldValue("FirstwebGroupPrimaryPage").Value.ToString(); 578 } 579 else 580 { 581 <a href="/@ShowOnPageUrl&GroupId=@Group.Id"> 582 @Group.Name 583 </a> 584 } 585 </p> 586 } 587 588 <p class="active color-subtle">@ProductName</p> 589 </div> 590 591 </div> 592 593 <div class="container mt-3 mb-5 product-details position-relative" data-bind="viewModel: 'ProductViewModel'"> 594 595 <div class="d-none" data-bind="setInitValue: { observable: CartPageId, value: '@AjaxCartPageId' }"></div> 596 <div class="d-none" data-bind="setInitValue: { observable: MiniCart, value: '.js-mini-cart-lines' }"></div> 597 <div class="d-none" data-bind="setInitValue: { observable: CartCount, value: '.js-cart-count' }"></div> 598 <div class="d-none" data-bind="setInitValue: { observable: CustomersAlsoSawLines, value: '.js-customers-also-saw-lines' }"></div> 599 <div class="d-none" data-bind="setInitValue: { observable: CustomersAlsoSawPage, value: '@CustomersAlsoSawPageId' }"></div> 600 <div class="d-none" data-bind="setInitValue: { observable: MainProductId, value: '@ProductID' }"></div> 601 <div class="d-none" data-bind="setInitValue: { observable: VariantsEndpoint, value: '@VariantsEndpoint' }"></div> 602 <div class="d-none" data-bind="setInitValue: { observable: VariantDetailsEndpoint, value: '@VariantDetailsEndpoint' }"></div> 603 <div class="d-none" data-bind="setInitValue: { observable: TeaserText, value: '@TrimmedTeaser' }"></div> 604 <div class="d-none" data-bind="setInitValue: { observable: ProductName, value: '@TrimmedName' }"></div> 605 <div class="d-none" data-bind="setInitValue: { observable: ProductNumber, value: '@ProductNumber' }"></div> 606 <div class="d-none" data-bind="setInitValue: { observable: VariantId, value: '@VariantId' }"></div> 607 <div class="d-none" data-bind="setInitValue: { observable: Price, value: '@priceFormatted' }"></div> 608 <div class="d-none js-update-cart" data-bind="setInitValue: { observable: CartEndpoint, value: '@GetCartEndpoint' }, click: GetCart"></div> 609 610 <div id="blueimp-gallery" class="blueimp-gallery blueimp-gallery-controls"> 611 <div class="slides"></div> 612 <h3 class="title"></h3> 613 <a class="prev">&#8249;</a> 614 <a class="next">&#8250;</a> 615 <a class="close">x</a> 616 <a class="play-pause"></a> 617 <ol class="indicator"></ol> 618 </div> 619 620 <div class="modal fade video-modal" id="videoModal" tabindex="-1" role="dialog" aria-labelledby="video-modal" aria-hidden="true"> 621 <div class="modal-dialog modal-dialog-centered" role="document"> 622 <div class="modal-content"> 623 <div class="modal-body"> 624 <div id="player"></div> 625 </div> 626 </div> 627 </div> 628 </div> 629 630 <div class="add-to-cart-overlay" data-bind="css: { 'd-block': ProcessingAjax }"> 631 <p class="fs4 m-0 color-white">@Translate("ProductAjaxAddingToCart", "Tilf&oslash;jer til kurv") <i class="fa fa-spinner fa-spin ml-3 fs5"></i></p> 632 </div> 633 634 <div class="add-to-cart-overlay" data-bind="css: { 'd-block': ProcessingVariantDetailsAjax }"> 635 <p class="fs4 m-0 color-white">@Translate("ProductAjaxGettingVariant", "Henter variant") <i class="fa fa-spinner fa-spin ml-3 fs5"></i></p> 636 </div> 637 638 <div class="delivery-information-popup" data-bind="css: { 'd-flex': DeliveryInfoOpen }, click: ToggleDeliveryInfo"> 639 <div class="description-content bg-white px-3 py-4 px-lg-4 position-relative" data-bind="click: OpenDeliveryInfo, clickBubble: false"> 640 <div class="modal-closer-custom" data-bind="click: ToggleDeliveryInfo, clickBubble: false"> 641 <img src="/Files/Templates/Designs/Mobler2018/assets/img/icons/close.svg" /> 642 </div> 643 @if (QuickDelivery) 644 { 645 <div> 646 @QuickDeliveryDescription 647 </div> 648 } 649 else if (DisplayAverageDeliveryTime) 650 { 651 <div> 652 @NormalDeliveryDescription 653 </div> 654 } 655 </div> 656 </div> 657 658 @if (CostPrice > 0) 659 { 660 string PriceDescription = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetString("DagsprisDescription"); 661 <div class="delivery-information-popup" data-bind="css: { 'd-flex': PriceInfoOpen }, click: TogglePriceInfo"> 662 <div class="description-content bg-white px-3 py-4 px-lg-4 position-relative" data-bind="click: OpenPriceInfo, clickBubble: false"> 663 <div class="modal-closer-custom" data-bind="click: TogglePriceInfo, clickBubble: false"> 664 <img src="/Files/Templates/Designs/Mobler2018/assets/img/icons/close.svg" /> 665 </div> 666 <div> 667 @PriceDescription 668 </div> 669 </div> 670 </div> 671 } 672 673 <h1 class="header mb-4" data-bind="text: ProductName">@ProductName</h1> 674 675 <div class="d-flex flex-wrap"> 676 677 <div class="image-container position-relative overflow-hidden"> 678 679 <div class="splash splash--on-top unimportant-hidden" data-bind="css: { 'd-flex': SplashType() == 1 }"><p class="m-0">@Translate("ProductOffer", "Tilbud")</p></div> 680 <div class="splash splash--on-top unimportant-hidden new-item" data-bind="css: { 'd-flex': SplashType() == 2 }"><p class="m-0">@Translate("ProductNew", "Nyhed")</p></div> 681 <div class="splash splash--on-top unimportant-hidden low-price" data-bind="css: { 'd-flex': SplashType() == 3 }"><p class="m-0">@Translate("ProductLowPrice", "Fast lavpris")</p></div> 682 <div class="splash splash--on-top unimportant-hidden price-shape" data-bind="css: { 'd-flex': SplashType() == 4 }" style="background-color: @DailyPriceBackgroundColor;"><p class="m-0" style="color: @DailyPriceTextColor;">@Translate("ProductDailyPriceSplash", "Dagspris")</p></div> 683 <div class="splash splash--on-top unimportant-hidden splash--small" data-bind="css: { 'd-flex': SplashType() == 5}"><p class="m-0">@Translate("ProductCombinationOffer", "Sætpris")</p></div> 684 685 <div id="imageSlider" class="carousel slide" data-ride="carousel" data-interval="5000"> 686 <div class="carousel-inner align-items-center" data-bind="if: Images().length == 0"> 687 688 @foreach (var Image in Images) 689 { 690 if (First) 691 { 692 <a href="/Admin/Public/GetImage.ashx?Image=@Image&width=2000" class="mb-3 mb-lg-0 carousel-item active" data-gallery> 693 <img class="product-image main-image" src="/Admin/Public/GetImage.ashx?Image=@Image&width=950&height=500&crop=5" alt="@ProductName" /> 694 </a> 695 First = false; 696 FirstImage = "/Admin/Public/GetImage.ashx?Image=" + Image + "&width=950&height=500&crop=5"; 697 } 698 else 699 { 700 <a href="/Admin/Public/GetImage.ashx?Image=@Image&width=2000" class="mb-3 mb-lg-0 carousel-item" data-gallery> 701 <img class="product-image main-image" src="/Admin/Public/GetImage.ashx?Image=@Image&width=950&height=500&crop=5" alt="@ProductName" /> 702 </a> 703 } 704 705 } 706 707 </div> 708 <div class="carousel-inner align-items-center d-flex js-ko-carousel" data-bind="foreach: Images()"> 709 710 <a data-bind="attr: { href: '/Admin/Public/GetImage.ashx?Image=' + $data + '&width=2000' }" class="mb-3 mb-lg-0 carousel-item active" data-gallery> 711 <img class="product-image main-image" data-bind="attr: { src: '/Admin/Public/GetImage.ashx?Image=' + $data + '&width=950&height=500&crop=5' }" /> 712 </a> 713 714 </div> 715 </div> 716 717 @if (Images.Count > 0) 718 { 719 <div class="row small-gutter carousel-row" data-bind="css: { 'd-none': Images().length > 0 }"> 720 @if (Images.Count > 1) 721 { 722 foreach (var Image in Images) 723 { 724 if (FirstIndicator) 725 { 726 <div data-target="#imageSlider" data-slide-to="@IndicatorIncrementer" class="col-4 mt-lg-3 cursor-pointer active"> 727 <div class="secondary-image"> 728 <img class="product-image" src="/Admin/Public/GetImage.ashx?Image=@Image&width=400&height=230&crop=5" alt="@ProductName" /> 729 </div> 730 </div> 731 FirstIndicator = false; 732 } 733 else 734 { 735 <div data-target="#imageSlider" data-slide-to="@IndicatorIncrementer" class="col-4 mt-lg-3 cursor-pointer"> 736 <div class="secondary-image"> 737 <img class="product-image" src="/Admin/Public/GetImage.ashx?Image=@Image&width=400&height=230&crop=5" alt="@ProductName" /> 738 </div> 739 </div> 740 } 741 IndicatorIncrementer++; 742 } 743 } 744 @if (!string.IsNullOrEmpty(GetString("Ecom:Product:Field.VideoKlip.Value"))) 745 { 746 string BackgroundSize = !String.IsNullOrEmpty(GetString("Ecom:Product:Field.VideoBillede.Value.Clean")) ? "cover" : "contain"; 747 string OverlayImage = !String.IsNullOrEmpty(GetString("Ecom:Product:Field.VideoBillede.Value.Clean")) ? GetString("Ecom:Product:Field.VideoBillede.Value.Clean") : FirstImage; 748 <div class="youtube-video-container mt-lg-3" style="min-height:120px;" data-bind="youtubeVideo: { videoId: '@GetString("Ecom:Product:Field.VideoKlip.Value")', overlayId: 'js-video-overlay', playerId: 'player' }"> 749 <div id="js-video-overlay" class="video-overlay pointer" style="background-image:url('@OverlayImage');background-size: @BackgroundSize;"> 750 <div class="visual-overlay d-flex flex-column justify-content-center align-items-center h-100 w-100"> 751 <img src="/Files/Templates/Designs/Mobler2018/assets/img/icons/Play.svg" /> 752 <p class="mt-3 mb-0 color-white">@Translate("Product.WatchVideo", "Se video")</p> 753 </div> 754 </div> 755 </div> 756 } 757 758 </div> 759 760 <div class="row small-gutter carousel-row unimportant-hidden" data-bind="css: { 'd-flex': Images().length > 0 }"> 761 <span class="images" style="display:contents;" data-bind="foreach: Images()"> 762 <!-- ko if: $index() == 0 --> 763 <div data-target="#imageSlider" class="col-4 mt-lg-3 cursor-pointer active" data-bind="click: $parent.ChangeSlide.bind($data, $index())"> 764 <div class="secondary-image"> 765 <img class="product-image" data-bind="attr: { src: '/Admin/Public/GetImage.ashx?Image=' + $data + '&width=400&height=230&crop=5' }" alt="@ProductName" /> 766 </div> 767 </div> 768 <!-- /ko --> 769 <!-- ko if: $index() != 0 --> 770 <div data-target="#imageSlider" class="col-4 mt-lg-3 cursor-pointer" data-bind="click: $parent.ChangeSlide.bind($data, $index())"> 771 <div class="secondary-image"> 772 <img class="product-image" data-bind="attr: { src: '/Admin/Public/GetImage.ashx?Image=' + $data + '&width=400&height=230&crop=5' }" alt="@ProductName" /> 773 </div> 774 </div> 775 <!-- /ko --> 776 </span> 777 778 @if (!String.IsNullOrEmpty(GetString("Ecom:Product:Field.VideoKlip.Value"))) 779 { 780 string BackgroundSize = !String.IsNullOrEmpty(GetString("Ecom:Product:Field.VideoBillede.Value.Clean")) ? "cover" : "contain"; 781 string OverlayImage = !String.IsNullOrEmpty(GetString("Ecom:Product:Field.VideoBillede.Value.Clean")) ? GetString("Ecom:Product:Field.VideoBillede.Value.Clean") : FirstImage; 782 <div class="youtube-video-container mt-lg-3" data-bind="youtubeVideo: { videoId: '@GetString("Ecom:Product:Field.VideoKlip.Value")', overlayId: 'js-videovariant-overlay', playerId: 'player' }"> 783 <div id="js-videovariant-overlay" class="video-overlay pointer" style="background-image:url('@OverlayImage');background-size: @BackgroundSize;"> 784 <div class="visual-overlay d-flex flex-column justify-content-center align-items-center h-100 w-100"> 785 <img src="/Files/Templates/Designs/Mobler2018/assets/img/icons/Play.svg" /> 786 <p class="mt-3 mb-0 color-white">@Translate("Product.WatchVideo", "Se video")</p> 787 </div> 788 </div> 789 </div> 790 } 791 </div> 792 } 793 794 </div> 795 796 <div class="pl-lg-4 description-container d-flex flex-wrap flex-column mt-3 mt-lg-0 position-relative"> 797 798 <div class="mb-2">@ShortDescription</div> 799 800 <div class="w-100"><p class="color-primary pointer mb-2" data-bind="scrollToElement: { target: '#js-full-description' }">@Translate("ProductReadFullDescription", "L&aelig;s hele beskrivelsen")</p></div> 801 802 <div class="w-100"> 803 <p class="color-subtle m-0">@Translate("ProductProductNumber", "Produktnummer:") <span data-bind="text: ProductNumber">@ProductNumber</span></p> 804 <p class="color-subtle m-0"> 805 @if (!string.IsNullOrWhiteSpace(GetString("Ecom:Product:Field.dybdeint.Value.Clean"))) 806 { 807 if (GetString("Ecom:Product:Field.dybdeint.Value.Clean") != "0") 808 { 809 <span>D/L: @GetValue("Ecom:Product:Field.dybdeint.Value.Clean")</span> 810 } 811 } 812 @if (!string.IsNullOrWhiteSpace(GetString("Ecom:Product:Field.hoejdeint.Value.Clean"))) 813 { 814 if (GetString("Ecom:Product:Field.hoejdeint.Value.Clean") != "0") 815 { 816 <span>H: @GetValue("Ecom:Product:Field.hoejdeint.Value.Clean")</span> 817 } 818 } 819 @if (!string.IsNullOrWhiteSpace(GetString("Ecom:Product:Field.breddeint.Value.Clean"))) 820 { 821 if (GetString("Ecom:Product:Field.breddeint.Value.Clean") != "0") 822 { 823 <span>B: @GetValue("Ecom:Product:Field.breddeint.Value.Clean")</span> 824 } 825 } 826 </p> 827 </div> 828 829 @if ((QuickDelivery || DisplayAverageDeliveryTime) && !HideDelivery) 830 { 831 <div class="w-100 mt-3"> 832 833 <div class="delivery-information"> 834 <svg class="delivery-icon mr-2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" fill="@DeliveryColor" x="0px" y="0px" width="30px" height="30px" viewBox="0 0 612 612" style="enable-background:new 0 0 612 612;" xml:space="preserve"> 835 <g> 836 <g> 837 <path d="M226.764,375.35c-28.249,0-51.078,22.91-51.078,51.16c0,28.166,22.829,51.078,51.078,51.078s51.078-22.912,51.078-51.078 C277.841,398.26,255.013,375.35,226.764,375.35z M226.764,452.049c-14.125,0-25.54-11.498-25.54-25.541 c0-14.123,11.415-25.539,25.54-25.539c14.124,0,25.539,11.416,25.539,25.539C252.302,440.551,240.888,452.049,226.764,452.049z M612,337.561v54.541c0,13.605-11.029,24.635-24.636,24.635h-26.36c-4.763-32.684-32.929-57.812-66.927-57.812 c-33.914,0-62.082,25.129-66.845,57.812H293.625c-4.763-32.684-32.93-57.812-66.845-57.812c-33.915,0-62.082,25.129-66.844,57.812 h-33.012c-13.606,0-24.635-11.029-24.635-24.635v-54.541H612L612,337.561z M494.143,375.35c-28.249,0-51.16,22.91-51.16,51.16 c0,28.166,22.912,51.078,51.16,51.078c28.166,0,51.077-22.912,51.077-51.078C545.22,398.26,522.309,375.35,494.143,375.35z M494.143,452.049c-14.125,0-25.539-11.498-25.539-25.541c0-14.123,11.414-25.539,25.539-25.539 c14.042,0,25.539,11.416,25.539,25.539C519.682,440.551,508.185,452.049,494.143,452.049z M602.293,282.637l-96.817-95.751 c-6.159-6.077-14.453-9.526-23.076-9.526h-48.86v-18.313c0-13.631-11.004-24.635-24.635-24.635H126.907 c-13.55,0-24.635,11.005-24.635,24.635v3.86L2.3,174.429l177.146,23.068L0,215.323l178.814,25.423L0,256.25l102.278,19.29 l-0.007,48.403h509.712v-17.985C611.983,297.171,608.452,288.796,602.293,282.637z M560.084,285.839h-93.697 c-2.135,0-3.86-1.724-3.86-3.859v-72.347c0-2.135,1.725-3.86,3.86-3.86h17.82c0.985,0,1.971,0.411,2.71,1.068l75.796,72.347 C565.257,281.569,563.532,285.839,560.084,285.839z" /> 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 </g> 854 </g> 855 </svg> 856 <p class="delivery-text @DeliveryFontWeightModifier">@DeliveryTime - <a href="#" class="text-underline" data-bind="click: ToggleDeliveryInfo" style="color: @DeliveryColor">@Translate("Product.DeliveryInfo.ReadmoreText", "L&aelig;s mere")</a></p> 857 </div> 858 859 </div> 860 } 861 862 @if (CostPrice > 0) 863 { 864 <div class="w-100 mt-3"> 865 866 <div class="delivery-information"> 867 <div class="live-price-animation"></div> 868 <p class="delivery-text">@Translate("Product.PriceInfo.RecommendedPriceInfo", "Aktuel dagspris - ")<a href="#" class="text-underline" data-bind="click: TogglePriceInfo">@Translate("Product.PriceInfo.RecommendedPriceLink", "L&aelig;s mere")</a></p> 869 </div> 870 871 </div> 872 } 873 874 875 <div class="w-100"> 876 @if (GetBoolean("Ecom:Product:Field.Farvevarianter1.Value")) 877 { 878 <img class="img-fluid mb-3 mt-5" src="/Files/Images/Farver/farver1.png" /> 879 <p class="mb-0">@Translate("ProductColor1Text", "F&aring;s i flere forskellige varianter og moduler, bes&oslash;g dit lokale M&oslash;blér bolighus og f&aring; vejledning til design af din sofa.")</p> 880 } 881 else if (GetBoolean("Ecom:Product:Field.Farvevarianter2.Value")) 882 { 883 <img class="img-fluid mb-3 mt-5" src="/Files/Images/Farver/farver2.png" /> 884 <p class="mb-0">@Translate("ProductColor2Text", "Farve 2 hj&aelig;lpetekst")</p> 885 } 886 else if (GetBoolean("Ecom:Product:Field.Farvevarianter3.Value")) 887 { 888 <img class="img-fluid mb-3 mt-5" src="/Files/Images/Farver/farver3.png" /> 889 <p class="mb-0">@Translate("ProductColor3Text", "Farve 3 hj&aelig;lpetekst")</p> 890 } 891 else if (GetBoolean("Ecom:Product:Field.Farvevarianter4.Value")) 892 { 893 <img class="img-fluid mb-3 mt-5" src="/Files/Images/Farver/farver4.png" /> 894 <p class="mb-0">@Translate("ProductColor4Text", "Farve 4 hj&aelig;lpetekst")</p> 895 } 896 else if (GetBoolean("Ecom:Product:Field.Farvevarianter5.Value")) 897 { 898 <img class="img-fluid mb-3 mt-5" src="/Files/Images/Farver/farver5.png" /> 899 <p class="mb-0">@Translate("ProductColor5Text", "Farve 5 hj&aelig;lpetekst")</p> 900 } 901 </div> 902 @if (GetLoop("VariantCombinations").Count > 0) 903 { 904 var VariantGroupsWithMultipleOptions = GetLoop("VariantGroups").Where(x => x.GetLoop("VariantAvailableOptions").Count > 1); 905 int VariantGroupCount = VariantGroupsWithMultipleOptions.Count(); 906 int VariantCombinationsCount = GetLoop("VariantCombinations").Count; 907 int PossibleVariantCombinations = 1; 908 foreach (var VG in GetLoop("VariantGroups")) 909 { 910 PossibleVariantCombinations *= VG.GetLoop("VariantAvailableOptions").Count; 911 } 912 if (VariantGroupCount == 1) 913 { 914 var RelevantVariantGroup = VariantGroupsWithMultipleOptions.FirstOrDefault(); 915 var SelectedVariant = RelevantVariantGroup.GetLoop("VariantAvailableOptions").Where(x => x.GetBoolean("Ecom:VariantOption.Selected")).FirstOrDefault(); 916 <div class="position-relative"> 917 <div class="variant-dropdown p-2 box-shadow mt-3 d-flex justify-content-between align-items-center pointer js-variant-dropdown"> 918 <p class="m-0"><span class="font-weight-bold">@RelevantVariantGroup.GetString("Ecom:VariantGroup.Label")</span> - <span data-bind="text: SelectedVariantOption0">@SelectedVariant.GetString("Ecom:VariantOption.Name")</span></p> 919 <i class="fas fa-chevron-down"></i> 920 </div> 921 <div class="variant-options bg-white"> 922 @foreach (var Variant in RelevantVariantGroup.GetLoop("VariantAvailableOptions")) 923 { 924 var VariantCombination = GetLoop("VariantCombinations").Where(x => x.GetString("Ecom:VariantCombination.VariantID").ToString().Contains(Variant.GetString("Ecom:VariantOption.ID"))).FirstOrDefault(); 925 string VariantName = Variant.GetString("Ecom:VariantOption.Name"); 926 string VariantIdentifier = Variant.GetString("Ecom:VariantOption.ID"); 927 string VariantLink = VariantCombination.GetString("Ecom:VariantCombination.Link.Clean"); 928 string VariantPreview = String.Empty; 929 var ObservableToSet = "SelectedVariantOption0"; 930 var ObservableToSetId = "SelectedVariantOptionId0"; 931 bool ShowPreview = RelevantVariantGroup.GetString("Ecom:VariantGroup.Name").ToString().ToLower().Contains("farve") || RelevantVariantGroup.GetString("Ecom:VariantGroup.Name").ToString().ToLower().Contains("materiale") ? true : false; 932 if (!String.IsNullOrEmpty(Variant.GetString("Ecom:VariantOption.ImgSmall.Clean")) && ShowPreview) 933 { 934 if (Variant.GetString("Ecom:VariantOption.ImgSmall.Clean").StartsWith("#")) 935 { 936 VariantPreview = "style= \"background-color: " + Variant.GetString("Ecom:VariantOption.ImgSmall.Clean") + ";\""; 937 } 938 else 939 { 940 VariantPreview = "style=\"background-image: url('" + Variant.GetString("Ecom:VariantOption.ImgSmall.Clean") + "');\""; 941 } 942 } 943 <div class="option pointer color-primary d-flex w-100 p-2 bg-grey" data-bind="click: UpdateVariantAndSetObservable.bind($data, '@VariantIdentifier', @ObservableToSet, '@VariantName', @ObservableToSetId)"> 944 @if (!String.IsNullOrEmpty(VariantPreview)) 945 { 946 <span class="option-preview mr-2" @VariantPreview></span> 947 } 948 <span>@VariantName</span> 949 </div> 950 <div class="d-none" data-bind="setInitValue: { observable: @ObservableToSet, value: '@SelectedVariant.GetString("Ecom:VariantOption.Name")' }"></div> 951 <div class="d-none" data-bind="setInitValue: { observable: @ObservableToSetId, value: '@SelectedVariant.GetString("Ecom:VariantOption.ID")' }"></div> 952 953 } 954 </div> 955 </div> 956 } 957 else if (PossibleVariantCombinations == VariantCombinationsCount) 958 { 959 Dictionary<string, string> CurrentlySelectedVariantOptions = new Dictionary<string, string>(); 960 foreach (var VG in GetLoop("VariantGroups")) 961 { 962 foreach (var VO in VG.GetLoop("VariantAvailableOptions").Where(x => x.GetBoolean("Ecom:VariantOption.Selected"))) 963 { 964 CurrentlySelectedVariantOptions.Add(VG.GetString("Ecom:VariantGroup.Name"), VO.GetString("Ecom:VariantOption.ID")); 965 } 966 } 967 int VGLoopCounter = 0; 968 foreach (var VG in GetLoop("VariantGroups")) 969 { 970 List<LoopItem> RelevantVariantCombinations = new List<LoopItem>(); 971 var VariantCombinationLink = GetLoop("VariantCombinations"); 972 var SelectedVariant = VG.GetLoop("VariantAvailableOptions").Where(x => x.GetBoolean("Ecom:VariantOption.Selected")).FirstOrDefault(); 973 var ObservableToSet = "SelectedVariantOption" + VGLoopCounter.ToString(); 974 var ObservableToSetId = "SelectedVariantOptionId" + VGLoopCounter.ToString(); 975 VGLoopCounter++; 976 foreach (var VC in VariantCombinationLink) 977 { 978 var Add = true; 979 foreach (var KVP in CurrentlySelectedVariantOptions.Where(s => s.Key != VG.GetString("Ecom:VariantGroup.Name"))) 980 { 981 if (!VC.GetString("Ecom:VariantCombination.VariantID").ToString().Contains(KVP.Value)) 982 { 983 Add = false; 984 } 985 } 986 if (Add) 987 { 988 RelevantVariantCombinations.Add(VC); 989 } 990 } 991 <div class="d-none" data-bind="setInitValue: { observable: @ObservableToSet, value: '@SelectedVariant.GetString("Ecom:VariantOption.Name")' }"></div> 992 <div class="d-none" data-bind="setInitValue: { observable: @ObservableToSetId, value: '@SelectedVariant.GetString("Ecom:VariantOption.ID")' }"></div> 993 994 995 <div class="position-relative"> 996 <div class="variant-dropdown p-2 box-shadow mt-3 d-flex justify-content-between align-items-center pointer js-variant-dropdown"> 997 <p class="m-0"><span class="font-weight-bold">@VG.GetString("Ecom:VariantGroup.Label")</span> - <span data-bind="text: @ObservableToSet">@SelectedVariant.GetString("Ecom:VariantOption.Name")</span></p> 998 <i class="fas fa-chevron-down"></i> 999 </div> 1000 <div class="variant-options bg-white"> 1001 @foreach (var VO in VG.GetLoop("VariantAvailableOptions")) 1002 { 1003 var VariantCombination = RelevantVariantCombinations.Where(vc => vc.GetString("Ecom:VariantCombination.VariantID").ToString().Contains(VO.GetString("Ecom:VariantOption.ID"))).FirstOrDefault(); 1004 string VariantLink = VariantCombination.GetString("Ecom:VariantCombination.Link.Clean"); 1005 string VariandOptionId = VariantCombination.GetString("Ecom:VariantCombination.VariantID"); 1006 string VariantPreview = String.Empty; 1007 string VOName = VO.GetString("Ecom:VariantOption.Name"); 1008 string VOId = VO.GetString("Ecom:VariantOption.ID"); 1009 bool ShowPreview = VG.GetString("Ecom:VariantGroup.Name").ToString().ToLower().Contains("farve") || VG.GetString("Ecom:VariantGroup.Name").ToString().ToLower().Contains("materiale") ? true : false; 1010 if (!String.IsNullOrEmpty(VO.GetString("Ecom:VariantOption.ImgSmall.Clean")) && ShowPreview) 1011 { 1012 if (VO.GetString("Ecom:VariantOption.ImgSmall.Clean").StartsWith("#")) 1013 { 1014 VariantPreview = "style= \"background-color: " + VO.GetString("Ecom:VariantOption.ImgSmall.Clean") + ";\""; 1015 } 1016 else 1017 { 1018 VariantPreview = "style=\"background-image: url('" + VO.GetString("Ecom:VariantOption.ImgSmall.Clean") + "');\""; 1019 } 1020 } 1021 <div class="option d-flex w-100 p-2 bg-grey color-primary pointer" data-bind="click: UpdateVariantAndSetObservable.bind($data, '@VOId', @ObservableToSet, '@VOName', @ObservableToSetId)"> 1022 @if (!String.IsNullOrEmpty(VariantPreview)) 1023 { 1024 <span class="option-preview mr-2" @VariantPreview></span> 1025 } 1026 @VOName 1027 </div> 1028 } 1029 </div> 1030 </div> 1031 } 1032 } 1033 else if (GetLoop("VariantGroups").Where(x => x.GetString("Ecom:VariantGroup.Name").ToString().ToLower().Contains("farve")).Count() > 0 && GetLoop("VariantGroups").Where(x => x.GetString("Ecom:VariantGroup.Name").ToString().ToLower().Contains("materiale")).Count() > 0) 1034 { 1035 <div class="mt-3"> 1036 <p class="mb-1">@Translate("CurrentDesignName", "Valgte design: ")</p> 1037 <p class="font-weight-bold">@CurrentVariantName</p> 1038 </div> 1039 <div class="d-flex"> 1040 <div class="btn btn-primary" data-bind="click: ToggleVariantPicker">@Translate("ChooseNewDesign", "V&aelig;lg design")</div> 1041 </div> 1042 } 1043 else 1044 { 1045 var SelectedVariant = GetLoop("VariantCombinations").Where(x => x.GetBoolean("Ecom:VariantCombination.Selected")).FirstOrDefault(); 1046 var SelectedVariantName = SelectedVariant.GetString("Ecom:VariantCombination.VariantText"); 1047 var SelectedVariantId = SelectedVariant.GetString("Ecom:VariantOption.ID"); 1048 <div class="d-none" data-bind="setInitValue: { observable: SelectedVariantOption0, value: '@SelectedVariantName' }"></div> 1049 <div class="d-none" data-bind="setInitValue: { observable: SelectedVariantOptionId0, value: '@SelectedVariantId' }"></div> 1050 <div class="position-relative"> 1051 <div class="variant-dropdown p-2 box-shadow mt-3 d-flex justify-content-between align-items-center pointer js-variant-dropdown"> 1052 <p class="m-0"><span class="font-weight-bold">@Translate("FallbackVariantsText", "VARIANTER")</span> - <span data-bind="text: SelectedVariantOption0">@SelectedVariantName</span></p> 1053 <i class="fas fa-chevron-down"></i> 1054 </div> 1055 <div class="variant-options bg-white"> 1056 @foreach (var Variant in GetLoop("VariantCombinations")) 1057 { 1058 string VariantName = Variant.GetString("Ecom:VariantCombination.VariantText"); 1059 string VariantLink = Variant.GetString("Ecom:VariantCombination.Link.Clean"); 1060 string VCId = Variant.GetString("Ecom:Product.VariantID"); 1061 <div class="option color-primary pointer d-block p-2 bg-grey" data-bind="click: UpdateVariantAndSetObservable.bind($data, '@VCId', SelectedVariantOption0, '@VariantName', SelectedVariantOptionId0)">@VariantName</div> 1062 } 1063 </div> 1064 </div> 1065 } 1066 1067 } 1068 1069 <div class="row align-items-end f-grow-1"> 1070 <div class="col-10 offset-1 col-sm-12 offset-sm-0 d-flex justify-content-center justify-content-lg-start"> 1071 1072 <div class="mt-5 d-flex flex-wrap flex-column justify-content-end"> 1073 @if (campaignText == "KOMBI") 1074 { 1075 <div class="d-none" data-bind="setInitValue: { observable: SplashType, value: 5 }"></div> 1076 <div class="d-none" data-bind="setInitValue: { observable: BeforePrice, value: '@normalPriceFormatted' }"></div> 1077 <div class="d-none" data-bind="setInitValue: { observable: Saving, value: '@sparFormatted' }"></div> 1078 } 1079 else if (spar > 0) 1080 { 1081 <div class="d-none" data-bind="setInitValue: { observable: SplashType, value: 1 }"></div> 1082 <div class="d-none" data-bind="setInitValue: { observable: BeforePrice, value: '@normalPriceFormatted' }"></div> 1083 <div class="d-none" data-bind="setInitValue: { observable: Saving, value: '@sparFormatted' }"></div> 1084 } 1085 else if (NewItem) 1086 { 1087 if ( NewItemExpiryDate > DateTime.Now ) 1088 { 1089 <div class="d-none" data-bind="setInitValue: { observable: SplashType, value: 2 }"></div> 1090 } 1091 } 1092 else if (LowPrice) 1093 { 1094 <div class="d-none" data-bind="setInitValue: { observable: SplashType, value: 3 }"></div> 1095 } 1096 else if (CostPrice > 0) 1097 { 1098 <div class="d-none" data-bind="setInitValue: { observable: SplashType, value: 4 }"></div> 1099 } 1100 1101 <div class="w-100 unimportant-hidden" data-bind="css: { 'd-flex': SplashType() == 1 || SplashType() == 5}"> 1102 <p class="color-subtle fs0 m-0 text-uppercase mr-3">@Translate("PriceBefore", "Før") <span data-bind="text: BeforePrice"></span></p> 1103 <p class="splash fs0 text-uppercase m-0 px-2">@Translate("PriceSaving", "Spar") <span data-bind="text: Saving"></span></p> 1104 </div> 1105 <p class="price font-weight-bold m-0"> 1106 <span class="unimportant-hidden" data-bind="css: { 'd-inline': SplashType() == 1 }">@Translate("ProductNow", "NU") </span> 1107 <span data-bind="text: Price"></span> 1108 </p> 1109 1110 1111 @if (!string.IsNullOrEmpty(campaignDateStart) && !string.IsNullOrEmpty(campaignDateEnd)) 1112 { 1113 string CampaignText = $"{Translate("Campaign.BeforeDate.Text", "Gældende fra:")} {campaignDateStart} {Translate("Campaign.BeforeDate.Text2", "t.o.m.")} {campaignDateEnd}"; 1114 <div class="d-none" data-bind="setInitValue: { observable: CampaignText, value: '@CampaignText' }"></div> 1115 } 1116 else 1117 { 1118 <div class="d-none" data-bind="setInitValue: { observable: CampaignText, value: '' }"></div> 1119 } 1120 1121 <p data-bind="text: CampaignText"></p> 1122 1123 @if (!string.IsNullOrEmpty(PayeverWidget.WidgetId) && !string.IsNullOrEmpty(PayeverWidget.BusinessId) && !string.IsNullOrEmpty(PayeverWidget.CheckoutId)) 1124 { 1125 <div> 1126 <div class="payever-widget-finexp" 1127 data-widgetid="@PayeverWidget.WidgetId" 1128 data-checkoutid="@PayeverWidget.CheckoutId" 1129 data-business="@PayeverWidget.BusinessId" 1130 data-type="text" 1131 data-reference="order-id" 1132 data-amount="@GetString("Ecom:Product.Price.Price").Replace(".", string.Empty).Replace(",", ".")"></div> 1133 <script> 1134 var script = document.createElement('script'); 1135 script.src = 'https://widgets.payever.org/finance-express/widget.min.js'; 1136 script.onload = function() { 1137 PayeverPaymentWidgetLoader.init( 1138 '.payever-widget-finexp' 1139 ); 1140 }; 1141 document.head.appendChild(script); 1142 </script> 1143 </div> 1144 } 1145 1146 @if (ForSale) 1147 { 1148 <div class="d-flex align-items-center mt-3"> 1149 <p class="m-0 font-weight-bold fs1 mr-2">@Translate("Product.Quantity", "Antal")</p> 1150 <div class="d-flex"> 1151 <div class="quantity-controls d-flex align-items-center mr-3"> 1152 <div class="control minus" data-bind="click: DecreaseQuantity"> 1153 - 1154 </div> 1155 <input type="text" name="Quantity" value="1" data-bind="value: Quantity" /> 1156 <div class="control plus" data-bind="click: IncrementQuantity"> 1157 + 1158 </div> 1159 </div> 1160 @{ 1161 string addToCartButtonClass = BlackFridayTheme == "True" ? "btn-black-friday bf-bg-black" : "btn-primary"; 1162 } 1163 <p class="btn @addToCartButtonClass add-to-cart m-0 d-flex align-items-center px-4" data-bind="click: AddToCart.bind($data, '@DataLayerPrice')"> 1164 @Translate("ProductAddToCart", "L&aelig;g i kurv") 1165 </p> 1166 1167 </div> 1168 </div> 1169 } 1170 else 1171 { 1172 <p>@Translate("Ecom:Product.NotForSaleMessage", "Produktet kan ikke købes.")</p> 1173 } 1174 </div> 1175 </div> 1176 </div> 1177 1178 </div> 1179 1180 </div> 1181 1182 <div class="d-flex flex-wrap justify-content-center external-ctas"> 1183 1184 @if (!String.IsNullOrWhiteSpace(GetString("Ecom:Product:Field.ProviderLink.Value.Clean"))) 1185 { 1186 <a href="@GetString("Ecom:Product:Field.ProviderLink.Value.Clean")" target="_blank" class="bg-brand font-weight-bold d-flex align-items-center justify-content-center no-underline p-3 color-white"> 1187 <span>@Translate("Product.DesignSelf", "Design selv")</span> 1188 <img src="/Files/Templates/Designs/Mobler2018/assets/img/icons/Pencil1.svg" /> 1189 </a> 1190 } 1191 1192 @if (!String.IsNullOrEmpty(ProductCatalogLink)) 1193 { 1194 <a class="btn btn-secondary rounded-0 d-flex justify-content-center align-items-center p-3 color-white font-weight-bold" href="@ProductCatalogLink" target="_blank"> 1195 <span>@Translate("ProductProductCatalogLink", "Se inspirationsbrochure")</span> 1196 <img src="/Files/Templates/Designs/Mobler2018/assets/img/icons/Brochure.svg" /> 1197 </a> 1198 } 1199 1200 </div> 1201 1202 <div class="d-flex flex-wrap mt-5"> 1203 1204 <div id="js-full-description"> 1205 <p class="fs3 mb-2 font-weight-bold">@Translate("ProductDescriptionHeader", "Beskrivelse")</p> 1206 <div class="unimportant-hidden" data-bind="html: FullDescription, css: { 'd-block': FullDescription().length > 0 }"> 1207 </div> 1208 <div data-bind="css: { 'd-none': FullDescription().length > 0 }"> 1209 @LongDescription 1210 1211 @if (!string.IsNullOrEmpty(productionDescription)) 1212 { 1213 <br /><br /> 1214 <h4>@Translate("Product.ProductionDescription.Headline", "Produktionsbeskrivelse")</h4> 1215 @:@productionDescription 1216 } 1217 </div> 1218 </div> 1219 1220 </div> 1221 1222 <div class="d-flex flex-wrap my-5"> 1223 1224 <div class="description-container mt-5 mt-lg-0"> 1225 <div class="bg-brand color-white box-shadow p-3 pb-5 questions"> 1226 <img class="staff-img" src="/Files/Templates/Designs/Mobler2018/assets/img/sovnmand.png" /> 1227 1228 @if (!String.IsNullOrWhiteSpace(shopInfo.ShopName) && shopInfo.ShopName != "Møblér") 1229 { 1230 <div class="shop-info"> 1231 <h4 class="fs45">@Translate("ProductQuestionsHeader", "Har du sp&oslash;rsm&aring;l?")</h4> 1232 <p class="mb-1">@shopInfo.Address, @shopInfo.PostalAndCity</p> 1233 <p class="mb-1">@shopInfo.Phone</p> 1234 @if (!String.IsNullOrEmpty(shopInfo.Email)) 1235 { 1236 <p class="mb-1"><a class="color-white" href="mailto:@shopInfo.Email">@shopInfo.Email</a></p> 1237 } 1238 @if (!String.IsNullOrEmpty(shopInfo.ShopName1)) 1239 { 1240 <p class="mb-1 mt-2">@shopInfo.Address1, @shopInfo.PostalAndCity1</p> 1241 <p class="mb-2">@shopInfo.Phone1</p> 1242 } 1243 @if (!String.IsNullOrEmpty(shopInfo.ShopName2)) 1244 { 1245 <p class="mb-1 mt-2">@shopInfo.Address2, @shopInfo.PostalAndCity2</p> 1246 <p class="mb-2">@shopInfo.Phone2</p> 1247 } 1248 @shopInfo.OpeningHours 1249 </div> 1250 } 1251 else 1252 { 1253 <h4 class="fs45">@Translate("ProductQuestionsHeader", "Har du sp&oslash;rsm&aring;l?")</h4> 1254 <p class="fs2 text">@Translate("ProductSelectNearestShop", "V&aelig;lg n&aelig;rmeste M&oslash;bler bolighus")</p> 1255 <select style="width: 280px;" data-bind="select2SelectShop: { overlay: 'find-dealer-overlay', placeholder: '@SelectPlaceholder' }"> 1256 @if (shopname == "Møblér") 1257 { 1258 <option selected disabled>@Translate("HeaderFindShop", "Find forhandler")</option> 1259 } 1260 else 1261 { 1262 foreach (var Shop in AllShops.Where(x => x.MenuText == shopname)) 1263 { 1264 <option selected disabled value="@HttpUtility.UrlEncode(Shop.MenuText)">@Shop.ShopName</option> 1265 } 1266 } 1267 @foreach (var Shop in AllShops) 1268 { 1269 if (Shop.MenuText != "Møblér" && Shop.MenuText != shopname) 1270 { 1271 var Address = "<div>" + Shop.Address + "</div><div>" + Shop.PostalAndCity + "</div>"; 1272 <option title="@Address" value="@HttpUtility.UrlEncode(Shop.MenuText)">@Shop.ShopName {{@Shop.PostalAndCity @Shop.SearchKeyWords}}</option> 1273 } 1274 } 1275 </select> 1276 } 1277 </div> 1278 </div> 1279 1280 </div> 1281 1282 @if (GetInteger("Ecom:Product.RelatedCount") > 0) 1283 { 1284 foreach (var Group in GetLoop("ProductRelatedGroups").Where(g => g.GetLoop("Products").Count > 0)) 1285 { 1286 <div class="py-3 mt-5" data-bind="viewModel: 'ProductListViewModel'"> 1287 1288 <div class="delivery-information-popup" data-bind="css: { 'd-flex': QuickDeliveryInfoOpen }, click: ToggleQuickDeliveryInfo"> 1289 <div class="description-content bg-white px-3 py-4 px-lg-4 position-relative" data-bind="click: OpenQuickDeliveryInfo, clickBubble: false"> 1290 <div class="modal-closer-custom" data-bind="click: ToggleQuickDeliveryInfo, clickBubble: false"> 1291 <img src="/Files/Templates/Designs/Mobler2018/assets/img/icons/close.svg" /> 1292 </div> 1293 <div> 1294 @QuickDeliveryDescription 1295 </div> 1296 </div> 1297 </div> 1298 <div class="delivery-information-popup" data-bind="css: { 'd-flex': NormalDeliveryInfoOpen }, click: ToggleNormalDeliveryInfo"> 1299 <div class="description-content bg-white px-3 py-4 px-lg-4 position-relative" data-bind="click: OpenNormalDeliveryInfo, clickBubble: false"> 1300 <div class="modal-closer-custom" data-bind="click: ToggleNormalDeliveryInfo, clickBubble: false"> 1301 <img src="/Files/Templates/Designs/Mobler2018/assets/img/icons/close.svg" /> 1302 </div> 1303 <div> 1304 @NormalDeliveryDescription 1305 </div> 1306 </div> 1307 </div> 1308 1309 <div class="line-through-header mb-3"> 1310 <h4>@Group.GetString("Ecom:Product:RelatedGroup.Name")</h4> 1311 </div> 1312 1313 <div class="row"> 1314 1315 @foreach (var Product in Group.GetLoop("Products")) 1316 { 1317 var productToRender = Product; 1318 string productId = Product.GetString("Ecom:Product.ID"); 1319 string variantIdLoop = productsDisplayVariant.GetDisplayVariantId(productId); 1320 1321 if (Product.GetLoop("VariantCombinations").Count > 0 && Product.GetLoop("VariantCombinations").Any(x => x.GetString("Ecom:Product.VariantID").Equals(variantIdLoop))) 1322 { 1323 productToRender = Product.GetLoop("VariantCombinations").FirstOrDefault(x => x.GetString("Ecom:Product.VariantID").Equals(variantIdLoop)); 1324 } 1325 @RenderProduct(productToRender) 1326 } 1327 </div> 1328 </div> 1329 } 1330 } 1331 1332 1333 @if(Mobler.Website.CustomCode.RelewiseCustom.RelewiseConnectorSetting.ShowRecommendations) 1334 { 1335 if (GetLoop("RelewiseRecommendationProducts").Count > 0) 1336 { 1337 <div class="py-3 mt-5" data-bind="viewModel: 'ProductListViewModel'"> 1338 1339 1340 <div class="line-through-header mb-3"> 1341 <h4>@Translate("Product:RelewiseRecommendationProducts.Headline", "Vi anbefaler du også tjekker disse produkter ud...")</h4> 1342 </div> 1343 1344 <div class="row"> 1345 1346 @foreach (var Product in GetLoop("RelewiseRecommendationProducts")) 1347 { 1348 var productToRender = Product; 1349 string productId = Product.GetString("Ecom:Product.ID"); 1350 string variantIdLoop = productsDisplayVariant.GetDisplayVariantId(productId); 1351 1352 if (Product.GetLoop("VariantCombinations").Count > 0 && Product.GetLoop("VariantCombinations").Any(x => x.GetString("Ecom:Product.VariantID").Equals(variantIdLoop))) 1353 { 1354 productToRender = Product.GetLoop("VariantCombinations").FirstOrDefault(x => x.GetString("Ecom:Product.VariantID").Equals(variantIdLoop)); 1355 } 1356 1357 @RenderProduct(productToRender) 1358 } 1359 </div> 1360 </div> 1361 } 1362 } 1363 1364 1365 @if (RelatedBlogs.Count > 0) 1366 { 1367 string ImagePosition = "Left"; 1368 <div class="feature-blogs my-5"> 1369 1370 <div class="row"> 1371 1372 @foreach (var Blog in RelatedBlogs) 1373 { 1374 @RenderLargeBlogTeaser(Blog, ImagePosition) 1375 if (ImagePosition == "Left") 1376 { 1377 ImagePosition = "Right"; 1378 } 1379 else 1380 { 1381 ImagePosition = "Left"; 1382 } 1383 } 1384 1385 </div> 1386 1387 </div> 1388 } 1389 1390 1391 <div class="after-add-to-cart bg-white box-shadow" data-bind="css: { 'd-block': ProductAddedToCart }"> 1392 <div class="closer fs3 pointer" data-bind="click: ProductAddedToCart(false)"> 1393 <i class="fas fa-times-circle color-primary"></i> 1394 </div> 1395 <div class="p-3"> 1396 <p class="font-weight-bold fs4 text-uppercase m-0"> 1397 <i class="fas fa-check-circle color-primary"></i> 1398 @Translate("ProductProductAddedToCart", "Varen er lagt i indk&oslash;bskurven") 1399 </p> 1400 </div> 1401 <div class="mini-cart large-cart power-step"> 1402 1403 <div class="position-relative"> 1404 <div class="cart-command-loader unimportant-hidden justify-content-center align-items-center" data-bind="css: { 'd-flex': Loading }"> 1405 <div class="d-flex align-items-center"> 1406 <p class="m-0 mr-2">@Translate("Cart.UpdatingCart", "Opdaterer kurv")</p> 1407 <i class="fas fa-spinner fa-spin"></i> 1408 </div> 1409 </div> 1410 1411 <div class="lines" data-bind="foreach: Orderlines"> 1412 <div class="cartline d-flex justify-content-between align-items-center px-3 py-2 position-relative bg-grey"> 1413 <span class="delete-orderline color-subtle cursor-pointer mr-2" data-bind="click: $parent.DeleteOrderline.bind($data, OrderlineId)"> 1414 <i class="fas fa-times"></i> 1415 </span> 1416 <div class="product-image w-10"> 1417 <img class="img-fluid" data-bind="attr: { src: ImagePath }" /> 1418 </div> 1419 <div class="flex-fill px-3 w-75"> 1420 <p class="font-weight-bold m-0" data-bind="text: ProductName"></p> 1421 <p class="m-0 color-subtle small-quantity-indicator"><span data-bind="text: Quantity"></span> stk. a <span data-bind="text: QuantityPrice"></span></p> 1422 <div class="variant-dimensions" data-bind="foreach: VariantDimensions"> 1423 <p class="m-0 color-subtle color-dark-grey font-weight-bold"> 1424 <span data-bind="text: Label"></span> 1425 <span class="font-weight-normal" data-bind="text: Value"></span> 1426 </p> 1427 </div> 1428 </div> 1429 <div class="qty-counter w-10"> 1430 <div class="d-flex"> 1431 <div class="quantity-controls d-flex align-items-center mr-3"> 1432 <div class="control minus" data-bind="click: $parent.QuantityControl.bind($data, -1, OrderlineId)"> 1433 - 1434 </div> 1435 <input disabled type="text" name="Quantity" value="1" data-bind="value: Quantity, attr: { 'data-id': 'js-input-' + OrderlineId }" /> 1436 <div class="control plus" data-bind="click: $parent.QuantityControl.bind($data, 1, OrderlineId)"> 1437 + 1438 </div> 1439 </div> 1440 </div> 1441 </div> 1442 1443 <p class="fs0 m-0 orderline-price" data-bind="text: OrderlinePrice"></p> 1444 </div> 1445 </div> 1446 @if (BlackFridayTheme == "True") 1447 { 1448 <div class="bf-bg-black p-3 d-flex justify-content-between align-items-center price-summary"> 1449 <p class="m-0 color-white fs-12px font-weight-semibold">@Translate("MiniCartTotal", "Din kurv i alt (ex. fragt)")</p> 1450 <p class="m-0 color-white fs1 font-weight-bold" data-bind="text: CartTotalNoFees"></p> 1451 </div> 1452 } 1453 else 1454 { 1455 <div class="bg-brand p-3 d-flex justify-content-between align-items-center price-summary"> 1456 <p class="m-0 color-white fs-12px font-weight-semibold">@Translate("MiniCartTotal", "Din kurv i alt (ex. fragt)")</p> 1457 <p class="m-0 color-white fs1 font-extra-bold" data-bind="text: CartTotalNoFees"></p> 1458 </div> 1459 } 1460 </div> 1461 1462 </div> 1463 <div class="p-3 d-flex justify-content-between"> 1464 <p class="pointer py-2 px-3 bg-dark-grey color-white rounded m-0" data-bind="click: ProductAddedToCart(false)">@Translate("MiniCartContinueShopping", "Handel videre")</p> 1465 1466 @if (BlackFridayTheme == "True") 1467 { 1468 <a href="@CartPage" class="pointer py-2 px-3 bf-bg-black color-white rounded d-block no-underline">@Translate("MiniCartGoToCheckout", "G&aring; til kassen")</a> 1469 } 1470 else 1471 { 1472 <a href="@CartPage" class="pointer py-2 px-3 bg-brand color-white rounded d-block no-underline">@Translate("MiniCartGoToCheckout", "G&aring; til kassen")</a> 1473 } 1474 1475 </div> 1476 <div class="js-customers-also-saw-lines"></div> 1477 1478 </div> 1479 <div class="variant-picker" data-bind="css: { 'open': VariantPickerOpen }"> 1480 <div class="closer color-primary fs5 pointer" data-bind="click: ToggleVariantPicker"> 1481 <i class="fas fa-times-circle"></i> 1482 </div> 1483 <div class="container py-5 position-relative"> 1484 <h3 class="fs4 text-center">Design din @ProductName</h3> 1485 @{ 1486 var ColorDimensions = GetLoop("VariantGroups").Where(g => g.GetString("Ecom:VariantGroup.Name").ToLower().Contains("farve")); 1487 var NonColorDimensions = GetLoop("VariantGroups").Where(g => !g.GetString("Ecom:VariantGroup.Name").ToLower().Contains("farve")); 1488 int FilterCounter = 0; 1489 string RowClass = NonColorDimensions.Any() && ColorDimensions.Any() ? "flex-row-reverse" : ""; 1490 } 1491 <div class="row mt-5 @RowClass"> 1492 @if (ColorDimensions.Any()) 1493 { 1494 <div class="col-12 col-md-8"> 1495 @foreach (var VariantDimension in ColorDimensions) 1496 { 1497 string DimensionName = VariantDimension.GetString("Ecom:VariantGroup.Name"); 1498 string FilterName = "filter-" + FilterCounter; 1499 FilterCounter++; 1500 <div class="mb-5 mb-md-0"> 1501 <p class="font-weight-bold fs2 mb-2">@DimensionName</p> 1502 <div class="row custom-row"> 1503 @foreach (var VariantOption in VariantDimension.GetLoop("VariantAvailableOptions").OrderBy(v => v.GetString("Ecom:VariantOption.Name"))) 1504 { 1505 string VariantOptionName = VariantOption.GetString("Ecom:VariantOption.Name"); 1506 string VariantOptionId = VariantOption.GetString("Ecom:VariantOption.ID"); 1507 string Preview = VariantOption.GetString("Ecom:VariantOption.ImgSmall.Clean"); 1508 string PreviewCss = ""; 1509 if (!String.IsNullOrEmpty(Preview)) 1510 { 1511 if (Preview.StartsWith("#")) 1512 { 1513 PreviewCss = "style= \"background-color: " + Preview + ";\""; 1514 } 1515 else 1516 { 1517 PreviewCss = "style=\"background-image: url('" + Preview + "');\""; 1518 } 1519 } 1520 <div class="col-2 col-sm-3 col-md-2 mb-3 d-flex flex-column justify-content-end pointer color-variant" data-bind="click: AddToFilter.bind($data, $element, '@FilterName', '@VariantOptionId')"> 1521 <p class="mb-0 color-variant-name d-none d-sm-block">@VariantOptionName</p> 1522 <div class="variant-preview position-relative d-flex" @PreviewCss></div> 1523 </div> 1524 } 1525 </div> 1526 </div> 1527 } 1528 </div> 1529 } 1530 @if (NonColorDimensions.Any()) 1531 { 1532 <div class="col-12 col-sm-6 col-md-4"> 1533 @foreach (var VariantDimension in NonColorDimensions) 1534 { 1535 string DimensionName = VariantDimension.GetString("Ecom:VariantGroup.Name"); 1536 string FilterName = "filter-" + FilterCounter; 1537 FilterCounter++; 1538 <div class="mb-5"> 1539 <p class="font-weight-bold fs2 mb-2">@DimensionName</p> 1540 <div class="row custom-row"> 1541 @foreach (var VariantOption in VariantDimension.GetLoop("VariantAvailableOptions").OrderBy(v => v.GetString("Ecom:VariantOption.Name"))) 1542 { 1543 string VariantOptionName = VariantOption.GetString("Ecom:VariantOption.Name"); 1544 string VariantOptionId = VariantOption.GetString("Ecom:VariantOption.ID"); 1545 string Preview = VariantOption.GetString("Ecom:VariantOption.ImgSmall.Clean"); 1546 string PreviewCss = ""; 1547 if (!String.IsNullOrEmpty(Preview)) 1548 { 1549 if (Preview.StartsWith("#")) 1550 { 1551 PreviewCss = "style= \"background-color: " + Preview + ";\""; 1552 } 1553 else 1554 { 1555 PreviewCss = "style=\"background-image: url('/Files" + Preview + "');\""; 1556 } 1557 } 1558 if (DimensionName == "STØRRELSE") 1559 { 1560 <div class="col-6 col-sm-4 mb-3 d-flex flex-column justify-content-end pointer size-variant" data-bind="click: AddToFilter.bind($data, $element, '@FilterName', '@VariantOptionId')"> 1561 <div class="variant-preview position-relative d-flex justify-content-center align-items-center" @PreviewCss> 1562 <p class="mb-0 color-variant-name font-weight-bold">@VariantOptionName</p> 1563 </div> 1564 </div> 1565 } 1566 else 1567 { 1568 <div class="col-6 col-sm-4 mb-3 d-flex flex-column justify-content-end pointer" data-bind="click: AddToFilter.bind($data, $element, '@FilterName', '@VariantOptionId')"> 1569 <p class="mb-0 color-variant-name">@VariantOptionName</p> 1570 <div class="variant-preview position-relative d-flex" @PreviewCss></div> 1571 </div> 1572 } 1573 } 1574 </div> 1575 </div> 1576 } 1577 </div> 1578 } 1579 1580 <div class="col-12 d-flex justify-content-end"> 1581 <p class="color-primary pointer my-3" data-bind="click: ResetFilters">Nulstil</p> 1582 </div> 1583 </div> 1584 <p class="font-weight-bold fs2 mt-5"> 1585 @Translate("ChooseProduct", "V&aelig;lg produkt") 1586 </p> 1587 <div class="row align-items-end" data-bind="foreach: FilteredVariants"> 1588 <div class="col-12 col-sm-6 col-md-3 mb-3"> 1589 <a class="color-black no-underline" data-bind="attr: { href: Link }"> 1590 <p class="fs0 font-weight-bold m-0" data-bind="text: Name"></p> 1591 <img class="img-fluid box-shadow my-1" data-bind="attr: { src: Image }" /> 1592 <div class="d-flex justify-content-center mt-2"> 1593 <div class="btn btn-primary">@Translate("VariantChooseProduct", "V&aelig;lg")</div> 1594 </div> 1595 </a> 1596 </div> 1597 </div> 1598 <div data-bind="visible: FilteredVariants().length == 0"> 1599 <p class="font-weight-bold mt-3 fs3">@Translate("VariantsNoResults", "Filtreringen gav ingen resultater")</p> 1600 </div> 1601 </div> 1602 </div> 1603 </div> 1604 1605 @SnippetStart("DataLayerOverwrites") 1606 <script> 1607 ecomm_pagetype = "Product"; 1608 ecomm_totalvalue = @GetString("Ecom:Product.Price.Price").Replace(".","").Replace(",","."); 1609 ecomm_prodid = "@GetString("Ecom:Product.ID")"; 1610 </script> 1611 @SnippetEnd("DataLayerOverwrites") 1612 1613 <script> 1614 var dataLayer = window.dataLayer || []; 1615 dataLayer.push({ 1616 'event': 'product', 1617 'ecommerce': { 1618 'detail': { 1619 'actionField': { 1620 'list': '@DataLayerParentGroups' 1621 }, 1622 'products': [{ 1623 'id': '@ProductID', 1624 'name': '@ProductName', 1625 'image': '@OgImage', 1626 'brand': '@BrandName', 1627 'variant': '@CurrentVariantName', 1628 'category': '@DataLayerParentGroup', 1629 'price': '@DataLayerPrice' 1630 }] 1631 } 1632 }, 1633 'page': { 1634 'type': 'product', 1635 'environment': 'production' 1636 } 1637 }); 1638 </script> 1639