0
Din indkøbskurv

Opdaterer kurv

stk. a

-
+

Din kurv i alt (ex. fragt)

Handel videre

Gå til kassen
Dankort VISA VISA Elektron American express Santander Mobilepay
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_cd03d32dbe654b1e9aea5fc97fbb3cf7.Execute() in D:\dynamicweb.net\Solutions\mobler.LIVE\Files\Templates\Designs\Mobler2018\eCom\Product\Product.cshtml:line 492
   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 @using System.Web 2 @using Mobler.Website.CustomModules.MoblerHelpers 3 @using System.Text.RegularExpressions 4 @using CampaignModule.Models 5 @using Dynamicweb.Core 6 @using Dynamicweb.Ecommerce.Products 7 @using Group = Dynamicweb.Ecommerce.Products.Group 8 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 9 10 @{ 11 var request = HttpContext.Current.Request; 12 string shopname = MoblerHelpers.GetShopName(); 13 string SelectPlaceholder = Translate("ShopSelectPlaceholder", "Indtast by, postnummer eller adresse"); 14 var shopInfo = MoblerHelpers.ShopInfo(); 15 int ShopPageId = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetInt("ShopPageId"); 16 var AllShops = Firstweb.Custom.CustomCode.Frontend.Helpers.Shops.GetAllShops(ShopPageId); 17 int AjaxCartPageId = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetInt("AjaxCartPageId"); 18 int CustomersAlsoSawPageId = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetInt("CustomersAlsoSawPageId"); 19 string relewiseRecommandationsEndpoint = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetString("RelewiseRecommandationsPageId"); 20 bool userIsAnonymous= Mobler.Website.CustomCode.RelewiseCustom.RelewiseConnectorSetting.IsAnonymous; 21 bool showRecommendations = Mobler.Website.CustomCode.RelewiseCustom.RelewiseConnectorSetting.ShowRecommendations; 22 string CartPage = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetString("CartPage"); 23 string VariantsEndpoint = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetString("VariantsUrl"); 24 string VariantDetailsEndpoint = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetString("VariantDetailsUrl"); 25 string BlackFridayTheme = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetString("BlackFridayTheme"); 26 string ProductID = GetString("Ecom:Product.ID"); 27 string GroupID = Firstweb.Custom.CustomCode.Frontend.Helpers.EcomGroups.GetProductDefaultShopGroupID(ProductID); //GetString("Ecom:Product.PrimaryOrFirstGroupID"); 28 string DefaultVariantID = GetString("Ecom:Product.DefaultVariantComboID"); 29 string ProductImage = MoblerHelpers.GetProductListImage(ProductID, DefaultVariantID); 30 string ProductName = GetString("Ecom:Product.Name"); 31 string ProductNumber = GetString("Ecom:Product.Number"); 32 string ProductCatalogLink = !String.IsNullOrEmpty(GetString("Ecom:Product:Field.ProductCatelog.Value.Clean")) ? GetString("Ecom:Product:Field.ProductCatelog.Value.Clean") : ""; 33 string VariantId = GetString("Ecom:Product.VariantID"); 34 string ShortDescription = GetString("Ecom:Product.ShortDescription"); 35 string LongDescription = GetString("Ecom:Product.LongDescription").Replace("||", "<br/>"); 36 string CurrentVariantName = GetString("Ecom:Product.SelectedVariantComboName"); 37 var FaqQuestions = MoblerHelpers.GetProductFAQs(ProductID, GroupID); 38 39 // Group Specific - Exclude Bed Accessories 40 bool excludeBedAccessories = GetBoolean("Ecom:Product.CategoryField.Senge.ExcludeBedAccessories.Value"); 41 42 43 Mobler.Website.CustomCode.Frontend.PayeverHelper payeverHelper = new Mobler.Website.CustomCode.Frontend.PayeverHelper(); 44 Mobler.Website.CustomCode.Models.PayeverWidget PayeverWidget = payeverHelper.GetPayeverWidgetInformation(); 45 46 string MetaDescription = GetString("Ecom:Product.MetaDescription"); 47 48 if (string.IsNullOrEmpty(MetaDescription)) 49 { 50 MetaDescription = Mobler.Website.CustomCode.Frontend.Helpers.Text.GetFirstLine(LongDescription.Replace("<br/>", " ")); 51 } 52 else 53 { 54 MetaDescription = ""; //Meta data description bliver sat af DW, hvis dette felt er udfyldt, så vi skal ikke opsætte noget. 55 } 56 57 var RelatedBlogs = Firstweb.Custom.CustomCode.Frontend.Helpers.Blogs.GetBlogsRelatedToProduct(ProductID); 58 bool NewItem = GetBoolean("Ecom:Product:Field.NewItem"); 59 DateTime NewItemExpiryDate = GetDate( "Ecom:Product:Field.NewItemExpiryDate" ); 60 bool LowPrice = GetBoolean("Ecom:Product:Field.Splash3"); 61 62 Mobler.Website.CustomCode.Frontend.ProductsDisplayVariant productsDisplayVariant = Mobler.Website.CustomCode.Frontend.ProductsDisplayVariant.Instance(); 63 64 bool ForSale = !GetBoolean("Ecom:Product:Field.NotForSaleOnline"); 65 string FirstImage = ""; 66 var Images = MoblerHelpers.GetProductImages(GetString("Ecom:Product.ID"), VariantId); 67 bool First = true; 68 bool FirstIndicator = true; 69 int IndicatorIncrementer = 0; 70 string ProductLink = GetString("Ecom:Product.Link.Clean"); 71 72 double ActualPrice = GetDouble("Ecom:Product.Price.Price"); 73 double spar = 0; 74 double price = 0; 75 double normalPrice = 0; 76 77 string priceFormatted = ""; 78 string sparFormatted = ""; 79 string normalPriceFormatted = ""; 80 81 string campaignColor = ""; 82 string campaignText = ""; 83 string campaignTextClean = ""; 84 string campaignDate = ""; 85 86 string campaignDateStart = ""; 87 string campaignDateEnd = ""; 88 89 bool CampaignActiveOnProduct = GetBoolean("CampaignModule:Product.CampaignActiveOnProduct"); 90 91 bool IsLocalWebshopProduct = (Mobler.Website.CustomCode.Frontend.Helper.IsLocalWebshop() && !GetBoolean("Ecom:Product:Field.SystemIsMasterShopProduct")); 92 93 94 if (!CampaignActiveOnProduct && !IsLocalWebshopProduct) 95 { 96 price = ActualPrice; 97 priceFormatted = MoblerHelpers.formatPrice(price); 98 } 99 else if (IsLocalWebshopProduct) 100 { 101 price = ActualPrice; 102 priceFormatted = MoblerHelpers.formatPrice(price); 103 104 normalPrice = GetDouble("Ecom:Product:Field.ForPris"); 105 normalPriceFormatted = MoblerHelpers.formatPrice(normalPrice); 106 107 spar = GetDouble("Ecom:Product:Field.Spar"); 108 sparFormatted = MoblerHelpers.formatPrice(spar); 109 110 bool SplashLwCombiPrice = GetBoolean("Ecom:Product:Field.SplashLwCombiPrice"); 111 DateTime SplashLwCombiPriceExpiryDate = GetDate("Ecom:Product:Field.SplashLwCombiPriceExpiryDate"); 112 113 if (SplashLwCombiPrice && (SplashLwCombiPriceExpiryDate == DateTime.MinValue || SplashLwCombiPriceExpiryDate > DateTime.Now)) 114 { 115 campaignTextClean = "KOMBI"; 116 } 117 118 119 } 120 else 121 { 122 normalPrice = GetDouble("CampaignModule:Product.CampaignProduct.NormalPrice"); 123 normalPriceFormatted = GetString("CampaignModule:Product.CampaignProduct.NormalPrice.FormattedRetail"); 124 125 price = GetDouble("CampaignModule:Product.CampaignProduct.CampaignPrice"); 126 priceFormatted = GetString("CampaignModule:Product.CampaignProduct.CampaignPrice.FormattedRetail"); 127 128 spar = GetDouble("CampaignModule:Product.CampaignProduct.DiscountAmount"); 129 sparFormatted = GetString("CampaignModule:Product.CampaignProduct.DiscountAmount.FormattedRetail"); 130 131 campaignColor = GetString("CampaignModule:Product.Campaign.Color"); 132 campaignTextClean = GetString("CampaignModule:Product.Campaign.Text"); 133 134 campaignDateStart = GetString("CampaignModule:Product.CampaignProduct.Campaign.Start"); 135 campaignDateEnd = GetString("CampaignModule:Product.CampaignProduct.Campaign.End"); 136 campaignText = $"{Translate("Campaign.BeforeDate.Text", "Gældende fra:")} {campaignDateStart} {Translate("Campaign.BeforeDate.Text2", "t.o.m.")} {campaignDateEnd}"; 137 } 138 139 string DataLayerPrice = ActualPrice.ToString().Replace(".", "").Replace(",", "."); 140 System.Web.HttpContext.Current.Items["OverrideOgTags"] = true; 141 string OgImage = "https://mobler.dk" + Images.FirstOrDefault(); 142 143 string TrimmedTeaser = Firstweb.Custom.CustomCode.Frontend.Helpers.JSFormatting.TrimLinebreaks(ShortDescription); 144 string TrimmedName = Firstweb.Custom.CustomCode.Frontend.Helpers.JSFormatting.TrimLinebreaks(ProductName); 145 146 var ParentGroups = Firstweb.Custom.CustomCode.Frontend.Helpers.EcomGroups.getBreadCrumbGroupList(GroupID, true); 147 var DataLayerParentGroup = ParentGroups.Last().Name; 148 List<string> DataLayerParentGroupStrings = ParentGroups.Select(group => group.Name).ToList(); 149 string DataLayerParentGroups = string.Join(" > ", DataLayerParentGroupStrings); 150 151 // Handle USPs on the product page 152 int uspPageId = 0; 153 string uspProductdetailLinkProductLevel = GetString("Ecom:Product:Field.uspproductdetaillink.Value.Clean"); 154 string uspProductdetailLinkGroupLevel = ParentGroups.Last().ProductGroupFieldValues.GetProductGroupFieldValue("uspproductdetaillink").Value.ToString(); 155 bool hasUspProductdetailLinkProductLevel = !string.IsNullOrEmpty(uspProductdetailLinkProductLevel); 156 bool hasUspProductdetailLinkGroupLevel = !string.IsNullOrEmpty(uspProductdetailLinkGroupLevel); 157 158 // Check if there's a product detail link on the product level 159 if (hasUspProductdetailLinkProductLevel) 160 { 161 Int32.TryParse(uspProductdetailLinkProductLevel.Substring(uspProductdetailLinkProductLevel.LastIndexOf('=') + 1), out uspPageId); 162 } 163 // Check if there's a product detail link on the group level 164 else if (hasUspProductdetailLinkGroupLevel) 165 { 166 Int32.TryParse(uspProductdetailLinkGroupLevel.Substring(uspProductdetailLinkGroupLevel.LastIndexOf('=') + 1), out uspPageId); 167 } 168 169 // Handle display of product catalogue image, if it exists on the group level 170 string productCatalogueImage = ParentGroups.Last().ProductGroupFieldValues.GetProductGroupFieldValue("ProductCatalogueImage").Value.ToString(); 171 172 // Handle USP Icons and Text 173 string usp1Icon = ParentGroups.Last().ProductGroupFieldValues.GetProductGroupFieldValue("usp_1_icon").Value.ToString(); 174 if (usp1Icon == "") 175 { 176 usp1Icon = "piggy-bank"; 177 } 178 string usp2Icon = ParentGroups.Last().ProductGroupFieldValues.GetProductGroupFieldValue("usp_2_icon").Value.ToString(); 179 if (usp2Icon == "") 180 { 181 usp2Icon = "truck"; 182 } 183 string usp3Icon = ParentGroups.Last().ProductGroupFieldValues.GetProductGroupFieldValue("usp_3_icon").Value.ToString(); 184 if (usp3Icon == "") 185 { 186 usp3Icon = "calendar"; 187 } 188 189 string usp1IconText = Translate("Product.USPIcon.One.Title", "Prismatch"); 190 string usp2IconText = Translate("Product.USPIcon.Two.Title", "Fri kantstenslevering*"); 191 string usp3IconText = Translate("Product.USPIcon.Three.Title", "Rentefri finansiering"); 192 string usp1IconTextFromField = ParentGroups.Last().ProductGroupFieldValues.GetProductGroupFieldValue("uspicontext1").Value.ToString(); 193 string usp2IconTextFromField = ParentGroups.Last().ProductGroupFieldValues.GetProductGroupFieldValue("uspicontext2").Value.ToString(); 194 string usp3IconTextFromField = ParentGroups.Last().ProductGroupFieldValues.GetProductGroupFieldValue("uspicontext3").Value.ToString(); 195 196 if (!string.IsNullOrEmpty(usp1IconTextFromField)) 197 { 198 usp1IconText = usp1IconTextFromField; 199 } 200 if (!string.IsNullOrEmpty(usp2IconTextFromField)) 201 { 202 usp2IconText = usp2IconTextFromField; 203 } 204 if (!string.IsNullOrEmpty(usp3IconTextFromField)) 205 { 206 usp3IconText = usp3IconTextFromField; 207 } 208 209 string usp1IconClass = "fa-solid fa-" + usp1Icon + " fs3"; 210 string usp2IconClass = "fa-solid fa-" + usp2Icon + " fs3"; 211 string usp3IconClass = "fa-solid fa-" + usp3Icon + " fs3"; 212 213 string seeProductInStore = ""; 214 if (!String.IsNullOrEmpty(GetString("Ecom:Product:Field.seeproductinstore.Value.Clean"))) 215 { 216 seeProductInStore = GetString("Ecom:Product:Field.seeproductinstore.Value.Clean"); 217 } 218 219 string ShowOnPageUrl = ""; 220 string GetCartEndpoint = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetString("GetCartJson"); 221 222 string QuickDeliveryColor = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetString("QuickDeliveryColor"); 223 string QuickDeliveryDescription = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetString("QuickDeliveryDescription"); 224 string NormalDeliveryDescription = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetString("NormalDeliveryDescription"); 225 string BrandName = GetString("Ecom:Product:Field.Maerkevarer.Value.Clean"); 226 string DeliveryTime = Translate("DeliveryTime." + BrandName, "Gns. leveringstid 3-12 dage"); 227 bool HideDelivery = DeliveryTime == "Skjul"; 228 string DeliveryColor = "#00AB5D"; 229 bool QuickDelivery = GetBoolean("Ecom:Product:Field.QuickDelivery.Value.Clean"); 230 string CustomDelivery = GetString("Ecom:Product:Field.CustomDeliveryTime.Value.Clean"); 231 if (QuickDelivery) 232 { 233 DeliveryColor = QuickDeliveryColor; 234 DeliveryTime = Translate("DeliveryTime.QuickDelivery", "Ekstra hurtig levering"); 235 } 236 else if (!String.IsNullOrEmpty(CustomDelivery)) 237 { 238 DeliveryTime = CustomDelivery; 239 } 240 string DeliveryFontWeightModifier = QuickDelivery ? "font-weight-bold" : ""; 241 bool DisplayAverageDeliveryTime = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetBoolean("DisplayAverageDeliveryTime"); 242 243 double CostPrice = GetDouble("Ecom:Product:Field.FirstwebCostPrice.Value.Raw"); 244 string DailyPriceBackgroundColor = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetString("AktuelDagsprisBackgroundColor"); 245 string DailyPriceTextColor = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetString("AktuelDagsprisTextColor"); 246 string EAN = GetString("Ecom:Product:Field.FirstEan.Value"); 247 string productionDescription = GetString("Ecom:Product:Field.FirstwebProductionDescription"); 248 249 Mobler.Website.CustomCode.RelewiseCustom.RelewiseCaller relewiseCaller = new Mobler.Website.CustomCode.RelewiseCustom.RelewiseCaller(); 250 relewiseCaller.TrackProductView(ProductID, VariantId); 251 bool hasVariants = false; 252 253 string purchasedWithStyle = Mobler.Website.CustomCode.Frontend.Helper.IsLocalWebshop() ? "display:none" : ""; 254 } 255 256 @SnippetStart("PricesContainer") 257 <div class="row"> 258 <div class="col-12 col-sm-12 offset-sm-0 d-flex justify-content-center justify-content-lg-start flex-column"> 259 @if (GetLoop("Co3VariantCombinations").Count > 0) { 260 hasVariants = true; 261 // Only show the extra price at top, if we have variants 262 <div class="d-flex flex-wrap flex-column justify-content-end border-grey border-bottom-0 p-4"> 263 <p class="price font-weight-bold m-0"> 264 <span class="unimportant-hidden" data-bind="css: { 'd-inline': SplashType() == 1 }">@Translate("ProductNow", "NU") </span> 265 <span class="total-price" data-bind="text: Price"></span> 266 </p> 267 @if (campaignTextClean == "KOMBI") 268 { 269 <div class="d-none" data-bind="setInitValue: { observable: SplashType, value: 5 }"></div> 270 <div class="d-none" data-bind="setInitValue: { observable: BeforePriceDouble, value: @normalPrice }"></div> 271 <div class="d-none" data-bind="setInitValue: { observable: BeforePrice, value: '@normalPriceFormatted' }"></div> 272 <div class="d-none" data-bind="setInitValue: { observable: SavingDouble, value: @spar }"></div> 273 <div class="d-none" data-bind="setInitValue: { observable: Saving, value: '@sparFormatted' }"></div> 274 } 275 else if (spar > 0) 276 { 277 <div class="d-none" data-bind="setInitValue: { observable: SplashType, value: 1 }"></div> 278 <div class="d-none" data-bind="setInitValue: { observable: BeforePriceDouble, value: @normalPrice }"></div> 279 <div class="d-none" data-bind="setInitValue: { observable: BeforePrice, value: '@normalPriceFormatted' }"></div> 280 <div class="d-none" data-bind="setInitValue: { observable: SavingDouble, value: @spar }"></div> 281 <div class="d-none" data-bind="setInitValue: { observable: Saving, value: '@sparFormatted' }"></div> 282 } 283 else if (NewItem) 284 { 285 if (NewItemExpiryDate > DateTime.Now) 286 { 287 <div class="d-none" data-bind="setInitValue: { observable: SplashType, value: 2 }"></div> 288 } 289 } 290 else if (LowPrice) 291 { 292 <div class="d-none" data-bind="setInitValue: { observable: SplashType, value: 3 }"></div> 293 } 294 else if (CostPrice > 0) 295 { 296 <div class="d-none" data-bind="setInitValue: { observable: SplashType, value: 4 }"></div> 297 } 298 299 <div class="w-100 unimportant-hidden" data-bind="css: { 'd-flex': SplashType() == 1 || SplashType() == 5}"> 300 <p class="color-subtle fs0 m-0 text-uppercase mr-3">@Translate("PriceBefore", "Før") <span class="before-price" data-bind="text: BeforePrice"></span></p> 301 <p class="splash fs0 text-uppercase m-0 px-2">@Translate("PriceSaving", "Spar") <span class="total-saving" data-bind="text: Saving"></span></p> 302 </div> 303 304 <div class="price-info fs-s mt-4"> 305 @if (excludeBedAccessories) 306 { 307 <p class="price-info-text color-subtle mb-1 js-update-price-info-text">@Translate("Ecom:Product.Pricing.Excludes.Beds", "Prisen er ekskl. ben og gavl.")</p> 308 } 309 @if (hasVariants) 310 { 311 <div class="variant-price-disclaimer color-subtle mb-1">@Translate("VariantPriceDisclaimer", "Prisen kan variere efter materialevalg")</div> 312 } 313 </div> 314 315 @if (!string.IsNullOrEmpty(campaignDateStart) && !string.IsNullOrEmpty(campaignDateEnd) && !string.IsNullOrEmpty(campaignText)) 316 { 317 <div class="d-none" data-bind="setInitValue: { observable: CampaignText, value: '@campaignText' }"></div> 318 <div class="price-info fs-xs"> 319 <p class="mb-1"><span class="dot dot-yellow"></span> <span data-bind="text: CampaignText"></span></p> 320 </div> 321 } 322 else 323 { 324 <div class="d-none" data-bind="setInitValue: { observable: CampaignText, value: '' }"></div> 325 } 326 @* <p data-bind="text: CampaignText"></p> *@ 327 </div> 328 } 329 330 @if (GetLoop("Co3VariantCombinations").Count > 0) 331 { 332 <div class="variant-selectors"> 333 @{ 334 hasVariants = true; 335 var VariantGroupsWithMultipleOptions = GetLoop("VariantGroups").Where(x => x.GetLoop("VariantAvailableOptions").Count > 1); 336 int VariantGroupCount = VariantGroupsWithMultipleOptions.Count(); 337 int VariantCombinationsCount = GetLoop("Co3VariantCombinations").Count; 338 int PossibleVariantCombinations = 1; 339 } 340 @foreach (var VG in GetLoop("VariantGroups")) 341 { 342 PossibleVariantCombinations *= VG.GetLoop("VariantAvailableOptions").Count; 343 } 344 @if (VariantGroupCount == 1) 345 { 346 var RelevantVariantGroup = VariantGroupsWithMultipleOptions.FirstOrDefault(); 347 var SelectedVariant = RelevantVariantGroup.GetLoop("VariantAvailableOptions").Where(x => x.GetBoolean("Ecom:VariantOption.Selected")).FirstOrDefault(); 348 int variantCount = RelevantVariantGroup.GetLoop("VariantAvailableOptions").Count; 349 var variantSelectorClass = "variant-options bg-white"; 350 if (RelevantVariantGroup.GetString("Ecom:VariantGroup.Label").ToLower().Contains("farve") && variantCount <= 5) 351 { 352 variantSelectorClass = "variant-selector__color-picker d-flex flex-wrap"; 353 } 354 string variantInfoText = Translate("VariantInfo-" + RelevantVariantGroup.GetString("Ecom:VariantGroup.Label"), "Variant Info Text"); 355 string variantInfoTextEscapedLineBreaks = variantInfoText.Replace(System.Environment.NewLine, "<br />"); 356 357 <div class="position-relative border-grey p-4"> 358 <div class="variant-selector__header"> 359 <div class="variant-selector__header-inner"> 360 <span class="font-weight-bold fs0">@RelevantVariantGroup.GetString("Ecom:VariantGroup.Label")</span> 361 <div class="variant-selector__header-choices"> 362 <span class="variantoptionname fs0" data-bind="text: SelectedVariantOption0">@SelectedVariant.GetString("Ecom:VariantOption.Name")</span> 363 </div> 364 </div> 365 <span class="variant-selector__toggle" data-bind="click: ToggleVariantInfo.bind($data, '@variantInfoTextEscapedLineBreaks')"> 366 <span class="fas fa-info-circle"></span> 367 </span> 368 </div> 369 370 @if (!RelevantVariantGroup.GetString("Ecom:VariantGroup.Label").ToLower().Contains("farve") || variantCount > 5) 371 { 372 <div class="variant-dropdown border-grey p-2 mt-3 d-flex justify-content-between align-items-center pointer js-variant-dropdown"> 373 <p class="m-0"><span data-bind="text: SelectedVariantOption0">@SelectedVariant.GetString("Ecom:VariantOption.Name")</span></p> 374 <i class="fas fa-chevron-down"></i> 375 </div> 376 } 377 378 <div class="@variantSelectorClass"> 379 @foreach (LoopItem Variant in RelevantVariantGroup.GetLoop("VariantAvailableOptions")) 380 { 381 LoopItem VariantCombination = GetLoop("Co3VariantCombinations").FirstOrDefault(x => x.GetString("Ecom:VariantCombination.VariantID").ToString().Contains(Variant.GetString("Ecom:VariantOption.ID"))); 382 string VariantName = Variant.GetString("Ecom:VariantOption.Name"); 383 string VariantIdentifier = Variant.GetString("Ecom:VariantOption.ID"); 384 string VariantLink = VariantCombination.GetString("Ecom:VariantCombination.Link.Clean"); 385 string VariantPreview = String.Empty; 386 var ObservableToSet = "SelectedVariantOption0"; 387 var ObservableToSetId = "SelectedVariantOptionId0"; 388 bool ShowPreview = RelevantVariantGroup.GetString("Ecom:VariantGroup.Name").ToLower().Contains("farve") || RelevantVariantGroup.GetString("Ecom:VariantGroup.Name").ToLower().Contains("materiale"); 389 390 List<string> variantCombinationVariantIds = GetLoop("Co3VariantCombinations").Select(p => p.GetString("Ecom:VariantCombination.VariantID")).ToList(); 391 string variantOptionColor = Variant.GetString("Ecom:VariantOption.ColorHex"); 392 string variantIdWithColorOptionId = variantCombinationVariantIds.FirstOrDefault(vid => vid.Contains(VariantIdentifier)); 393 394 if (!String.IsNullOrEmpty(Variant.GetString("Ecom:VariantOption.ImgSmall.Clean")) && ShowPreview) 395 { 396 if (Variant.GetString("Ecom:VariantOption.ImgSmall.Clean").StartsWith("#")) 397 { 398 VariantPreview = "style= \"background-color: " + Variant.GetString("Ecom:VariantOption.ImgSmall.Clean") + ";\""; 399 } 400 else 401 { 402 VariantPreview = "style=\"background-image: url('" + Variant.GetString("Ecom:VariantOption.ImgSmall.Clean") + "');\""; 403 } 404 } 405 406 if (!RelevantVariantGroup.GetString("Ecom:VariantGroup.Label").ToLower().Contains("farve") || variantCount > 5) 407 { 408 <div class="option pointer color-primary d-flex w-100 p-2 bg-grey" data-bind="click: UpdateVariantAndSetObservable.bind($data, '@VariantIdentifier', @ObservableToSet, '@VariantName', @ObservableToSetId)"> 409 @if (!String.IsNullOrEmpty(VariantPreview)) 410 { 411 <span class="option-preview mr-2" @VariantPreview></span> 412 } 413 <span>@VariantName</span> 414 </div> 415 <div class="d-none" data-bind="setInitValue: { observable: @ObservableToSet, value: '@SelectedVariant.GetString("Ecom:VariantOption.Name")' }"></div> 416 <div class="d-none" data-bind="setInitValue: { observable: @ObservableToSetId, value: '@SelectedVariant.GetString("Ecom:VariantOption.ID")' }"></div> 417 } 418 else 419 { 420 if (variantIdWithColorOptionId.IsNullOrEmpty() == false) 421 { 422 bool selectedVariant = Variant.GetBoolean("Ecom:VariantOption.Selected"); 423 string selectedVariantClass = ""; 424 if (selectedVariant) 425 { 426 selectedVariantClass = "selected"; 427 } 428 429 <div id="@VariantIdentifier" class="product-item__variant large @selectedVariantClass" style="background-color: @variantOptionColor;" data-bind="click: UpdateVariantAndSetObservable.bind($data, '@VariantIdentifier', @ObservableToSet, '@VariantName', @ObservableToSetId)"></div> 430 <div class="d-none" data-bind="setInitValue: { observable: @ObservableToSet, value: '@SelectedVariant.GetString("Ecom:VariantOption.Name")' }"></div> 431 <div class="d-none" data-bind="setInitValue: { observable: @ObservableToSetId, value: '@SelectedVariant.GetString("Ecom:VariantOption.ID")' }"></div> 432 } 433 } 434 } 435 </div> 436 </div> 437 } 438 else if (PossibleVariantCombinations == VariantCombinationsCount) 439 { 440 Dictionary<string, string> CurrentlySelectedVariantOptions = new Dictionary<string, string>(); 441 foreach (var VG in GetLoop("VariantGroups")) 442 { 443 foreach (var VO in VG.GetLoop("VariantAvailableOptions").Where(x => x.GetBoolean("Ecom:VariantOption.Selected"))) 444 { 445 CurrentlySelectedVariantOptions.Add(VG.GetString("Ecom:VariantGroup.Name"), VO.GetString("Ecom:VariantOption.ID")); 446 } 447 } 448 int VGLoopCounter = 0; 449 foreach (var VG in GetLoop("VariantGroups")) 450 { 451 List<LoopItem> RelevantVariantCombinations = new List<LoopItem>(); 452 var VariantCombinationLink = GetLoop("Co3VariantCombinations"); 453 var SelectedVariant = VG.GetLoop("VariantAvailableOptions").FirstOrDefault(x => x.GetBoolean("Ecom:VariantOption.Selected")); 454 var ObservableToSet = "SelectedVariantOption" + VGLoopCounter.ToString(); 455 var ObservableToSetId = "SelectedVariantOptionId" + VGLoopCounter.ToString(); 456 int variantCount = VG.GetLoop("VariantAvailableOptions").Count; 457 458 VGLoopCounter++; 459 460 var variantSelectorClass = "variant-options bg-white"; 461 if (!VG.GetString("Ecom:VariantGroup.ID").ToLower().Contains("fasthed")) 462 { 463 if (VG.GetString("Ecom:VariantGroup.Label").ToLower().Contains("farve") && variantCount <= 5) 464 { 465 variantSelectorClass = "variant-selector__color-picker d-flex flex-wrap"; 466 } 467 else if (VG.GetString("Ecom:VariantGroup.Label").ToLower().Contains("farve") && variantCount > 5) 468 { 469 variantSelectorClass = "variant-options bg-white"; 470 } 471 else 472 { 473 variantSelectorClass = "radio-button d-flex flex-column"; 474 } 475 } 476 477 foreach (var VC in VariantCombinationLink) 478 { 479 var Add = true; 480 foreach (var KVP in CurrentlySelectedVariantOptions.Where(s => s.Key != VG.GetString("Ecom:VariantGroup.Name"))) 481 { 482 if (!VC.GetString("Ecom:VariantCombination.VariantID").ToString().Contains(KVP.Value)) 483 { 484 Add = false; 485 } 486 } 487 if (Add) 488 { 489 RelevantVariantCombinations.Add(VC); 490 } 491 } 492 <div class="d-none" data-bind="setInitValue: { observable: @ObservableToSet, value: '@SelectedVariant.GetString("Ecom:VariantOption.Name")' }"></div> 493 <div class="d-none" data-bind="setInitValue: { observable: @ObservableToSetId, value: '@SelectedVariant.GetString("Ecom:VariantOption.ID")' }"></div> 494 495 string variantInfoText = Translate("VariantInfo-" + VG.GetString("Ecom:VariantGroup.Label"), "Variant Info Text"); 496 string variantInfoTextEscapedLineBreaks = variantInfoText.Replace(System.Environment.NewLine, "<br />"); 497 498 <div class="variant-selector position-relative border-grey border-bottom-0 p-4" data-variantgroupid="@VG.GetString("Ecom:VariantGroup.ID")"> 499 <div class="variant-selector__header"> 500 <div class="variant-selector__header-inner"> 501 <span class="font-weight-bold fs0">@VG.GetString("Ecom:VariantGroup.Label")</span> 502 <div class="variant-selector__header-choices"> 503 <span class="variantoptionname fs0" data-bind="text: @ObservableToSet">@SelectedVariant.GetString("Ecom:VariantOption.Name")</span> 504 </div> 505 </div> 506 <span class="variant-selector__toggle" data-bind="click: ToggleVariantInfo.bind($data, '@variantInfoTextEscapedLineBreaks')"> 507 <span class="fas fa-info-circle"></span> 508 </span> 509 </div> 510 @if (VG.GetString("Ecom:VariantGroup.Label").ToLower().Contains("fasthed") || VG.GetString("Ecom:VariantGroup.Label").ToLower().Contains("farve") && variantCount > 5) 511 { 512 <div class="variant-dropdown border-grey p-2 mt-3 d-flex justify-content-between align-items-center pointer js-variant-dropdown"> 513 <p class="m-0"><span data-bind="text: @ObservableToSet">@SelectedVariant.GetString("Ecom:VariantOption.Name")</span></p> 514 <i class="fas fa-chevron-down"></i> 515 </div> 516 } 517 518 <div class="@variantSelectorClass"> 519 @foreach (var VO in VG.GetLoop("VariantAvailableOptions")) 520 { 521 var VariantCombination = RelevantVariantCombinations.Where(vc => vc.GetString("Ecom:VariantCombination.VariantID").ToString().Contains(VO.GetString("Ecom:VariantOption.ID"))).FirstOrDefault(); 522 string VariantLink = VariantCombination.GetString("Ecom:VariantCombination.Link.Clean"); 523 string VariandOptionId = VariantCombination.GetString("Ecom:VariantCombination.VariantID"); 524 string VariantPreview = String.Empty; 525 string VOName = VO.GetString("Ecom:VariantOption.Name"); 526 string VOId = VO.GetString("Ecom:VariantOption.ID"); 527 bool ShowPreview = VG.GetString("Ecom:VariantGroup.Name").ToString().ToLower().Contains("farve") || VG.GetString("Ecom:VariantGroup.Name").ToString().ToLower().Contains("materiale") ? true : false; 528 529 List<string> variantCombinationVariantIds = GetLoop("Co3VariantCombinations").Select(p => p.GetString("Ecom:VariantCombination.VariantID")).ToList(); 530 string variantOptionColor = VO.GetString("Ecom:VariantOption.ColorHex"); 531 string variantIdWithColorOptionId = variantCombinationVariantIds.FirstOrDefault(vid => vid.Contains(VariandOptionId)); 532 533 if (!String.IsNullOrEmpty(VO.GetString("Ecom:VariantOption.ImgSmall.Clean")) && ShowPreview) 534 { 535 if (VO.GetString("Ecom:VariantOption.ImgSmall.Clean").StartsWith("#")) 536 { 537 VariantPreview = "style= \"background-color: " + VO.GetString("Ecom:VariantOption.ImgSmall.Clean") + ";\""; 538 } 539 else 540 { 541 VariantPreview = "style=\"background-image: url('" + VO.GetString("Ecom:VariantOption.ImgSmall.Clean") + "');\""; 542 } 543 } 544 545 if (VG.GetString("Ecom:VariantGroup.ID").ToLower().Contains("fasthed") || VG.GetString("Ecom:VariantGroup.Name").ToLower().Contains("farve") && variantCount > 5) 546 { 547 <div class="option d-flex w-100 p-2 bg-grey color-primary pointer" data-bind="click: UpdateVariantAndSetObservable.bind($data, '@VOId', @ObservableToSet, '@VOName', @ObservableToSetId)"> 548 @if (!String.IsNullOrEmpty(VariantPreview)) 549 { 550 <span class="option-preview mr-2" @VariantPreview></span> 551 } 552 @VOName 553 </div> 554 } 555 else if (VG.GetString("Ecom:VariantGroup.Name").ToLower().Contains("farve") && variantCount <= 5) 556 { 557 bool selectedVariant = VO.GetBoolean("Ecom:VariantOption.Selected"); 558 string selectedVariantClass = ""; 559 if (selectedVariant) 560 { 561 selectedVariantClass = "selected"; 562 } 563 564 if (variantIdWithColorOptionId.IsNullOrEmpty() == false) 565 { 566 <div id="@VOId" class="variantToggle product-item__variant large @selectedVariantClass" style="background-color: @variantOptionColor;" data-bind="click: UpdateVariantAndSetObservable.bind($data, '@VOId', @ObservableToSet, '@VOName', @ObservableToSetId, $element)"><i class="fa-solid fa-check"></i></div> 567 } 568 } 569 else if (!VG.GetString("Ecom:VariantGroup.ID").ToLower().Contains("fasthed") || VG.GetString("Ecom:VariantGroup.Name").ToLower().Contains("farve")) 570 { 571 bool selectedVariant = VO.GetBoolean("Ecom:VariantOption.Selected"); 572 string selectedVariantClass = ""; 573 if (selectedVariant) 574 { 575 selectedVariantClass = "selected"; 576 } 577 578 <div id="@VOId" class="variantToggle product-item__variant--radiobutton @selectedVariantClass mb-2" data-bind="click: UpdateVariantAndSetObservable.bind($data, '@VOId', @ObservableToSet, '@VOName', @ObservableToSetId, $element)"> 579 <span class="radiobutton"></span>@VOName 580 </div> 581 } 582 } 583 </div> 584 </div> 585 } 586 } 587 else if (GetLoop("VariantGroups").Any(x => x.GetString("Ecom:VariantGroup.Name").ToString().ToLower().Contains("farve")) && GetLoop("VariantGroups").Any(x => x.GetString("Ecom:VariantGroup.Name").ToString().ToLower().Contains("materiale"))) 588 { 589 <div class="mt-3"> 590 <p class="mb-1">@Translate("CurrentDesignName", "Valgte design: ")</p> 591 <p class="font-weight-bold">@CurrentVariantName</p> 592 </div> 593 <div class="d-flex"> 594 <div class="btn btn-primary" data-bind="click: ToggleVariantPicker">@Translate("ChooseNewDesign", "V&aelig;lg design")</div> 595 </div> 596 } 597 else 598 { 599 var SelectedVariantId = GetString("Ecom:Product.VariantID"); 600 var SelectedVariant = GetLoop("Co3VariantCombinations").Where(x => x.GetString("Ecom:VariantCombination.VariantID") == SelectedVariantId).FirstOrDefault(); 601 var SelectedVariantName = ""; 602 if (SelectedVariant != null) 603 { 604 SelectedVariantName = SelectedVariant.GetString("Ecom:VariantCombination.VariantText"); 605 } 606 <div class="d-none" data-bind="setInitValue: { observable: SelectedVariantOption0, value: '@SelectedVariantName' }"></div> 607 <div class="d-none" data-bind="setInitValue: { observable: SelectedVariantOptionId0, value: '@SelectedVariantId' }"></div> 608 609 <div class="position-relative"> 610 <div class="variant-dropdown p-2 box-shadow mt-3 d-flex justify-content-between align-items-center pointer js-variant-dropdown"> 611 <p class="m-0"><span class="font-weight-bold">@Translate("FallbackVariantsText", "VARIANTER")</span> - <span data-bind="text: SelectedVariantOption0">@SelectedVariantName</span></p> 612 <i class="fas fa-chevron-down"></i> 613 </div> 614 <div class="variant-options bg-white"> 615 @foreach (var Variant in GetLoop("Co3VariantCombinations")) 616 { 617 string VariantName = Variant.GetString("Ecom:VariantCombination.VariantText"); 618 string VCId = Variant.GetString("Ecom:VariantCombination.VariantID"); 619 <div class="option color-primary pointer d-block p-2 bg-grey" data-bind="click: UpdateVariantAndSetObservable.bind($data, '@VCId', SelectedVariantOption0, '@VariantName', SelectedVariantOptionId0)">@VariantName</div> 620 } 621 </div> 622 </div> 623 } 624 </div> 625 } 626 627 @if (GetInteger("Ecom:Product.RelatedCount") > 0) 628 { 629 <div class="optionalselectors position-relative border-grey border-bottom-0 p-4"> 630 <div class="optional-selectors__header"> 631 <span class="font-weight-bold fs0">@Translate("Tilvalg", "Tilvalg")</span> 632 <span class="variant-selector__toggle" data-bind="click: ToggleOptionalInfo"> 633 <span class="fas fa-info-circle"></span> 634 </span> 635 </div> 636 <div class="optional-selectors__body"> 637 @foreach (LoopItem relatedGroup in GetLoop("ProductRelatedGroups").Where(g => g.GetLoop("Products").Count > 0)) 638 { 639 string groupName = relatedGroup.GetString("Ecom:Product:RelatedGroup.Name"); 640 string groupNameInLowerCase = groupName.ToLower().Replace(" ", "-"); 641 642 <div class="optionalselectors--selector d-flex align-items-center mb-4 position-relative js-optional-selector" data-group-name="@groupNameInLowerCase"> 643 <div class="optionalselectors--selector__label u-inline-block d-flex"> 644 @groupName 645 <span class="optionalselector-remove js-optional-selector-remove optionalselector-remove__@groupNameInLowerCase d-none" data-bind="click: RemoveOptionalProduct"><i class="fa-solid fa-circle-xmark"></i></span> 646 </div> 647 <div class="variant-dropdown border-grey p-2 d-flex justify-content-between align-items-center pointer js-variant-dropdown js-optional-dropdown"> 648 <p class="m-0"><span>@Translate("Vælg", "Vælg")</span></p> 649 <svg class="svg-inline--fa fa-chevron-down fa-w-14" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="chevron-down" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" data-fa-i2svg=""><path fill="currentColor" d="M207.029 381.476L12.686 187.132c-9.373-9.373-9.373-24.569 0-33.941l22.667-22.667c9.357-9.357 24.522-9.375 33.901-.04L224 284.505l154.745-154.021c9.379-9.335 24.544-9.317 33.901.04l22.667 22.667c9.373 9.373 9.373 24.569 0 33.941L240.971 381.476c-9.373 9.372-24.569 9.372-33.942 0z"></path></svg><!-- <i class="fas fa-chevron-down"></i> Font Awesome fontawesome.com --> 650 </div> 651 <div class="variant-options bg-white"> 652 @foreach (LoopItem product in relatedGroup.GetLoop("Products")) 653 { 654 string optionalProductId = product.GetString("Ecom:Product.ID"); 655 string optionalProductName = product.GetString("Ecom:Product.Name"); 656 string optionalProductPrice = MoblerHelpers.formatPrice(product.GetString("Ecom:Product.Price.PriceWithVAT.Value")); 657 string optionalProductPriceUnformatted = product.GetString("Ecom:Product.Price.Price.Value"); 658 string optionalProductPriceBefore = product.GetString("CampaignModule:Product.CampaignProduct.NormalPrice"); 659 string optionalProductPriceDiscount = product.GetString("CampaignModule:Product.CampaignProduct.DiscountAmount.FormattedRetail"); 660 string optionalProductDiscountText = ""; 661 if (!String.IsNullOrEmpty(optionalProductPriceDiscount)) 662 { 663 optionalProductDiscountText = "(SPAR: " + optionalProductPriceDiscount + ")"; 664 } 665 string optionalProductVariantId = product.GetString("Ecom:Product.VariantID"); 666 string optionalProductVariantText = product.GetString("Ecom:Product.VariantText"); 667 668 <div class="option d-flex w-100 p-2 bg-grey color-primary pointer" id="@optionalProductId@optionalProductVariantId" data-bind="click: UpdateOptionalProduct.bind($data, '@optionalProductId', '@optionalProductVariantId', '@optionalProductName', '@optionalProductVariantText', '@optionalProductPrice', @optionalProductPriceUnformatted, '@optionalProductPriceBefore', '@optionalProductPriceDiscount', '@groupNameInLowerCase')"> 669 @optionalProductName @optionalProductVariantText - @optionalProductPrice @optionalProductDiscountText 670 </div> 671 } 672 </div> 673 </div> 674 } 675 </div> 676 </div> 677 } 678 679 <div class="d-flex flex-wrap flex-column justify-content-end border-grey p-4"> 680 @if (ForSale) 681 { 682 <div class="addtocart-price"> 683 <div class="d-flex align-items-center"> 684 <div class="d-flex justify-content-between w-100"> 685 <div class="quantity-controls d-flex align-items-center"> 686 <div class="control minus" data-bind="click: DecreaseQuantity"> 687 - 688 </div> 689 <input type="text" name="Quantity" value="1" data-bind="value: Quantity"/> 690 <div class="control plus" data-bind="click: IncrementQuantity"> 691 + 692 </div> 693 </div> 694 @{ 695 string addToCartButtonClass = BlackFridayTheme == "True" ? "btn-black-friday bf-bg-black" : "brand-primary-outline font-weight-bold"; 696 } 697 <p class="btn @addToCartButtonClass add-to-cart m-0 d-flex align-items-center px-4" data-bind="click: AddToCart.bind($data, '@DataLayerPrice')"> 698 @Translate("ProductAddToCart", "L&aelig;g i kurv") 699 </p> 700 </div> 701 </div> 702 <div class="d-flex flex-wrap flex-column justify-content-between mt-4 unimportant-hidden"> 703 <p class="price font-weight-bold m-0"> 704 <span class="unimportant-hidden" data-bind="css: { 'd-inline': SplashType() == 1 }">@Translate("ProductNow", "NU") </span> 705 <span class="total-price" data-bind="text: Price"></span> 706 <span id="priceWithoutAddons" class="unimportant-hidden" data-bind="text: PriceDouble"></span> 707 </p> 708 @if (campaignTextClean == "KOMBI") 709 { 710 <div class="d-none" data-bind="setInitValue: { observable: SplashType, value: 5 }"></div> 711 <div class="d-none" data-bind="setInitValue: { observable: BeforePriceDouble, value: @normalPrice }"></div> 712 <div class="d-none" data-bind="setInitValue: { observable: BeforePrice, value: '@normalPriceFormatted' }"></div> 713 <div class="d-none" data-bind="setInitValue: { observable: SavingDouble, value: @spar }"></div> 714 <div class="d-none" data-bind="setInitValue: { observable: Saving, value: '@sparFormatted' }"></div> 715 } 716 else if (spar > 0) 717 { 718 <div class="d-none" data-bind="setInitValue: { observable: SplashType, value: 1 }"></div> 719 <div class="d-none" data-bind="setInitValue: { observable: BeforePriceDouble, value: @normalPrice }"></div> 720 <div class="d-none" data-bind="setInitValue: { observable: BeforePrice, value: '@normalPriceFormatted' }"></div> 721 <div class="d-none" data-bind="setInitValue: { observable: SavingDouble, value: @spar }"></div> 722 <div class="d-none" data-bind="setInitValue: { observable: Saving, value: '@sparFormatted' }"></div> 723 } 724 else if (NewItem) 725 { 726 if (NewItemExpiryDate > DateTime.Now) 727 { 728 <div class="d-none" data-bind="setInitValue: { observable: SplashType, value: 2 }"></div> 729 } 730 } 731 else if (LowPrice) 732 { 733 <div class="d-none" data-bind="setInitValue: { observable: SplashType, value: 3 }"></div> 734 } 735 else if (CostPrice > 0) 736 { 737 <div class="d-none" data-bind="setInitValue: { observable: SplashType, value: 4 }"></div> 738 } 739 740 <div class="w-100 unimportant-hidden" data-bind="css: { 'd-flex': SplashType() == 1 || SplashType() == 5}"> 741 <p class="color-subtle fs0 m-0 text-uppercase mr-3">@Translate("PriceBefore", "Før") <span class="before-price" data-bind="text: BeforePrice"></span></p> 742 <p class="splash fs0 text-uppercase m-0 px-2">@Translate("PriceSaving", "Spar") <span class="total-saving" data-bind="text: Saving"></span></p> 743 </div> 744 745 <div class="price-info fs-s mt-4"> 746 @if (excludeBedAccessories) 747 { 748 <p class="mb-1 color-subtle price-info-text js-update-price-info-text">@Translate("Ecom:Product.Pricing.Excludes.Beds", "Prisen er ekskl. ben og gavl.")</p> 749 } 750 @if (hasVariants) 751 { 752 <div class="variant-price-disclaimer color-subtle fs-s mb-1">@Translate("VariantPriceDisclaimer", "Prisen kan variere efter materialevalg")</div> 753 } 754 </div> 755 756 @if (!string.IsNullOrEmpty(campaignDateStart) && !string.IsNullOrEmpty(campaignDateEnd) && !string.IsNullOrEmpty(campaignText)) 757 { 758 <div class="d-none" data-bind="setInitValue: { observable: CampaignText, value: '@campaignText' }"></div> 759 <div class="price-info fs-xs"> 760 <p class="mb-1"><span class="dot dot-yellow"></span> <span data-bind="text: CampaignText"></span></p> 761 </div> 762 } 763 else 764 { 765 <div class="d-none" data-bind="setInitValue: { observable: CampaignText, value: '' }"></div> 766 } 767 @* <p data-bind="text: CampaignText"></p> *@ 768 </div> 769 770 <div class="optionalproducts d-none"> 771 <hr /> 772 <h5>@Translate("Tilvalg", "Tilvalg")</h5> 773 <div class="optionalproduct"></div> 774 <p><strong>Sum af tilvalg: </strong><span id="optionalPrice"></span></p> 775 </div> 776 777 @if (!string.IsNullOrEmpty(PayeverWidget.WidgetId) && !string.IsNullOrEmpty(PayeverWidget.BusinessId) && !string.IsNullOrEmpty(PayeverWidget.CheckoutId)) 778 { 779 <div> 780 <div id="payever" class="payever-widget-finexp" 781 data-widgetid="@PayeverWidget.WidgetId" 782 data-checkoutid="@PayeverWidget.CheckoutId" 783 data-business="@PayeverWidget.BusinessId" 784 data-type="text" 785 data-reference="order-id" 786 data-amount="@GetString("Ecom:Product.Price.Price").Replace(".", string.Empty).Replace(",", ".")"> 787 </div> 788 <script> 789 var script = document.createElement('script'); 790 script.src = 'https://widgets.payever.org/finance-express/widget.min.js'; 791 script.onload = function() { 792 PayeverPaymentWidgetLoader.init( 793 '.payever-widget-finexp' 794 ); 795 }; 796 document.head.appendChild(script); 797 </script> 798 </div> 799 } 800 801 @if ((QuickDelivery || DisplayAverageDeliveryTime) && !HideDelivery) 802 { 803 <div class="w-100 mt-3"> 804 <div class="delivery-information"> 805 <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"> 806 <g><g> 807 <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" /> 808 </g></g> 809 </svg> 810 <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> 811 </div> 812 </div> 813 } 814 </div> 815 } 816 else 817 { 818 <p>@Translate("Ecom:Product.NotForSaleMessage", "Produktet kan ikke købes.")</p> 819 } 820 </div> 821 822 @if (seeProductInStore != "") 823 { 824 <div class="d-flex flex-wrap flex-column justify-content-end border-grey p-4 mt-2"> 825 <div class="align-self-center w-100"> 826 <a href="@seeProductInStore" class="btn brand-primary-outline see-product-btn font-weight-bold add-to-cart m-0 d-flex align-items-center justify-content-center w-100 px-4">@Translate("Se produktet i en af vores butikker", "Se produktet i en af vores butikker")</a> 827 </div> 828 </div> 829 } 830 </div> 831 </div> 832 833 <div class="delivery-information-popup" data-bind="css: { 'd-flex': DeliveryInfoOpen }, click: ToggleDeliveryInfo"> 834 <div class="description-content bg-white px-3 py-4 px-lg-4 position-relative" data-bind="click: OpenDeliveryInfo, clickBubble: false"> 835 <div class="modal-closer-custom" data-bind="click: ToggleDeliveryInfo, clickBubble: false"> 836 <img src="/Files/Templates/Designs/Mobler2018/assets/img/icons/close.svg" /> 837 </div> 838 @if (QuickDelivery) 839 { 840 <div> 841 @QuickDeliveryDescription 842 </div> 843 } 844 else if (DisplayAverageDeliveryTime) 845 { 846 <div> 847 @NormalDeliveryDescription 848 </div> 849 } 850 </div> 851 </div> 852 853 <div class="variant-information-popup" data-bind="css: { 'd-flex': VariantInfoOpen }, click: ToggleVariantInfo"> 854 <div class="description-content bg-white px-3 py-4 px-lg-4 position-relative" data-bind="click: OpenVariantInfo, clickBubble: false"> 855 <div class="modal-closer-custom" data-bind="click: ToggleVariantInfo, clickBubble: false"> 856 <img src="/Files/Templates/Designs/Mobler2018/assets/img/icons/close.svg" /> 857 </div> 858 <p></p> 859 </div> 860 </div> 861 862 <div class="delivery-information-popup" data-bind="css: { 'd-flex': OptionalInfoOpen }, click: ToggleOptionalInfo"> 863 <div class="description-content bg-white px-3 py-4 px-lg-4 position-relative" data-bind="click: OpenOptionalInfo, clickBubble: false"> 864 <div class="modal-closer-custom" data-bind="click: ToggleOptionalInfo, clickBubble: false"> 865 <img src="/Files/Templates/Designs/Mobler2018/assets/img/icons/close.svg" /> 866 </div> 867 <div> 868 @Translate("TilvalgInfoboks", "Tilvalg tekst") 869 </div> 870 </div> 871 </div> 872 873 @if (CostPrice > 0) 874 { 875 <div class="w-100 mt-3"> 876 877 <div class="delivery-information"> 878 <div class="live-price-animation"></div> 879 <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> 880 </div> 881 882 </div> 883 } 884 885 <div class="w-100"> 886 @if (GetBoolean("Ecom:Product:Field.Farvevarianter1.Value")) 887 { 888 <img class="img-fluid mb-3 mt-5" src="/Files/Images/Farver/farver1.png" /> 889 <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> 890 } 891 else if (GetBoolean("Ecom:Product:Field.Farvevarianter2.Value")) 892 { 893 <img class="img-fluid mb-3 mt-5" src="/Files/Images/Farver/farver2.png" /> 894 <p class="mb-0">@Translate("ProductColor2Text", "Farve 2 hj&aelig;lpetekst")</p> 895 } 896 else if (GetBoolean("Ecom:Product:Field.Farvevarianter3.Value")) 897 { 898 <img class="img-fluid mb-3 mt-5" src="/Files/Images/Farver/farver3.png" /> 899 <p class="mb-0">@Translate("ProductColor3Text", "Farve 3 hj&aelig;lpetekst")</p> 900 } 901 else if (GetBoolean("Ecom:Product:Field.Farvevarianter4.Value")) 902 { 903 <img class="img-fluid mb-3 mt-5" src="/Files/Images/Farver/farver4.png" /> 904 <p class="mb-0">@Translate("ProductColor4Text", "Farve 4 hj&aelig;lpetekst")</p> 905 } 906 else if (GetBoolean("Ecom:Product:Field.Farvevarianter5.Value")) 907 { 908 <img class="img-fluid mb-3 mt-5" src="/Files/Images/Farver/farver5.png" /> 909 <p class="mb-0">@Translate("ProductColor5Text", "Farve 5 hj&aelig;lpetekst")</p> 910 } 911 </div> 912 @SnippetEnd("PricesContainer") 913 914 @SnippetStart("ProductDetailsMeta") 915 @if (!string.IsNullOrEmpty(MetaDescription)) 916 { 917 <meta name="description" content="@MetaDescription" /> 918 } 919 @SnippetEnd("ProductDetailsMeta") 920 921 @SnippetStart("OgTags") 922 <meta property="og:type" content="product" /> 923 <meta property="og:description" content="@Regex.Replace(ShortDescription, "<.*?>", String.Empty)" /> 924 <meta property="og:image" content="@OgImage" /> 925 @SnippetEnd("OgTags") 926 927 @using System.Collections 928 @using Dynamicweb.Core 929 @using Dynamicweb.Ecommerce 930 @using Mobler.Website.CustomModules.MoblerHelpers 931 @using Dynamicweb.Ecommerce.Products 932 @using Dynamicweb.Ecommerce.Variants 933 @using Humanizer 934 @using Mobler.Website.CustomCode 935 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 936 937 @using Mobler.Website.CustomModules.MoblerHelpers 938 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 939 940 @helper RenderPricing(LoopItem product, bool hasVariants) 941 { 942 // Theming 943 string blackFridayTheme = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetString("BlackFridayTheme"); 944 945 // Pricing 946 DateTime newItemExpiryDate = product.GetDate( "Ecom:Product:Field.NewItemExpiryDate" ); 947 bool hasNewItemExpiryDate = newItemExpiryDate.Date > DateTime.Now.Date; 948 bool newItem = product.GetBoolean("Ecom:Product:Field.NewItem") && hasNewItemExpiryDate; 949 bool LowPrice = product.GetBoolean("Ecom:Product:Field.Splash3"); 950 double CostPrice = product.GetDouble("Ecom:Product:Field.FirstwebCostPrice.Value.Raw"); 951 string PriceSaving = product.GetString("Ecom:Product:Field.Spar.Value"); 952 double ActualPrice = product.GetDouble("Ecom:Product.Price.Price"); 953 954 // Initialize variables 955 double spar = 0; 956 double price = 0; 957 double normalPrice = 0; 958 959 string priceFormatted = ""; 960 string sparFormatted = ""; 961 string normalPriceFormatted = ""; 962 963 string campaignColor = ""; 964 string campaignText = ""; 965 string campaignDate = ""; 966 967 bool CampaignActiveOnProduct = product.GetBoolean("CampaignModule:Product.CampaignActiveOnProduct"); 968 bool IsLocalWebshopProduct = (Mobler.Website.CustomCode.Frontend.Helper.IsLocalWebshop() && !product.GetBoolean("Ecom:Product:Field.SystemIsMasterShopProduct")); 969 970 if (!CampaignActiveOnProduct && !IsLocalWebshopProduct) 971 { 972 price = ActualPrice; 973 priceFormatted = MoblerHelpers.formatPrice(price); 974 } 975 else if (IsLocalWebshopProduct) 976 { 977 price = ActualPrice; 978 priceFormatted = MoblerHelpers.formatPrice(price); 979 980 normalPrice = product.GetDouble("Ecom:Product:Field.ForPris"); 981 normalPriceFormatted = MoblerHelpers.formatPrice(normalPrice); 982 983 spar = product.GetDouble("Ecom:Product:Field.Spar"); 984 sparFormatted = MoblerHelpers.formatPrice(spar); 985 986 bool SplashLwCombiPrice = product.GetBoolean("Ecom:Product:Field.SplashLwCombiPrice"); 987 DateTime SplashLwCombiPriceExpiryDate = product.GetDate("Ecom:Product:Field.SplashLwCombiPriceExpiryDate"); 988 989 if (SplashLwCombiPrice && (SplashLwCombiPriceExpiryDate == DateTime.MinValue || SplashLwCombiPriceExpiryDate > DateTime.Now)) 990 { 991 campaignText = "KOMBI"; 992 } 993 } 994 else 995 { 996 normalPrice = product.GetDouble("CampaignModule:Product.CampaignProduct.NormalPrice"); 997 normalPriceFormatted = product.GetString("CampaignModule:Product.CampaignProduct.NormalPrice.FormattedRetail"); 998 999 price = product.GetDouble("CampaignModule:Product.CampaignProduct.CampaignPrice"); 1000 priceFormatted = product.GetString("CampaignModule:Product.CampaignProduct.CampaignPrice.FormattedRetail"); 1001 1002 spar = product.GetDouble("CampaignModule:Product.CampaignProduct.DiscountAmount"); 1003 sparFormatted = product.GetString("CampaignModule:Product.CampaignProduct.DiscountAmount.FormattedRetail"); 1004 1005 campaignColor = product.GetString("CampaignModule:Product.Campaign.Color"); 1006 campaignText = product.GetString("CampaignModule:Product.Campaign.Text"); 1007 } 1008 1009 // Set Splash Types 1010 string splashType = ""; 1011 if (campaignText == "KOMBI") 1012 { 1013 splashType = "combo"; 1014 } 1015 else if (CostPrice > 0) 1016 { 1017 splashType = "priceshape"; 1018 } 1019 else if (spar > 0) 1020 { 1021 splashType = "offer"; 1022 } 1023 else if (newItem) 1024 { 1025 splashType = "new"; 1026 } 1027 else if (LowPrice) 1028 { 1029 splashType = "low"; 1030 } 1031 1032 <div> 1033 <p class="product-item__price fs3 font-weight-bold"> 1034 @if (hasVariants) 1035 { 1036 <span class="font-weight-semibold fs0 mr-2">@Translate("ProductPrice.From", "Fra")</span> 1037 } 1038 @priceFormatted 1039 </p> 1040 @if (splashType == "combo") 1041 { 1042 <div class="splash splash--on-top"> 1043 <p class="m-0">@Translate("ProductCombinationOffer", "Sætpris")</p> 1044 </div> 1045 <div class="d-flex justify-content-between mb-2"> 1046 <p class="color-subtle fs0 m-0 text-uppercase">@Translate("PriceBeforeCombo", "Før") @normalPriceFormatted</p> 1047 <p class="splash fs0 text-uppercase m-0 px-2">@Translate("PriceSaving", "Spar") @sparFormatted</p> 1048 </div> 1049 } 1050 else if (splashType == "priceshape") 1051 { 1052 string DailyPriceBackgroundColor = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetString("AktuelDagsprisBackgroundColor"); 1053 string DailyPriceTextColor = Firstweb.Custom.CustomCode.Frontend.Helpers.AreaItems.GetString("AktuelDagsprisTextColor"); 1054 1055 <div class="splash splash--on-top price-shape" style="background-color: @DailyPriceBackgroundColor"> 1056 <p class="m-0" style="color: @DailyPriceTextColor;">@Translate("ProductDailyPriceSplash", "Dagspris")</p> 1057 </div> 1058 } 1059 else if (splashType == "offer") 1060 { 1061 if (blackFridayTheme == "True") 1062 { 1063 <div class="splash splash--on-top bf-bg-black bf-color-white"> 1064 <p class="m-0">@Translate("ProductOffer", "Tilbud")</p> 1065 </div> 1066 } 1067 else 1068 { 1069 <div class="splash splash--on-top p-1"> 1070 <p class="m-0">@Translate("ProductOffer", "Tilbud")</p> 1071 </div> 1072 } 1073 <div class="d-flex justify-content-between mb-2"> 1074 <p class="color-subtle fs0 m-0 text-uppercase">@Translate("PriceBefore", "Før") @normalPriceFormatted</p> 1075 <p class="splash fs0 m-0 text-uppercase px-2">@Translate("PriceSaving", "Spar") @sparFormatted</p> 1076 </div> 1077 } 1078 else if (splashType == "new") 1079 { 1080 <div class="splash splash--on-top p-1 new-item"> 1081 <p class="m-0">@Translate("ProductNew", "Nyhed")</p> 1082 </div> 1083 } 1084 else if (splashType == "low") 1085 { 1086 <div class="splash splash--on-top p-1 low-price"> 1087 <p class="m-0">@Translate("ProductLowPrice", "Fast lavpris")</p> 1088 </div> 1089 } 1090 </div> 1091 } 1092 1093 1094 @helper RenderProduct(LoopItem product, Boolean powerStep = false) 1095 { 1096 // Group Specific - Exclude Bed Accessories 1097 bool excludeBedAccessories = product.GetBoolean("Ecom:Product.CategoryField.Senge.ExcludeBedAccessories.Value"); 1098 1099 // Product General Info 1100 string productId = product.GetString("Ecom:Product.ID"); 1101 string productName = product.GetString("Ecom:Product.Name"); 1102 string productLink = product.GetString("Ecom:Product.Link.Clean"); 1103 string shortDescription = product.GetString("Ecom:Product.ShortDescription"); 1104 string languageId = product.GetString("Ecom:Product.LanguageID"); 1105 1106 // Variants 1107 string defaultVariantId = product.GetString("Ecom:Product.DefaultVariantComboID"); 1108 string variantId = product.GetString("Ecom:Product.VariantID"); 1109 if (String.IsNullOrEmpty(variantId)) { 1110 variantId = defaultVariantId; 1111 } 1112 if (!String.IsNullOrEmpty(variantId)) { 1113 productLink = productLink + "&variantid=" + variantId; 1114 } 1115 1116 // Product Images 1117 List<string> images = MoblerHelpers.GetProductImages(productId, variantId); 1118 string productImage = string.Format("/Admin/Public/GetImage.ashx?Image={0}&Width=280&height=220&Format=webP&Quality=90&Crop=5&resolution=50", images.FirstOrDefault()); //MoblerHelpers.GetProductListImageWithMainImage(ProductID, ProductNumber); 1119 1120 // Product Dimensions 1121 string productDepth = product.GetString("Ecom:Product:Field.dybdeint.Value.Clean"); 1122 string productHeight = product.GetString("Ecom:Product:Field.hoejdeint.Value.Clean"); 1123 string productWidth = product.GetString("Ecom:Product:Field.breddeint.Value.Clean"); 1124 bool hasProductDepth = !string.IsNullOrWhiteSpace(productDepth) && productDepth != "0"; 1125 bool hasProductHeight = !string.IsNullOrWhiteSpace(productHeight) && productHeight != "0"; 1126 bool hasProductWidth = !string.IsNullOrWhiteSpace(productWidth) && productWidth != "0"; 1127 1128 // Campaign 1129 string campaignDateStart = ""; 1130 string campaignDateEnd = ""; 1131 1132 bool campaignActiveOnProduct = product.GetBoolean("CampaignModule:Product.CampaignActiveOnProduct"); 1133 if (campaignActiveOnProduct) 1134 { 1135 campaignDateStart = product.GetString("CampaignModule:Product.CampaignProduct.Campaign.Start"); 1136 campaignDateEnd = product.GetString("CampaignModule:Product.CampaignProduct.Campaign.End"); 1137 } 1138 1139 bool hasCampaignDateStart = !string.IsNullOrWhiteSpace(campaignDateStart); 1140 1141 bool hasCampaignDateEnd = !string.IsNullOrWhiteSpace(campaignDateEnd); 1142 string campaignText = ""; 1143 if (hasCampaignDateStart && hasCampaignDateStart) 1144 { 1145 campaignText = $"{Translate("Campaign.BeforeDate.Text", "Gældende fra:")} {campaignDateStart} {Translate("Campaign.BeforeDate.Text2", "t.o.m.")} {campaignDateEnd}"; 1146 } 1147 1148 <div class="col-12 col-sm-6 col-lg-3 product-item js-product-list-item"> 1149 <div class="product-item__header"> 1150 <a href="@productLink" class="product-item__image"> 1151 <img class="js-product-image-@productId" src="@productImage" alt="@productName" loading="lazy"/> 1152 </a> 1153 @{ 1154 int colorOptionsToShow = 4; 1155 List<string> variantCombinationVariantIds = product.GetLoop("Co3VariantCombinations").Select(p => p.GetString("Ecom:VariantCombination.VariantID")).ToList(); 1156 bool hasVariants = false; 1157 } 1158 @if (variantCombinationVariantIds.Any() && !powerStep) 1159 { 1160 hasVariants = true; 1161 1162 <div class="product-item__variants d-flex align-items-center"> 1163 @foreach (LoopItem vg in product.GetLoop("VariantGroups")) 1164 { 1165 int variantOptionWithColorCount = 0; 1166 1167 @* Only show variants with hex colors *@ 1168 foreach (LoopItem variantOption in vg.GetLoop("VariantAvailableOptions")) 1169 { 1170 <p class="unimportant-hidden">@variantOptionWithColorCount</p> 1171 string variantOptionColor = variantOption.GetString("Ecom:VariantOption.ColorHex"); 1172 1173 // Get count of variants with color 1174 if (variantOptionColor.Any()) 1175 { 1176 variantOptionWithColorCount++; 1177 } 1178 // Only show this specific amount of variants 1179 if (variantOptionColor.Any() && variantOptionWithColorCount < colorOptionsToShow) 1180 { 1181 // Get variant option id, then compare with variant combinations, to get the link to the specific variant 1182 string variantOptionId = variantOption.GetString("Ecom:VariantOption.ID"); 1183 string variantIdWithColorOptionId = variantCombinationVariantIds.FirstOrDefault(vid => vid.Contains(variantOptionId)); 1184 1185 if (variantIdWithColorOptionId.IsNullOrEmpty() == false) 1186 { 1187 string variantLink = product.GetString("Ecom:Product.Link.Clean") + "&variantid=" + variantIdWithColorOptionId; 1188 <a href="@variantLink" class="product-item__variant" style="background-color: @variantOptionColor;"></a> 1189 } 1190 } 1191 else if (variantOptionColor.Any() && variantOptionWithColorCount == colorOptionsToShow) 1192 { 1193 <a href="@productLink" class="fs2 product-item__more-variants">+</a> 1194 } 1195 else 1196 { 1197 break; 1198 } 1199 } 1200 } 1201 @if (hasVariants) 1202 { 1203 <a href="@productLink" class="ml-4 fs-s"> 1204 <i class="fas fa-pen mr-1 fs-2"></i> 1205 @Translate("Ecom:Product.Pricing.Designer", "Design selv") 1206 </a> 1207 } 1208 </div> 1209 } 1210 </div> 1211 1212 <div class="product-item__body"> 1213 <a href="@productLink" class="product-item__title"> 1214 <h3 class="fs0">@productName</h3> 1215 </a> 1216 <div class="product-item__description fs0 color-subtle">@shortDescription</div> 1217 @if (hasProductDepth && !powerStep || hasProductHeight && !powerStep || hasProductWidth && !powerStep) 1218 { 1219 <p class="product-item__dimensions fs0 color-subtle"> 1220 @if (hasProductDepth) 1221 { 1222 <span>D/L: @productDepth</span> 1223 } 1224 @if (hasProductHeight) 1225 { 1226 <span>H: @productHeight</span> 1227 } 1228 @if (hasProductWidth) 1229 { 1230 <span>B: @productWidth</span> 1231 } 1232 </p> 1233 } 1234 </div> 1235 1236 <div class="product-item__footer"> 1237 @RenderPricing(product, hasVariants) 1238 1239 @if (excludeBedAccessories && !powerStep) 1240 { 1241 <p class="color-subtle fs-s m-0">@Translate("Ecom:Product.Pricing.Excludes.Beds", "Prisen er ekskl. ben og gavl.")</p> 1242 } 1243 @if (hasVariants && !powerStep) 1244 { 1245 <div class="variant-price-disclaimer color-subtle fs-s">@Translate("VariantPriceDisclaimer", "Prisen kan variere efter materialevalg")</div> 1246 } 1247 @if (hasCampaignDateStart && hasCampaignDateEnd && !powerStep) 1248 { 1249 <div class="product-item__campaign"> 1250 <p class="color-subtle fs-s">@campaignText</p> 1251 </div> 1252 } 1253 </div> 1254 </div> 1255 } 1256 1257 @using Mobler.Website.CustomModules.MoblerHelpers 1258 @inherits Dynamicweb.Rendering.RazorTemplateBase<Dynamicweb.Rendering.RazorTemplateModel<Dynamicweb.Rendering.Template>> 1259 1260 @helper RenderBlogTeaser(Firstweb.Custom.CustomCode.Frontend.Helpers.Blog Blog) 1261 { 1262 string PageId = GetGlobalValue( "Global:Page.ID" ); 1263 string CleanLink = Blog.Link.Replace("default.aspx?id", "Default.aspx?Id"); 1264 <div class="col-12 col-md-4 px-0 px-md-3 mb-4"> 1265 <a href="@CleanLink" class="blog d-block"> 1266 <div class="image" style="background-image:url('@Blog.Image')"> 1267 <img class="d-none" src="@Blog.Image" alt="Alternate Text" /> 1268 </div> 1269 <div class="text"> 1270 <div class="positioning"> 1271 <h4 class="col-10 col-md-9 px-2 pt-3 bg-white font-weight-bold text-center mx-auto">@Blog.Header</h4> 1272 @if ( PageId != "7613" ) 1273 { 1274 <p class="text-center color-subtle">@Blog.Date</p> 1275 } 1276 <p class="text-center font-weight-bold m-0 color-primary">@Translate("BlogReadMore", "L&aelig;s mere her")</p> 1277 </div> 1278 </div> 1279 </a> 1280 </div> 1281 } 1282 1283 @helper RenderLargeBlogTeaser(Firstweb.Custom.CustomCode.Frontend.Helpers.Blog Blog, string ImagePosition) 1284 { 1285 string ImageClass = ImagePosition == "Left" ? "" : "offset-md-4"; 1286 string TextClass = ImagePosition == "Left" ? "" : "left"; 1287 string Image = "/Admin/Public/GetImage.ashx?Image=" + Blog.Image + "&Format=webP&Quality=90&Height=400&Crop=0"; 1288 string CleanLink = Blog.Link.Replace("default.aspx?id", "Default.aspx?Id"); 1289 <div class="col-12 blog"> 1290 <div class="row"> 1291 <div class="col-12 col-md-8 px-0 px-md-3 @ImageClass"> 1292 <div class="image-container" style="background-image:url('@Image')"> 1293 <img class="img-fluid" src="@Image" alt="@Blog.Header" /> 1294 </div> 1295 </div> 1296 <div class="col-12 col-md-6 text-container mb-5 mb-md-0 @TextClass"> 1297 <div class="text bg-white p-3"> 1298 <div> 1299 <h4>@Blog.Header</h4> 1300 @Blog.Teaser 1301 </div> 1302 <a class="font-weight-bold" href="@CleanLink">@Translate("BlogReadMore", "L&aelig;s mere her")</a> 1303 </div> 1304 </div> 1305 </div> 1306 </div> 1307 } 1308 1309 @helper RenderLatestBlogsTeasers() 1310 { 1311 var LatestBlogs = Firstweb.Custom.CustomCode.Frontend.Helpers.Blogs.GetLatestBlogs(); 1312 foreach (var Blog in LatestBlogs) 1313 { 1314 @RenderBlogTeaser(Blog) 1315 } 1316 } 1317 1318 1319 <div class="container d-none d-md-block"> 1320 <div class="bread"> 1321 <p class="color-subtle">@Translate("Breadcrumb.CurrentPage", "Her er du:")</p> 1322 <p class="bread-item color-subtle"> 1323 <a href="/"> 1324 @Translate("Breadcrumb.Frontpage", "Forside") 1325 </a> 1326 </p> 1327 @foreach (var Group in ParentGroups) 1328 { 1329 <p class="bread-item color-subtle"> 1330 @if (Group == ParentGroups.First()) 1331 { 1332 @Group.Name 1333 ShowOnPageUrl = Group.ProductGroupFieldValues.GetProductGroupFieldValue("FirstwebGroupPrimaryPage").Value.ToString(); 1334 } 1335 else 1336 { 1337 <a href="/@ShowOnPageUrl&GroupId=@Group.Id"> 1338 @Group.Name 1339 </a> 1340 } 1341 </p> 1342 } 1343 <p class="active color-subtle">@ProductName</p> 1344 </div> 1345 </div> 1346 1347 <div class="container my-5 product-details position-relative" data-bind="viewModel: 'ProductViewModel'"> 1348 <div class="d-none" data-bind="setInitValue: { observable: CartPageId, value: '@AjaxCartPageId' }"></div> 1349 <div class="d-none" data-bind="setInitValue: { observable: MiniCart, value: '.js-mini-cart-lines' }"></div> 1350 <div class="d-none" data-bind="setInitValue: { observable: CartCount, value: '.js-cart-count' }"></div> 1351 <div class="d-none" data-bind="setInitValue: { observable: CustomersAlsoSawLines, value: '.js-customers-also-saw-lines' }"></div> 1352 <div class="d-none" data-bind="setInitValue: { observable: CustomersAlsoSawPage, value: '@CustomersAlsoSawPageId' }"></div> 1353 <div class="d-none" data-bind="setInitValue: { observable: RelewiseRecommandationsEndpoint, value: '@relewiseRecommandationsEndpoint' }"></div> 1354 <div class="d-none" data-bind="setInitValue: { observable: MainProductId, value: '@ProductID' }"></div> 1355 <div class="d-none" data-bind="setInitValue: { observable: VariantsEndpoint, value: '@VariantsEndpoint' }"></div> 1356 <div class="d-none" data-bind="setInitValue: { observable: VariantDetailsEndpoint, value: '@VariantDetailsEndpoint' }"></div> 1357 <div class="d-none" data-bind="setInitValue: { observable: TeaserText, value: '@TrimmedTeaser' }"></div> 1358 <div class="d-none" data-bind="setInitValue: { observable: ProductName, value: '@TrimmedName' }"></div> 1359 <div class="d-none" data-bind="setInitValue: { observable: ProductNumber, value: '@ProductNumber' }"></div> 1360 <div class="d-none" data-bind="setInitValue: { observable: VariantId, value: '@VariantId' }"></div> 1361 <div class="d-none" data-bind="setInitValue: { observable: Price, value: '@priceFormatted' }"></div> 1362 <div class="d-none" data-bind="setInitValue: { observable: PriceDouble, value: '@price' }"></div> 1363 1364 <div class="d-none js-update-cart" data-bind="setInitValue: { observable: CartEndpoint, value: '@GetCartEndpoint' }, click: GetCart"></div> 1365 1366 <h1 class="header fs4 mb-5" data-bind="text: ProductName">@ProductName</h1> 1367 <p class="color-subtle fs0 mt-0 mb-2">@Translate("ProductProductNumber", "Produktnummer:") <span data-bind="text: ProductNumber">@ProductNumber</span></p> 1368 <div class="short-description mb-4 fs2 content-left"> 1369 @ShortDescription 1370 <p class="m-0"> 1371 @if ( !string.IsNullOrWhiteSpace( GetString( "Ecom:Product:Field.dybdeint.Value.Clean" ) ) ) 1372 { 1373 if ( GetString( "Ecom:Product:Field.dybdeint.Value.Clean" ) != "0" ) 1374 { 1375 <span>D/L: @GetValue( "Ecom:Product:Field.dybdeint.Value.Clean" )</span> 1376 } 1377 } 1378 @if ( !string.IsNullOrWhiteSpace( GetString( "Ecom:Product:Field.hoejdeint.Value.Clean" ) ) ) 1379 { 1380 if ( GetString( "Ecom:Product:Field.hoejdeint.Value.Clean" ) != "0" ) 1381 { 1382 <span>H: @GetValue( "Ecom:Product:Field.hoejdeint.Value.Clean" )</span> 1383 } 1384 } 1385 @if ( !string.IsNullOrWhiteSpace( GetString( "Ecom:Product:Field.breddeint.Value.Clean" ) ) ) 1386 { 1387 if ( GetString( "Ecom:Product:Field.breddeint.Value.Clean" ) != "0" ) 1388 { 1389 <span>B: @GetValue( "Ecom:Product:Field.breddeint.Value.Clean" )</span> 1390 } 1391 } 1392 </p> 1393 </div> 1394 1395 <div class="d-flex flex-wrap product-top"> 1396 <div class="image-container position-relative overflow-hidden"> 1397 <div class="splash splash--on-top unimportant-hidden" data-bind="css: { 'd-flex': SplashType() == 1 }"><p class="m-0">@Translate("ProductOffer", "Tilbud")</p></div> 1398 <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> 1399 <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> 1400 <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> 1401 <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> 1402 1403 <div id="imageSlider" class="carousel slide" data-ride="carousel" data-interval="5000"> 1404 <div class="carousel-inner align-items-center" data-bind="if: Images().length == 0"> 1405 1406 @foreach (var Image in Images) 1407 { 1408 if (First) 1409 { 1410 <a href="/Admin/Public/GetImage.ashx?Image=@Image&Format=webP&Quality=90&width=2000" class="mb-3 mb-lg-0 carousel-item active" data-gallery> 1411 <img class="product-image main-image" src="/Admin/Public/GetImage.ashx?Image=@Image&Format=webP&Quality=90&width=800&height=500&crop=5" alt="@ProductName" /> 1412 </a> 1413 First = false; 1414 FirstImage = "/Admin/Public/GetImage.ashx?Image=" + Image + "&Format=webP&Quality=90&width=800&height=500&crop=5"; 1415 } 1416 else 1417 { 1418 <a href="/Admin/Public/GetImage.ashx?Image=@Image&Format=webP&Quality=90&width=1600" class="mb-3 mb-lg-0 carousel-item" data-gallery> 1419 <img class="product-image main-image" src="/Admin/Public/GetImage.ashx?Image=@Image&Format=webP&Quality=90&width=800&height=500&crop=5" alt="@ProductName" /> 1420 </a> 1421 } 1422 1423 } 1424 1425 </div> 1426 <div class="carousel-inner align-items-center d-flex js-ko-carousel" data-bind="foreach: Images()"> 1427 1428 <a data-bind="attr: { href: '/Admin/Public/GetImage.ashx?Image=' + $data + '&Format=webP&Quality=90&width=1600' }" class="mb-3 mb-lg-0 carousel-item active" data-gallery> 1429 <img class="product-image main-image" data-bind="attr: { src: '/Admin/Public/GetImage.ashx?Image=' + $data + '&Format=webP&Quality=90&width=800&height=500&crop=5' }" /> 1430 </a> 1431 1432 </div> 1433 </div> 1434 1435 @if (Images.Count > 0) 1436 { 1437 <div class="row small-gutter carousel-row mb-2" data-bind="css: { 'd-none': Images().length > 0 }"> 1438 @if (Images.Count > 0) 1439 { 1440 foreach (var Image in Images) 1441 { 1442 if (FirstIndicator) 1443 { 1444 <div data-target="#imageSlider" data-slide-to="@IndicatorIncrementer" class="col-4 mt-lg-3 cursor-pointer active"> 1445 <div class="secondary-image"> 1446 <img class="product-image" src="/Admin/Public/GetImage.ashx?Image=@Image&Format=webP&Quality=90&width=400&height=230&crop=5" alt="@ProductName" /> 1447 </div> 1448 </div> 1449 FirstIndicator = false; 1450 } 1451 else 1452 { 1453 <div data-target="#imageSlider" data-slide-to="@IndicatorIncrementer" class="col-4 mt-lg-3 cursor-pointer"> 1454 <div class="secondary-image"> 1455 <img class="product-image" src="/Admin/Public/GetImage.ashx?Image=@Image&Format=webP&Quality=90&width=160&height=100&crop=5" alt="@ProductName" /> 1456 </div> 1457 </div> 1458 } 1459 IndicatorIncrementer++; 1460 } 1461 } 1462 1463 @if (!string.IsNullOrEmpty(GetString("Ecom:Product:Field.VideoKlip.Value"))) 1464 { 1465 string BackgroundSize = !String.IsNullOrEmpty(GetString("Ecom:Product:Field.VideoBillede.Value.Clean")) ? "cover" : "contain"; 1466 string OverlayImage = !String.IsNullOrEmpty(GetString("Ecom:Product:Field.VideoBillede.Value.Clean")) ? GetString("Ecom:Product:Field.VideoBillede.Value.Clean") : FirstImage; 1467 <div class="youtube-video-container col-4 mt-lg-3" data-bind="youtubeVideo: { videoId: '@GetString("Ecom:Product:Field.VideoKlip.Value")', overlayId: 'js-video-overlay', playerId: 'player' }"> 1468 <div id="js-video-overlay" class="video-overlay pointer" style="background-image:url('@OverlayImage');background-size: @BackgroundSize;"> 1469 <div class="visual-overlay d-flex flex-column justify-content-center align-items-center h-100 w-100"> 1470 <img src="/Files/Templates/Designs/Mobler2018/assets/img/icons/Play.svg" /> 1471 </div> 1472 </div> 1473 </div> 1474 } 1475 1476 </div> 1477 1478 <div class="row small-gutter carousel-row mb-2 unimportant-hidden" data-bind="css: { 'd-flex': Images().length > 0 }"> 1479 <span class="images" style="display:contents;" data-bind="foreach: Images()"> 1480 <!-- ko if: $index() == 0 --> 1481 <div data-target="#imageSlider" class="col-4 mt-lg-3 cursor-pointer active" data-bind="click: $parent.ChangeSlide.bind($data, $index())"> 1482 <div class="secondary-image"> 1483 <img class="product-image" data-bind="attr: { src: '/Admin/Public/GetImage.ashx?Image=' + $data + '&Format=webP&Quality=90&width=400&height=230&crop=5' }" alt="@ProductName" /> 1484 </div> 1485 </div> 1486 <!-- /ko --> 1487 <!-- ko if: $index() != 0 --> 1488 <div data-target="#imageSlider" class="col-4 mt-lg-3 cursor-pointer" data-bind="click: $parent.ChangeSlide.bind($data, $index())"> 1489 <div class="secondary-image"> 1490 <img class="product-image" data-bind="attr: { src: '/Admin/Public/GetImage.ashx?Image=' + $data + '&Format=webP&Quality=90&width=400&height=230&crop=5' }" alt="@ProductName" /> 1491 </div> 1492 </div> 1493 <!-- /ko --> 1494 </span> 1495 1496 @if (!String.IsNullOrEmpty(GetString("Ecom:Product:Field.VideoKlip.Value"))) 1497 { 1498 string BackgroundSize = !String.IsNullOrEmpty(GetString("Ecom:Product:Field.VideoBillede.Value.Clean")) ? "cover" : "contain"; 1499 string OverlayImage = !String.IsNullOrEmpty(GetString("Ecom:Product:Field.VideoBillede.Value.Clean")) ? GetString("Ecom:Product:Field.VideoBillede.Value.Clean") : FirstImage; 1500 <div class="youtube-video-container mt-lg-3" data-bind="youtubeVideo: { videoId: '@GetString("Ecom:Product:Field.VideoKlip.Value")', overlayId: 'js-videovariant-overlay', playerId: 'player' }"> 1501 <div id="js-videovariant-overlay" class="video-overlay pointer" style="background-image:url('@OverlayImage');background-size: @BackgroundSize;"> 1502 <div class="visual-overlay d-flex flex-column justify-content-center align-items-center h-100 w-100"> 1503 <img src="/Files/Templates/Designs/Mobler2018/assets/img/icons/Play.svg" /> 1504 <p class="mt-3 mb-0 color-white">@Translate("Product.WatchVideo", "Se video")</p> 1505 </div> 1506 </div> 1507 </div> 1508 } 1509 </div> 1510 } 1511 1512 <div class="shortcuts d-flex"> 1513 <div class="shortcuts__header fs0"><b>@Translate( "ShortCuts", "Genveje:" )</b></div> 1514 <div class="shortcuts__body"> 1515 @if (!String.IsNullOrWhiteSpace(GetString("Ecom:Product:Field.ProviderLink.Value.Clean"))) 1516 { 1517 <div class="shortcut"><i class="fa-solid fa-pen"></i> <a href="@GetString("Ecom:Product:Field.ProviderLink.Value.Clean")" target="_blank">@Translate("Product.DesignYourself.Title", "Design selv")</a></div> 1518 } 1519 <div class="shortcut" data-bind="click: ScrollToElement.bind($element, specifications)"><i class="fa fa-clipboard"></i> <a href="#">@Translate("Product.Specifications.Title", "Specifikationer" )</a></div> 1520 @if ( !String.IsNullOrEmpty( ProductCatalogLink ) ) 1521 { 1522 <div class="shortcut"><i class="fa fa-book-open"></i> <a href="@ProductCatalogLink" target="_blank">@Translate( "Product.InspirationBrochure.Title", "Inspirationsbrochure" )</a></div> 1523 } 1524 </div> 1525 </div> 1526 1527 @* <div class="pl-lg-4 prices-container flex-wrap flex-column mt-3 mt-lg-0 position-relative d-flex d-lg-none"> *@ 1528 @* @RenderSnippet("PricesContainer") *@ 1529 @* </div> *@ 1530 1531 <div class="product-bottom-details"> 1532 <div class="d-flex flex-wrap mt-5"> 1533 <div id="js-full-description"> 1534 <h2 class="fs3 mb-2 font-weight-bold">@Translate("Product.ProductDescription.Title", "Produktbeskrivelse")</h2> 1535 <div class="usps d-flex mt-4 mb-4"> 1536 <div class="usps--usp d-flex align-items-center"><i class="@usp1IconClass"></i><strong>@usp1IconText</strong></div> 1537 <div class="usps--usp d-flex align-items-center"><i class="@usp2IconClass"></i><strong>@usp2IconText</strong></div> 1538 <div class="usps--usp d-flex align-items-center"><i class="@usp3IconClass"></i><strong>@usp3IconText</strong></div> 1539 </div> 1540 1541 <div class="product-description"> 1542 <div class="product-description--inner read-more-container"> 1543 <div class="unimportant-hidden" data-bind="html: FullDescription, css: { 'd-block': FullDescription().length > 0 }"></div> 1544 </div> 1545 <p class="read-more"><a href="#" class="text-underline" data-bind="click: ProductDescriptionReadMore.bind($data, $element)">@Translate("Product.Description.ReadMore.Title", "Læs hele beskrivelsen")</a></p> 1546 </div> 1547 1548 <div class="product-description" data-bind="css: { 'd-none': FullDescription().length > 0 }"> 1549 <div class="product-description--inner read-more-container"> 1550 @LongDescription 1551 @if ( !string.IsNullOrEmpty( productionDescription ) ) 1552 { 1553 <h4 class="mt-4">@Translate( "Product.ProductionDescription.Title", "Produktionsbeskrivelse" )</h4> 1554 @:@productionDescription 1555 } 1556 </div> 1557 <p class="read-more"><a href="#" class="text-underline" data-bind="click: ProductDescriptionReadMore.bind($data, $element)">@Translate( "Product.ProductDescription.ReadMore.Title", "Læs hele beskrivelsen" )</a></p> 1558 </div> 1559 </div> 1560 1561 </div> 1562 1563 <div class="d-flex flex-wrap mt-5"> 1564 <div id="specifications" class="specifications-container w-100"> 1565 <h2 class="fs3 mb-4 font-weight-bold">@Translate("Product.Specifications.Title", "Specifikationer")</h2> 1566 <div class="product-specifications"> 1567 @* Render product specifications from variants *@ 1568 <dl class="d-flex flex-wrap w-100 read-more-container unimportant-hidden" data-bind="foreach: Specifications"> 1569 <dt class="w-50 border-top" data-bind="text: Name"></dt> 1570 <dd class="w-50 border-top" data-bind="text: Value"></dd> 1571 </dl> 1572 1573 <dl class="d-flex flex-wrap w-100 read-more-container" data-bind="css: { 'd-none': Specifications().length > 0 }"> 1574 @foreach (LoopItem displayGroup in GetLoop("FieldDisplayGroups")) 1575 { 1576 foreach (LoopItem field in displayGroup.GetLoop("Fields")) 1577 { 1578 if (!field.GetString("Ecom:FieldDisplayGroup.Field.Value").IsNullOrEmpty() && field.GetString("Ecom:FieldDisplayGroup.Field.Value") != "0" && field.GetString("Ecom:FieldDisplayGroup.Field.Value") != "," && !field.GetString("Ecom:FieldDisplayGroup.Field.Value").Contains(",,")) 1579 { 1580 <dt class="w-50 border-top">@field.GetString("Ecom:FieldDisplayGroup.Field.Name")</dt> 1581 <dd class="w-50 border-top"> 1582 @if (field.GetBoolean("Ecom:FieldDisplayGroup.Field.IsList")) 1583 { 1584 @field.GetString("Ecom:FieldDisplayGroup.Field.OptionLabel") 1585 } 1586 else 1587 { 1588 @field.GetString("Ecom:FieldDisplayGroup.Field.Value") 1589 } 1590 </dd> 1591 } 1592 } 1593 } 1594 </dl> 1595 <p class="read-more"><a href="#" class="text-underline" data-bind="click: ProductDescriptionReadMore.bind($data, $element)">@Translate("Product.Specifications.ReadMore.Title", "Vis alle specifikationer")</a></p> 1596 </div> 1597 </div> 1598 </div> 1599 </div> 1600 </div> 1601 1602 <div id="blueimp-gallery" class="blueimp-gallery blueimp-gallery-controls"> 1603 <div class="slides"></div> 1604 <h3 class="title"></h3> 1605 <a class="prev">&#8249;</a> 1606 <a class="next">&#8250;</a> 1607 <a class="close">x</a> 1608 <a class="play-pause"></a> 1609 <ol class="indicator"></ol> 1610 </div> 1611 1612 <div class="pl-lg-4 prices-container flex-wrap flex-column mt-3 mt-lg-0 position-relative"> 1613 @RenderSnippet("PricesContainer") 1614 </div> 1615 </div> 1616 @if (!string.IsNullOrEmpty(productCatalogueImage)) 1617 { 1618 <img id="GroupCatalogueImage" class="unimportant-hidden" src="/Admin/Public/GetImage.ashx?Image=/Files/Images/@productCatalogueImage&Width=320&height=200&Format=webP&Quality=90&Crop=5&resolution=50" /> 1619 } 1620 @if (!string.IsNullOrEmpty(ProductCatalogLink)) 1621 { 1622 <a id="ProductCatalogueLink" class="unimportant-hidden" href="@ProductCatalogLink" target="_blank"></a> 1623 } 1624 @if (uspPageId > 0) 1625 { 1626 <div class="productdetail-usps mt-8 d-flex"> 1627 <div class="row"> 1628 @RenderPageContent(uspPageId) 1629 </div> 1630 </div> 1631 } 1632 1633 @if (showRecommendations) 1634 { 1635 <div id="customersAlsoViewed" class="related-products unimportant-hidden"> 1636 <div class="related-products__header mb-4"> 1637 <h4>@Translate("Product:RelewiseCustomersAlsoViewed.Headline", "Andre har også set")</h4> 1638 </div> 1639 <div id="customersAlsoViewedContainer" class="related-products__body"> 1640 </div> 1641 </div> 1642 } 1643 1644 @if (showRecommendations && !userIsAnonymous) 1645 { 1646 <div id="recentlyViewedProducts" class="related-products unimportant-hidden"> 1647 <div class="related-products__header mb-4"> 1648 <h4>@Translate("Product:RelewiseLatestVisitedProducts.Headline", "Dine seneste besøgte produkter")</h4> 1649 </div> 1650 <div id="recentlyViewedProductsContainer" class="related-products__body"> 1651 1652 </div> 1653 </div> 1654 } 1655 1656 <div class="after-add-to-cart bg-white box-shadow" data-bind="css: { 'd-block': ProductAddedToCart }"> 1657 <div class="closer fs3 pointer" data-bind="click: ProductAddedToCart(false)"> 1658 <i class="fas fa-times-circle color-primary"></i> 1659 </div> 1660 <div class="after-add-to-cart__inner"> 1661 <div class="p-3"> 1662 <p class="font-weight-bold fs text-uppercase m-0"> 1663 <i class="fas fa-check-circle color-primary"></i> 1664 @Translate("ProductProductAddedToCart", "Varen er lagt i indk&oslash;bskurven") 1665 </p> 1666 </div> 1667 <div class="mini-cart large-cart"> 1668 1669 <div class="position-relative"> 1670 <div class="cart-command-loader unimportant-hidden justify-content-center align-items-center" data-bind="css: { 'd-flex': Loading }"> 1671 <div class="d-flex align-items-center"> 1672 <p class="m-0 mr-2">@Translate("Cart.UpdatingCart", "Opdaterer kurv")</p> 1673 <i class="fas fa-circle-notch fa-spin"></i> 1674 </div> 1675 </div> 1676 1677 <div class="lines" data-bind="foreach: Orderlines"> 1678 <div class="cartline d-flex justify-content-between align-items-center px-3 py-2 position-relative bg-grey"> 1679 <span class="delete-orderline color-subtle cursor-pointer mr-2" data-bind="click: $parent.DeleteOrderline.bind($data, OrderlineId)"> 1680 <i class="fas fa-times"></i> 1681 </span> 1682 <div class="product-image w-10"> 1683 <img class="img-fluid" data-bind="attr: { src: ImagePath }"/> 1684 </div> 1685 <div class="flex-fill px-3 w-75"> 1686 <p class="font-weight-bold fs0 m-0" data-bind="text: ProductName"></p> 1687 <p class="m-0 color-subtle small-quantity-indicator"><span data-bind="text: Quantity"></span> stk. a <span data-bind="text: QuantityPrice"></span></p> 1688 <div class="variant-dimensions" data-bind="foreach: VariantDimensions"> 1689 <p class="m-0 color-subtle color-dark-grey font-weight-bold"> 1690 <span data-bind="text: Label"></span> 1691 <span class="font-weight-normal" data-bind="text: Value"></span> 1692 </p> 1693 </div> 1694 </div> 1695 <div class="qty-counter mr-1"> 1696 <div class="d-flex"> 1697 <div class="quantity-controls d-flex align-items-center mr-3"> 1698 <div class="control minus" data-bind="click: $parent.QuantityControl.bind($data, -1, OrderlineId)"> 1699 - 1700 </div> 1701 <input disabled type="text" name="Quantity" value="1" data-bind="value: Quantity, attr: { 'data-id': 'js-input-' + OrderlineId }"/> 1702 <div class="control plus" data-bind="click: $parent.QuantityControl.bind($data, 1, OrderlineId)"> 1703 + 1704 </div> 1705 </div> 1706 </div> 1707 </div> 1708 1709 <p class="fs0 m-0 orderline-price" data-bind="text: OrderlinePrice"></p> 1710 </div> 1711 </div> 1712 @if (BlackFridayTheme == "True") 1713 { 1714 <div class="bf-bg-black p-3 d-flex justify-content-between align-items-center price-summary"> 1715 <p class="m-0 color-white fs-12px font-weight-semibold">@Translate("MiniCartTotal", "Din kurv i alt (ex. fragt)")</p> 1716 <p class="m-0 color-white fs1 font-weight-bold" data-bind="text: CartTotalNoFees"></p> 1717 </div> 1718 } 1719 else 1720 { 1721 <div class="bg-brand p-3 d-flex justify-content-between align-items-center price-summary"> 1722 <p class="m-0 color-white fs-12px font-weight-semibold">@Translate("MiniCartTotal", "Din kurv i alt (ex. fragt)")</p> 1723 <p class="m-0 color-white fs1 font-extra-bold" data-bind="text: CartTotalNoFees"></p> 1724 </div> 1725 } 1726 </div> 1727 1728 </div> 1729 1730 <div id="purchasedWith" class="power-step unimportant-hidden" style="@purchasedWithStyle"> 1731 <div class="power-step__header"> 1732 <h6>@Translate("Checkout.PowerStep.Title", "Andre har også købt") </h6> 1733 </div> 1734 <div id="purchasedWithContainer"> 1735 </div> 1736 </div> 1737 1738 1739 <div class="p-3 d-flex justify-content-between after-add-to-cart__buttons"> 1740 <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> 1741 1742 @if (BlackFridayTheme == "True") 1743 { 1744 <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> 1745 } 1746 else 1747 { 1748 <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> 1749 } 1750 1751 </div> 1752 <div class="js-customers-also-saw-lines"></div> 1753 </div> 1754 </div> 1755 <div class="variant-picker" data-bind="css: { 'open': VariantPickerOpen }"> 1756 <div class="closer color-primary fs5 pointer" data-bind="click: ToggleVariantPicker"> 1757 <i class="fas fa-times-circle"></i> 1758 </div> 1759 <div class="container py-5 position-relative"> 1760 <h3 class="fs4 text-center">Design din @ProductName</h3> 1761 @{ 1762 var ColorDimensions = GetLoop( "VariantGroups" ).Where( g => g.GetString( "Ecom:VariantGroup.Name" ).ToLower().Contains( "farve" ) ); 1763 var NonColorDimensions = GetLoop( "VariantGroups" ).Where( g => !g.GetString( "Ecom:VariantGroup.Name" ).ToLower().Contains( "farve" ) ); 1764 int FilterCounter = 0; 1765 string RowClass = NonColorDimensions.Any() && ColorDimensions.Any() ? "flex-row-reverse" : ""; 1766 } 1767 <div class="row mt-5 @RowClass"> 1768 @if ( ColorDimensions.Any() ) 1769 { 1770 <div class="col-12 col-md-8"> 1771 @foreach ( var VariantDimension in ColorDimensions ) 1772 { 1773 string DimensionName = VariantDimension.GetString( "Ecom:VariantGroup.Name" ); 1774 string FilterName = "filter-" + FilterCounter; 1775 FilterCounter++; 1776 <div class="mb-5 mb-md-0"> 1777 <p class="font-weight-bold fs2 mb-2">@DimensionName</p> 1778 <div class="row custom-row"> 1779 @foreach ( var VariantOption in VariantDimension.GetLoop( "VariantAvailableOptions" ).OrderBy( v => v.GetString( "Ecom:VariantOption.Name" ) ) ) 1780 { 1781 string VariantOptionName = VariantOption.GetString( "Ecom:VariantOption.Name" ); 1782 string VariantOptionId = VariantOption.GetString( "Ecom:VariantOption.ID" ); 1783 string Preview = VariantOption.GetString( "Ecom:VariantOption.ImgSmall.Clean" ); 1784 string PreviewCss = ""; 1785 if ( !String.IsNullOrEmpty( Preview ) ) 1786 { 1787 if ( Preview.StartsWith( "#" ) ) 1788 { 1789 PreviewCss = "style= \"background-color: " + Preview + ";\""; 1790 } 1791 else 1792 { 1793 PreviewCss = "style=\"background-image: url('" + Preview + "');\""; 1794 } 1795 } 1796 <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')"> 1797 <p class="mb-0 color-variant-name d-none d-sm-block">@VariantOptionName</p> 1798 <div class="variant-preview position-relative d-flex" @PreviewCss></div> 1799 </div> 1800 } 1801 </div> 1802 </div> 1803 } 1804 </div> 1805 } 1806 @if ( NonColorDimensions.Any() ) 1807 { 1808 <div class="col-12 col-sm-6 col-md-4"> 1809 @foreach ( var VariantDimension in NonColorDimensions ) 1810 { 1811 string DimensionName = VariantDimension.GetString( "Ecom:VariantGroup.Name" ); 1812 string FilterName = "filter-" + FilterCounter; 1813 FilterCounter++; 1814 <div class="mb-5"> 1815 <p class="font-weight-bold fs2 mb-2">@DimensionName</p> 1816 <div class="row custom-row"> 1817 @foreach ( var VariantOption in VariantDimension.GetLoop( "VariantAvailableOptions" ).OrderBy( v => v.GetString( "Ecom:VariantOption.Name" ) ) ) 1818 { 1819 string VariantOptionName = VariantOption.GetString( "Ecom:VariantOption.Name" ); 1820 string VariantOptionId = VariantOption.GetString( "Ecom:VariantOption.ID" ); 1821 string Preview = VariantOption.GetString( "Ecom:VariantOption.ImgSmall.Clean" ); 1822 string PreviewCss = ""; 1823 if ( !String.IsNullOrEmpty( Preview ) ) 1824 { 1825 if ( Preview.StartsWith( "#" ) ) 1826 { 1827 PreviewCss = "style= \"background-color: " + Preview + ";\""; 1828 } 1829 else 1830 { 1831 PreviewCss = "style=\"background-image: url('/Files" + Preview + "');\""; 1832 } 1833 } 1834 if ( DimensionName == "STØRRELSE" ) 1835 { 1836 <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')"> 1837 <div class="variant-preview position-relative d-flex justify-content-center align-items-center" @PreviewCss> 1838 <p class="mb-0 color-variant-name font-weight-bold">@VariantOptionName</p> 1839 </div> 1840 </div> 1841 } 1842 else 1843 { 1844 <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')"> 1845 <p class="mb-0 color-variant-name">@VariantOptionName</p> 1846 <div class="variant-preview position-relative d-flex" @PreviewCss></div> 1847 </div> 1848 } 1849 } 1850 </div> 1851 </div> 1852 } 1853 </div> 1854 } 1855 1856 <div class="col-12 d-flex justify-content-end"> 1857 <p class="color-primary pointer my-3" data-bind="click: ResetFilters">Nulstil</p> 1858 </div> 1859 </div> 1860 <p class="font-weight-bold fs2 mt-5"> 1861 @Translate( "ChooseProduct", "V&aelig;lg produkt" ) 1862 </p> 1863 <div class="row align-items-end" data-bind="foreach: FilteredVariants"> 1864 <div class="col-12 col-sm-6 col-md-3 mb-3"> 1865 <a class="color-black no-underline" data-bind="attr: { href: Link }"> 1866 <p class="fs0 font-weight-bold m-0" data-bind="text: Name"></p> 1867 <img class="img-fluid box-shadow my-1" data-bind="attr: { src: Image }" /> 1868 <div class="d-flex justify-content-center mt-2"> 1869 <div class="btn btn-primary">@Translate( "VariantChooseProduct", "V&aelig;lg" )</div> 1870 </div> 1871 </a> 1872 </div> 1873 </div> 1874 <div data-bind="visible: FilteredVariants().length == 0"> 1875 <p class="font-weight-bold mt-3 fs3">@Translate( "VariantsNoResults", "Filtreringen gav ingen resultater" )</p> 1876 </div> 1877 </div> 1878 </div> 1879 1880 <div class="add-to-cart-overlay" data-bind="css: { 'd-block': ProcessingAjax }"> 1881 <p class="fs4 m-0 color-white">@Translate("ProductAjaxAddingToCart", "Tilf&oslash;jer til kurv") <i class="fa fa-circle-notch fa-spin ml-3 fs5"></i></p> 1882 </div> 1883 1884 1885 <div class="add-to-cart-overlay" data-bind="css: { 'd-block': ProcessingVariantDetailsAjax }"> 1886 <p class="fs4 m-0 color-white">@Translate("ProductAjaxGettingVariant", "Henter variant") <i class="fa fa-circle-notch fa-spin ml-3 fs5"></i></p> 1887 </div> 1888 </div> 1889 1890 <div class="modal fade video-modal" id="videoModal" tabindex="-1" role="dialog" aria-labelledby="video-modal" aria-hidden="true"> 1891 <div class="modal-dialog modal-dialog-centered" role="document"> 1892 <div class="modal-content"> 1893 <div class="modal-body"> 1894 <div id="player"></div> 1895 </div> 1896 </div> 1897 </div> 1898 </div> 1899 1900 @SnippetStart("DataLayerOverwrites") 1901 <script> 1902 ecomm_pagetype = "Product"; 1903 ecomm_totalvalue = @GetString("Ecom:Product.Price.Price").Replace(".","").Replace(",","."); 1904 ecomm_prodid = "@GetString("Ecom:Product.ID")"; 1905 </script> 1906 @SnippetEnd("DataLayerOverwrites") 1907 1908 <script> 1909 var dataLayer = window.dataLayer || []; 1910 dataLayer.push({ 1911 'event': 'product', 1912 'ecommerce': { 1913 'detail': { 1914 'actionField': { 1915 'list': '@DataLayerParentGroups' 1916 }, 1917 'products': [{ 1918 'id': '@ProductID', 1919 'name': '@ProductName', 1920 'image': '@OgImage', 1921 'brand': '@BrandName', 1922 'variant': '@CurrentVariantName', 1923 'category': '@DataLayerParentGroup', 1924 'price': '@DataLayerPrice' 1925 }] 1926 } 1927 }, 1928 'page': { 1929 'type': 'product', 1930 'environment': 'production' 1931 } 1932 }); 1933 </script> 1934