Skip to main content
Error executing template "Designs/Keflico/eCom/Product/Product.cshtml"
System.InvalidOperationException: Sequence contains no elements
   at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
   at CompiledRazorTemplates.Dynamic.RazorEngine_5903a55ba4c143e1ac88c4d8d7bada0b.Execute() in D:\dynamicweb.net\Solutions\keflico.live\Files\Templates\Designs\Keflico\eCom\Product\Product.cshtml:line 1103
   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 System.Web.Helpers; 3 @using System.IO; 4 5 @using Dynamicweb.Rendering; 6 @using Dynamicweb.Ecommerce.ProductCatalog; 7 @using Dynamicweb.Ecommerce.Variants; 8 @using Dynamicweb.Core; 9 10 @{ 11 System.Web.HttpCookie lastProductIdCookie = new System.Web.HttpCookie("LastProductIdCookie"); 12 lastProductIdCookie.Value = GetString("Ecom:Product.ID"); 13 lastProductIdCookie.Expires = DateTime.MinValue; 14 HttpContext.Current.Response.Cookies.Add(lastProductIdCookie); 15 16 var viewmodelSettings = new ProductViewModelSettings(Dynamicweb.Ecommerce.Common.Context.LanguageID, Dynamicweb.Ecommerce.Common.Context.Currency.Code, Dynamicweb.Ecommerce.Common.Context.Country.Code2, Pageview.Area.EcomShopId, Dynamicweb.Security.UserManagement.User.GetCurrentExtranetUserId()); 17 var productViewmodel = Dynamicweb.Ecommerce.ProductCatalog.ViewModelFactory.CreateView(viewmodelSettings, GetString("Ecom:Product.ID"), GetString("Ecom:Product.VariantId"), ""); 18 var combination = new VariantCombination(GetString("Ecom:Product.ID")); 19 IList<VariantCombination> productVariants = new List<VariantCombination>(); 20 var singleVariant = new VariantCombination(); 21 22 if(combination != null && combination.Product != null) { 23 productVariants = combination.Product.VariantCombinations; 24 } 25 26 if(productVariants.Count == 1) { 27 singleVariant = productVariants.FirstOrDefault(); 28 } 29 30 string CartPage = Pageview.Area.Item["CartPage"].ToString(); 31 string cartCount = GetGlobalValue("Global:eCommerce.Order.OrderLines.TotalProductQuantity"); 32 33 if(string.IsNullOrWhiteSpace(cartCount)) { 34 cartCount = "0"; 35 } 36 37 string EcomPage = Pageview.Area.Item["EcomPage"].ToString(); 38 string VariantsLookup = "/" + Pageview.Area.Item["Variantslookup"].ToString(); 39 string BundleLookup = "/" + Pageview.Area.Item["Bundlelookup"].ToString(); 40 string PriceLookup = "/" + Pageview.Area.Item["Pricelookup"].ToString(); 41 string productNumber = GetString("Ecom:Product.Number"); 42 string dbNumber = GetString("Ecom:Product:Field.ProductDbNumber.Value"); 43 string productId = GetString("Ecom:Product.ID"); 44 string productName = GetString("Ecom:Product.Name"); 45 string primaryGroup = GetString("Ecom:Product.PrimaryGroupID").ToLower(); 46 string formAction = "/" + CartPage; 47 string priceCurrencySymbol = GetString("Ecom:Product.Currency.Symbol"); 48 string loopCounter = GetString("Ecom:Product.LoopCounter"); 49 string inputName = "Quantity" + loopCounter; 50 var categories = GetLoop("AssociatedGroups"); 51 var mainCategory = (LoopItem)null; 52 var productLayout = !string.IsNullOrWhiteSpace(GetString("Ecom:Product:Field.ProductLayout")) ? GetString("Ecom:Product:Field.ProductLayout") : primaryGroup; 53 54 string labelCode = GetString("Ecom:Product:Field.ProductPurchaseCode"); 55 56 var breadcrumbs = new List<LoopItem>(); 57 58 foreach(var cat in categories) { 59 if(cat.GetString("Ecom:Group.ID").ToLower() == primaryGroup) { 60 mainCategory = cat; 61 } 62 } 63 64 if(mainCategory != null) { 65 breadcrumbs.Add(mainCategory); 66 67 foreach(var child in mainCategory.GetLoop("Childgroups")) { 68 foreach(var category in categories) { 69 if(category.GetString("Ecom:Group.ID").ToLower() == child.GetString("Ecom:Group.ID").ToLower()) { 70 breadcrumbs.Add(category); 71 } 72 } 73 } 74 } 75 76 bool enquireProduct = false; 77 bool isSunDryProduct = System.Convert.ToBoolean(GetString("Ecom:Product:Field.ProductSundryItem")); 78 bool isBundleOnly = System.Convert.ToBoolean(GetString("Ecom:Product:Field.BundleOnly")); 79 80 var totalStock = GetDouble("Ecom:Product.Stock"); 81 totalStock += GetDouble("Ecom:Product:Field.StockSea.Value"); 82 83 int totalStockWareHouse = GetInteger("Ecom:Product.Stock"); 84 int totalStockSea = GetInteger("Ecom:Product:Field.StockSea.Value"); 85 86 if(primaryGroup != "group32") { 87 totalStock += GetDouble("Ecom:Product:Field.ProductPieceOnPurchase.Value"); 88 totalStockSea += int.Parse(GetString("Ecom:Product:Field.ProductPieceOnPurchase.Value").Replace(",", string.Empty)); 89 } 90 91 bool isSingleVariant = GetInteger("Ecom:Product.VariantCount") == 1 ? true : false; 92 93 double singleVariantStock = 0; 94 int singleVariantStockSea = 0; 95 96 if(isSingleVariant) { 97 singleVariantStock = singleVariant.Product.UnitStock; 98 singleVariantStockSea = !String.IsNullOrWhiteSpace(singleVariant.Product.ProductFieldValues.GetProductFieldValue("ProductPieceOnPurchase").Value.ToString()) ? Convert.ToInt32(singleVariant.Product.ProductFieldValues.GetProductFieldValue("ProductPieceOnPurchase").Value.ToString().Replace(",", "")) : 0; 99 100 totalStock += singleVariantStock; 101 totalStock += singleVariantStockSea; 102 } 103 104 string halfParcelAmount = GetString("Ecom:Product:Field.ProductNumberPerHalfPackage.Value.Raw"); 105 string completeParcelAmount = GetString("Ecom:Product:Field.ProductNumberPerPackage"); 106 107 string standardPrice = GetString("Ecom:Product.Price.PriceWithoutVAT"); 108 string standardPriceJS = !string.IsNullOrWhiteSpace(GetString("Ecom:Product.Discount.Price.PriceWithoutVAT.Value")) ? GetString("Ecom:Product.Discount.Price.PriceWithoutVAT.Value").Replace(",", ".") : "0"; 109 string halfPrice = !string.IsNullOrWhiteSpace(GetString("Ecom:Product:Field.ProductPriceHalfParcel")) ? GetString("Ecom:Product:Field.ProductPriceHalfParcel").Replace(".","-").Replace(",", ".").Replace("-", ",") : "0"; 110 string fullPrice = !string.IsNullOrWhiteSpace(GetString("Ecom:Product:Field.ProductPriceCompleteParcel")) ? GetString("Ecom:Product:Field.ProductPriceCompleteParcel").Replace(".","-").Replace(",", ".").Replace("-", ",") : "0"; 111 string bundlePrice = GetString("Ecom:Product:Field.ProductPriceBundle.Value").Replace(",", "-").Replace(".", ",").Replace("-", "."); 112 string bundlePriceJS = !string.IsNullOrWhiteSpace(GetString("Ecom:Product:Field.ProductPriceBundle.Value")) ? GetString("Ecom:Product:Field.ProductPriceBundle.Value").Replace(",", "") : "0"; 113 string above100Price = !string.IsNullOrWhiteSpace(GetString("Ecom:Product:Field.ProductPriceAbove100SQM")) ? GetString("Ecom:Product:Field.ProductPriceAbove100SQM") : "0"; 114 string above100PriceJS = !string.IsNullOrWhiteSpace(GetString("Ecom:Product:Field.ProductPriceAbove100SQM.Value.Raw")) ? GetString("Ecom:Product:Field.ProductPriceAbove100SQM.Value.Raw").Replace(",", ".") : "0"; 115 string above3000Price = !string.IsNullOrWhiteSpace(GetString("Ecom:Product:Field.ProductPriceAbove3000M.Value")) ? GetString("Ecom:Product:Field.ProductPriceAbove3000M.Value").Replace(".", ",") : "0"; 116 117 string salesUnit = GetString("Ecom:Product.DefaultUnitName").ToLower(); 118 string salesUnitCode = GetString("Ecom:Product:Field.ProductLengthUnitCode"); 119 120 string configuratorUrl = GetString("Ecom:Product:Field.ProductConfiguratorUrl"); 121 122 string fscLink = Pageview.Area.Item["FSC"].ToString(); 123 string pefcLink = Pageview.Area.Item["PEFC"].ToString(); 124 string ecoNordicLink = Pageview.Area.Item["EcoNordic"].ToString(); 125 string cradleToCradleLink = Pageview.Area.Item["CradleToCradle"].ToString(); 126 127 bool hasNewDownloads = false; 128 bool hasDownloads = false; 129 130 foreach(var fileCat in GetLoop("ImageCategories")) { 131 132 if(fileCat.GetString("Category.SystemName").StartsWith("docView_") && fileCat.GetLoop("Category.Images").Count() > 0) { 133 hasNewDownloads = true; 134 hasDownloads = false; 135 break; 136 } 137 else if(fileCat.GetString("Category.SystemName") != "Images" && fileCat.GetLoop("Category.Images").Count() > 0) { 138 hasDownloads = true; 139 } 140 } 141 142 bool isloggedin = false; 143 144 if (!string.IsNullOrWhiteSpace(GetGlobalValue("Global:Extranet.UserName").ToString())) { 145 isloggedin = true; 146 } 147 148 if(GetString("Ecom:Product:Field.EcomProduct").Contains("forespoerg")) { 149 enquireProduct = true; 150 } 151 152 if(isSunDryProduct) { 153 enquireProduct = true; 154 } 155 156 if(labelCode.ToLower() == "skaffe" || labelCode.ToLower() == "relatordre") { 157 enquireProduct = true; 158 } 159 } 160 161 @SnippetStart("PageTemplate") 162 product-page 163 @SnippetEnd("PageTemplate") 164 165 <article class="module module-sand product-details"> 166 <div class="breadcrumbs"> 167 <ul class="breadcrumbs__list"> 168 <li class="breadcrumbs__item"> 169 <a href="@EcomPage">@Translate("Translate_Breadcrumb_Products")</a> 170 </li> 171 172 @if(breadcrumbs.Count > 0) { 173 foreach(var group in breadcrumbs) { 174 <li class="breadcrumbs__item"> 175 <a href="@group.GetString("Ecom:Group.Link.Clean")">@group.GetString("Ecom:Group.Name")</a> 176 </li> 177 } 178 } 179 <li class="breadcrumbs__item active">@productName</li> 180 </ul> 181 </div> 182 <div class="product-details__container"> 183 @switch (labelCode.ToLower()) 184 { 185 case "prøver": 186 <div class="product-details__label-code label-code label-code--samples">@Translate("LabelCode_" + labelCode.ToLower().Replace("ø", "oe"))</div> 187 break; 188 case "skaffe": 189 case "relatordre": 190 <div class="product-details__label-code label-code">@Translate("LabelCode_" + labelCode.ToLower())</div> 191 break; 192 default: 193 break; 194 } 195 <div class="product-details__media" data-igo-gallery> 196 @if (!String.IsNullOrWhiteSpace(GetString("Ecom:Product.ImageDefault.Clean"))) 197 { 198 <picture class="product-details__image-wrap" data-igo-image="@GetString("Ecom:Product.ImageDefault.Clean")"> 199 <img src="@GetString("Ecom:Product.ImageDefault.Clean")" alt="@productName" loading="lazy"> 200 </picture> 201 } 202 @foreach (var category in GetLoop("ImageCategories")) 203 { 204 if (category.GetString("Category.SystemName") == "Images") 205 { 206 foreach (var image in category.GetLoop("Category.Images")) 207 { 208 <picture class="product-details__image-wrap" data-igo-image="@image.GetString("Ecom:Product:Detail.Image.Clean")"> 209 <img src="@image.GetString("Ecom:Product:Detail.Image.Clean")" alt="@productName" loading="lazy"> 210 </picture> 211 } 212 } 213 } 214 <div class="product-details__media-steps"> 215 <span class="disclaimer">* @Translate("Translate_Product_Page_ImageDisclaimer")</span> 216 <span class="current">1/1</span> 217 </div> 218 </div> 219 <div class="product-details__info"> 220 <div class="product-details__info-labels"> 221 @if (!String.IsNullOrWhiteSpace(GetString("Ecom:Product:Field.ProductCertification")) && GetString("Ecom:Product:Field.ProductCertification") != "-1") 222 { 223 string certification = GetString("Ecom:Product:Field.ProductCertification").ToLower(); 224 if (certification.Contains("pefc")) 225 { 226 <a href="@pefcLink" target="_blank"> 227 @if (System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/pefc-logo.svg"))) 228 { 229 @System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/pefc-logo.svg")) 230 } 231 </a> 232 } 233 else if (certification.Contains("fsc")) 234 { 235 <a href="@fscLink" target="_blank"> 236 @if (System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/fsc-logo.svg"))) 237 { 238 @System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/fsc-logo.svg")) 239 } 240 </a> 241 } 242 } 243 @if (!String.IsNullOrWhiteSpace(GetString("Ecom:Product:Field.ProductNordicEcoLabel")) && GetString("Ecom:Product:Field.ProductNordicEcoLabel") != "-1") 244 { 245 <a href="@ecoNordicLink" target="_blank"> 246 @if (System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/svanemaerket-logo.svg"))) 247 { 248 @System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/svanemaerket-logo.svg")) 249 } 250 </a> 251 } 252 @if (!String.IsNullOrWhiteSpace(GetString("Ecom:Product:Field.ProductCradleToCradle.Value")) && GetString("Ecom:Product:Field.ProductCradleToCradle.Value") != "-1" && GetString("Ecom:Product:Field.ProductCradleToCradle.Value") != "N/A") 253 { 254 <a href="@cradleToCradleLink" target="_blank"> 255 @if (System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/cradle-logo.svg"))) 256 { 257 @System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/cradle-logo.svg")) 258 } 259 </a> 260 } 261 </div> 262 <div class="product-details__info-meta"> 263 <ul class="product-details__info-meta-list"> 264 <li id="productNumber">@Translate("Translate_Product_Page_ProductNumber"): @productNumber</li> 265 @if (!string.IsNullOrWhiteSpace(dbNumber)) 266 { 267 <li>@GetString("Ecom:Product:Field.ProductDbNumber.Name"): @dbNumber</li> 268 } 269 </ul> 270 </div> 271 <h1 id="productName" class="product-details__info-title">@productName</h1> 272 <div class="product-details__info-size">@GetString("Ecom:Product:Field.Name2")</div> 273 274 @switch (productLayout) 275 { 276 case "group1": // Hårdtræ 277 if (isloggedin) 278 { 279 if ((standardPriceJS != "0" && !isBundleOnly) || bundlePriceJS != "0") 280 { 281 <div class="product-details__info-price-container"> 282 <div class="product-details__info-price-heading"> 283 @Translate("Translate_ProductPage_PriceDefinition_HardWood") 284 <span class="tooltip"> 285 <span class="tooltip__icon"> 286 @if (System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/info.svg"))) 287 { 288 @System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/info.svg")) 289 } 290 </span> 291 <span class="tooltip__text tooltip__text--top"> 292 @Translate("Translate_ProductPage_PriceDefinition_HardWood_Tooltip") 293 </span> 294 </span> 295 </div> 296 @if (standardPriceJS != "0" && !isBundleOnly) 297 { 298 <div class="product-details__info-price-option"> 299 <div class="product-details__info-price-option-title">@Translate("Translate_ProductPage_Breakup")</div> 300 <div class="product-details__info-price-option-price">@standardPrice @priceCurrencySymbol pr. @salesUnit</div> 301 <div class="product-details__info-price-option-vat">@Translate("Translate_Ecom_ExVat")</div> 302 </div> 303 } 304 @if (bundlePriceJS != "0") 305 { 306 if (bundlePrice.Contains(",")) 307 { 308 string[] sp = bundlePrice.Split(','); 309 310 if (sp[1].Length == 1) 311 { 312 bundlePrice += "0"; 313 } 314 } 315 else 316 { 317 bundlePrice += ",00"; 318 } 319 320 <div class="product-details__info-price-option"> 321 <div class="product-details__info-price-option-title">@Translate("Translate_ProductPage_Bundle")</div> 322 <div class="product-details__info-price-option-price">@bundlePrice @priceCurrencySymbol pr. @salesUnit</div> 323 <div class="product-details__info-price-option-vat">@Translate("Translate_Ecom_ExVat")</div> 324 </div> 325 } 326 </div> 327 } 328 } 329 330 if (standardPriceJS == "0" && bundlePriceJS == "0") 331 { 332 enquireProduct = true; 333 } 334 335 <div id="product-order-button" style="min-height: 64px;"> 336 @if (enquireProduct) 337 { 338 <a data-action="open-content" data-target="#enquireForm" class="product-details__info-button btn btn--block btn-secondary product-order-form-button">@Translate("Translate_Product_Page_EnquireButton")</a> 339 } 340 else 341 { 342 <div style="display: none;" class="loader"></div> 343 <a style="display: none;" href="#" class="product-details__info-button btn btn--block btn-secondary product-order-button">@Translate("Translate_Product_Page_OrderButton")</a> 344 <a style="display: none;" data-action="open-content" data-target="#enquireForm" class="product-details__info-button btn btn--block btn-secondary product-order-form-button">@Translate("Translate_Product_Page_EnquireButton")</a> 345 } 346 </div> 347 348 break; 349 350 case "group32": // Terrasse 351 352 if (isloggedin) 353 { 354 if (standardPriceJS != "0" || above100PriceJS != "0") 355 { 356 <div class="product-details__info-price-container"> 357 <div class="product-details__info-price-heading"> 358 @Translate("Translate_ProductPage_PriceDefinition_Terrasse") 359 360 @if (primaryGroup == "group32") 361 { 362 <span class="tooltip"> 363 <span class="tooltip__icon"> 364 @if (System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/info.svg"))) 365 { 366 @System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/info.svg")) 367 } 368 </span> 369 <span class="tooltip__text tooltip__text--top"> 370 @Translate("Translate_ProductPage_PriceDefinition_Terrasse_Tooltip") 371 </span> 372 </span> 373 } 374 else 375 { 376 <span class="tooltip"> 377 <span class="tooltip__icon"> 378 @if (System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/info.svg"))) 379 { 380 @System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/info.svg")) 381 } 382 </span> 383 <span class="tooltip__text tooltip__text--top"> 384 @Translate("Translate_ProductPage_PriceDefinition_Facade_Tooltip") 385 </span> 386 </span> 387 } 388 </div> 389 390 @if (standardPriceJS != "0") 391 { 392 <div class="product-details__info-price-option"> 393 <div class="product-details__info-price-option-title">@Translate("Translate_ProductPage_Under100")</div> 394 <div class="product-details__info-price-option-price">@standardPrice @priceCurrencySymbol pr. @salesUnit</div> 395 <div class="product-details__info-price-option-vat">@Translate("Translate_Ecom_ExVat")</div> 396 </div> 397 } 398 399 @if (above100PriceJS != "0") 400 { 401 if (above100Price.Contains(",")) 402 { 403 string[] sp = above100Price.Split(','); 404 405 if (sp[1].Length == 1) 406 { 407 above100Price += "0"; 408 } 409 } 410 else 411 { 412 above100Price += ",00"; 413 } 414 415 <div class="product-details__info-price-option"> 416 <div class="product-details__info-price-option-title">@Translate("Translate_ProductPage_Above100")</div> 417 <div class="product-details__info-price-option-price">@above100Price @priceCurrencySymbol pr. @salesUnit</div> 418 <div class="product-details__info-price-option-vat">@Translate("Translate_Ecom_ExVat")</div> 419 </div> 420 } 421 </div> 422 } 423 } 424 425 if (standardPriceJS == "0" && above100PriceJS == "0") 426 { 427 enquireProduct = true; 428 } 429 430 <div id="product-order-button" style="min-height: 64px;"> 431 @if (enquireProduct) 432 { 433 <a data-action="open-content" data-target="#enquireForm" class="product-details__info-button btn btn--block btn-secondary product-order-form-button">@Translate("Translate_Product_Page_EnquireButton")</a> 434 } 435 else 436 { 437 <div style="display: none;" class="loader"></div> 438 <a style="display: none;" href="#" class="product-details__info-button btn btn--block btn-secondary product-order-button">@Translate("Translate_Product_Page_OrderButton")</a> 439 <a style="display: none;" data-action="open-content" data-target="#enquireForm" class="product-details__info-button btn btn--block btn-secondary product-order-form-button">@Translate("Translate_Product_Page_EnquireButton")</a> 440 } 441 </div> 442 443 break; 444 445 case "group73": // Facadebeklædning 446 if (isloggedin) 447 { 448 if (standardPriceJS != "0" || above100PriceJS != "0" || above3000Price != "0") 449 { 450 <div class="product-details__info-price-container"> 451 <div class="product-details__info-price-heading"> 452 @Translate("Translate_ProductPage_PriceDefinition_Terrasse") 453 454 @if (primaryGroup == "group32") 455 { 456 <span class="tooltip"> 457 <span class="tooltip__icon"> 458 @if (System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/info.svg"))) 459 { 460 @System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/info.svg")) 461 } 462 </span> 463 <span class="tooltip__text tooltip__text--top"> 464 @Translate("Translate_ProductPage_PriceDefinition_Terrasse_Tooltip") 465 </span> 466 </span> 467 } 468 else 469 { 470 <span class="tooltip"> 471 <span class="tooltip__icon"> 472 @if (System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/info.svg"))) 473 { 474 @System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/info.svg")) 475 } 476 </span> 477 <span class="tooltip__text tooltip__text--top"> 478 @Translate("Translate_ProductPage_PriceDefinition_Facade_Tooltip") 479 </span> 480 </span> 481 } 482 </div> 483 484 @if (standardPriceJS != "0") 485 { 486 <div class="product-details__info-price-option"> 487 <div class="product-details__info-price-option-title">@Translate("Translate_ProductPage_Under1000")</div> 488 <div class="product-details__info-price-option-price">@standardPrice @priceCurrencySymbol pr. @salesUnit</div> 489 <div class="product-details__info-price-option-vat">@Translate("Translate_Ecom_ExVat")</div> 490 </div> 491 } 492 493 @if (above100PriceJS != "0") 494 { 495 if (above100Price.Contains(",")) 496 { 497 string[] sp = above100Price.Split(','); 498 499 if (sp[1].Length == 1) 500 { 501 above100Price += "0"; 502 } 503 } 504 else 505 { 506 above100Price += ",00"; 507 } 508 509 <div class="product-details__info-price-option"> 510 <div class="product-details__info-price-option-title">@Translate("Translate_ProductPage_Between1000and3000")</div> 511 <div class="product-details__info-price-option-price">@above100Price @priceCurrencySymbol pr. @salesUnit</div> 512 <div class="product-details__info-price-option-vat">@Translate("Translate_Ecom_ExVat")</div> 513 </div> 514 } 515 516 @if (above3000Price != "0") 517 { 518 if (above3000Price.Contains(",")) 519 { 520 string[] tp = above3000Price.Split(','); 521 522 if (tp[1].Length == 1) 523 { 524 above3000Price += "0"; 525 } 526 } 527 else 528 { 529 above3000Price += ",00"; 530 } 531 532 <div class="product-details__info-price-option"> 533 <div class="product-details__info-price-option-title">@Translate("Translate_ProductPage_Above3000")</div> 534 <div class="product-details__info-price-option-price">@above3000Price @priceCurrencySymbol pr. @salesUnit</div> 535 <div class="product-details__info-price-option-vat">@Translate("Translate_Ecom_ExVat")</div> 536 </div> 537 } 538 </div> 539 } 540 } 541 542 if (standardPriceJS == "0" && above100PriceJS == "0" && above3000Price == "0") 543 { 544 enquireProduct = true; 545 } 546 547 <div id="product-order-button" style="min-height: 64px;"> 548 @if (enquireProduct) 549 { 550 <a data-action="open-content" data-target="#enquireForm" class="product-details__info-button btn btn--block btn-secondary product-order-form-button">@Translate("Translate_Product_Page_EnquireButton")</a> 551 } 552 else 553 { 554 <div style="display: none;" class="loader"></div> 555 <a style="display: none;" href="#" class="product-details__info-button btn btn--block btn-secondary product-order-button">@Translate("Translate_Product_Page_OrderButton")</a> 556 <a style="display: none;" data-action="open-content" data-target="#enquireForm" class="product-details__info-button btn btn--block btn-secondary product-order-form-button">@Translate("Translate_Product_Page_EnquireButton")</a> 557 } 558 </div> 559 560 break; 561 562 case "group52": // Plader 563 case "group66": // Dekorative Overflader 564 565 if (isloggedin) 566 { 567 if (standardPriceJS != "0" || halfPrice != "0" || fullPrice != "0") 568 { 569 <div class="product-details__info-price-container"> 570 <div class="product-details__info-price-heading"> 571 @Translate("Translate_ProductPage_PriceDefinition_Plader") 572 @if (primaryGroup == "group52") 573 { 574 <span class="tooltip"> 575 <span class="tooltip__icon"> 576 @if (System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/info.svg"))) 577 { 578 @System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/info.svg")) 579 } 580 </span> 581 <span class="tooltip__text tooltip__text--top"> 582 @Translate("Translate_ProductPage_PriceDefinition_Plader_Tooltip") 583 </span> 584 </span> 585 } 586 else 587 { 588 <span class="tooltip"> 589 <span class="tooltip__icon"> 590 @if (System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/info.svg"))) 591 { 592 @System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/info.svg")) 593 } 594 </span> 595 <span class="tooltip__text tooltip__text--top"> 596 @Translate("Translate_ProductPage_PriceDefinition_Overflader_Tooltip") 597 </span> 598 </span> 599 } 600 </div> 601 602 @if (standardPriceJS != "0") 603 { 604 <div class="product-details__info-price-option"> 605 <div class="product-details__info-price-option-title">@Translate("Translate_ProductPage_PriceUnit_Anbrud")</div> 606 <div class="product-details__info-price-option-price">@standardPrice @priceCurrencySymbol pr. @salesUnit</div> 607 <div class="product-details__info-price-option-vat">@Translate("Translate_Ecom_ExVat")</div> 608 </div> 609 } 610 611 @if (halfPrice != "0") 612 { 613 if (halfPrice.Contains(",")) 614 { 615 string[] sp = halfPrice.Split(','); 616 617 if (sp[1].Length == 1) 618 { 619 halfPrice += "0"; 620 } 621 } 622 else 623 { 624 halfPrice += ",00"; 625 } 626 627 <div class="product-details__info-price-option"> 628 <div class="product-details__info-price-option-title">@Translate("Translate_ProductPage_PriceUnit_HalfParcel") (@halfParcelAmount @Translate("Translate_Ecom_Piece"))</div> 629 <div class="product-details__info-price-option-price">@halfPrice @priceCurrencySymbol pr. @salesUnit</div> 630 <div class="product-details__info-price-option-vat">@Translate("Translate_Ecom_ExVat")</div> 631 </div> 632 } 633 634 @if (fullPrice != "0") 635 { 636 if (fullPrice.Contains(",")) 637 { 638 string[] sp = fullPrice.Split(','); 639 640 if (sp[1].Length == 1) 641 { 642 fullPrice += "0"; 643 } 644 } 645 else 646 { 647 fullPrice += ",00"; 648 } 649 650 <div class="product-details__info-price-option"> 651 <div class="product-details__info-price-option-title">@Translate("Translate_ProductPage_PriceUnit_CompleteParcel") (@completeParcelAmount @Translate("Translate_Ecom_Piece"))</div> 652 <div class="product-details__info-price-option-price">@fullPrice @priceCurrencySymbol pr. @salesUnit</div> 653 <div class="product-details__info-price-option-vat">@Translate("Translate_Ecom_ExVat")</div> 654 </div> 655 } 656 </div> 657 } 658 } 659 660 <div class="product-details__info-quantity"> 661 @{ 662 if (standardPriceJS == "0" && halfPrice == "0" && fullPrice == "0") 663 { 664 enquireProduct = true; 665 } 666 } 667 @if (totalStock > 0 && isloggedin && !enquireProduct) 668 { 669 <form class="form" action="@(formAction)&Redirect=@(CartPage)" method="post" name="@productId" id="@productId"> 670 <input type="hidden" name="CartCmd" value="addMulti" /> 671 672 @if (isSingleVariant) 673 { 674 <input type="hidden" name="ProductLoopCounter@(loopCounter)" id="ProductLoopCounter@(loopCounter)" value="@loopCounter"> 675 <input type="hidden" name="ProductID@(loopCounter)" id="ProductID@(loopCounter)" value="@productId"> 676 <input type="hidden" name="VariantID@(loopCounter)" id="VariantID@(loopCounter)" value="@singleVariant.VariantId"> 677 } 678 else 679 { 680 @GetString("Ecom:Product.Form.Multi.HiddenFields") 681 } 682 683 <div class="counter"> 684 <a class="substract">-</a> 685 <input name="@inputName" id="Quantity" class="amount" type="tel" value="1"> 686 <label for="Quanity" class="unit">@Translate("Translate_Piece_Short")</label> 687 <a class="add">+</a> 688 </div> 689 <button type="submit" id="product-order-button" class="product-details__info-button btn btn--block btn-secondary">Bestil</button> 690 </form> 691 } 692 else 693 { 694 <a href="#product-inquire-form" id="product-order-button" data-action="open-content" data-target="#enquireForm" class="product-details__info-button btn btn--block btn-secondary">@Translate("Translate_Product_Page_EnquireButton")</a> 695 } 696 </div> 697 698 break; 699 700 case "group126": // Tilbehør 701 702 if (isloggedin) 703 { 704 if (standardPriceJS != "0") 705 { 706 <div class="product-details__info-price-container"> 707 <div class="product-details__info-price-heading"> 708 @Translate("Translate_ProductPage_PriceDefinition_Andet") 709 <span class="tooltip"> 710 <span class="tooltip__icon"> 711 @if (System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/info.svg"))) 712 { 713 @System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/info.svg")) 714 } 715 </span> 716 <span class="tooltip__text tooltip__text--top"> 717 @Translate("Translate_ProductPage_PriceDefinition_Andet_Tooltip") 718 </span> 719 </span> 720 </div> 721 <div class="product-details__info-price-option"> 722 <div class="product-details__info-price-option-price">@standardPrice @priceCurrencySymbol pr. @salesUnit</div> 723 <div class="product-details__info-price-option-vat">@Translate("Translate_Ecom_ExVat")</div> 724 </div> 725 </div> 726 } 727 } 728 729 <div class="product-details__info-quantity"> 730 @{ 731 if (standardPriceJS == "0") 732 { 733 enquireProduct = true; 734 } 735 } 736 @if (totalStock > 0 && isloggedin && !enquireProduct) 737 { 738 <form class="form" action="@(formAction)&Redirect=@(CartPage)" method="post" name="@productId" id="@productId"> 739 <input type="hidden" name="CartCmd" value="addMulti" /> 740 @GetString("Ecom:Product.Form.Multi.HiddenFields") 741 <div class="counter"> 742 <a class="substract">-</a> 743 <input name="@inputName" id="Quantity" class="amount" type="tel" value="1"> 744 <label for="Quanity" class="unit">@Translate("Translate_Piece_Short")</label> 745 <a class="add">+</a> 746 </div> 747 <button type="submit" id="product-order-button" class="product-details__info-button btn btn--block btn-secondary">Bestil</button> 748 </form> 749 } 750 else 751 { 752 <a href="#product-inquire-form" id="product-order-button" data-action="open-content" data-target="#enquireForm" class="product-details__info-button btn btn--block btn-secondary">@Translate("Translate_Product_Page_EnquireButton")</a> 753 } 754 </div> 755 break; 756 757 default: 758 759 <h1>Produkt mangler at få valgt primær gruppe</h1> 760 break; 761 } 762 763 <div class="product-details__info-more"> 764 @switch (productLayout) 765 { 766 case "group52": // Plader 767 case "group66": // Dekorative Overflader 768 case "group126": // Tilbehør 769 var warehouseStock = GetDouble("Ecom:Product.Stock"); 770 var seaStock = int.Parse(GetString("Ecom:Product:Field.ProductPieceOnPurchase.Value").Replace(",", string.Empty)); 771 772 if (isSingleVariant) 773 { 774 warehouseStock = singleVariantStock; 775 seaStock = totalStockSea; 776 } 777 778 string displayWarehouseStock = warehouseStock.ToString("N0"); 779 string displaySeaStock = seaStock.ToString("N0"); 780 781 if (isloggedin) 782 { 783 if (warehouseStock > 500) 784 { 785 displayWarehouseStock = "+500"; 786 } 787 788 if (seaStock > 500) 789 { 790 displaySeaStock = "+500"; 791 } 792 } 793 else 794 { 795 if (warehouseStock > 100) 796 { 797 displayWarehouseStock = "+100"; 798 } 799 800 if (seaStock > 100) 801 { 802 displaySeaStock = "+100"; 803 } 804 } 805 806 if(labelCode.ToLower() != "skaffe" && labelCode.ToLower() != "relatordre") { 807 <div class="product-details__info-stock product-details__info-stock--inline"> 808 <div class="option option--in-house"> 809 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 23.818"> 810 <g class="warehouse" transform="translate(-551.005 -159.082)"> 811 <path class="box box--top" d="M563.005,177.15h-5.25a.75.75,0,0,0-.75.75v4.5a.75.75,0,0,0,.75.75h4.5a.75.75,0,0,0,.75-.75Z" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" /> 812 <path class="box box--bottom-right" d="M568.255,177.15h-5.25v5.25a.75.75,0,0,0,.75.75h4.5a.75.75,0,0,0,.75-.75v-4.5A.75.75,0,0,0,568.255,177.15Z" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" /> 813 <path class="box box--bottom-left" d="M565.255,171.15h-4.5a.75.75,0,0,0-.75.75v5.25h6V171.9A.75.75,0,0,0,565.255,171.15Z" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" /> 814 <path class="building" d="M574.255,183.15v-15.6a1.5,1.5,0,0,0-.794-1.324l-9.75-5.2a1.5,1.5,0,0,0-1.411,0l-9.75,5.2a1.5,1.5,0,0,0-.795,1.324v15.6" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" /> 815 </g> 816 </svg> 817 <span>@Translate("Translate_ProductPage_StockOnWarehouse")</span> @displayWarehouseStock @Translate("Translate_Ecom_Piece") 818 </div> 819 <div class="option option--in-route"> 820 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 16.5"> 821 <g class="truck" transform="translate(-215 -899.75)"> 822 <path class="back" d="M238.25,909.5V902a1.5,1.5,0,0,0-1.5-1.5h-12a1.5,1.5,0,0,0-1.5,1.5v6" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" /> 823 <path class="front" d="M223.25,908v-6h-3a4.5,4.5,0,0,0-4.5,4.5v6a1.5,1.5,0,0,0,1.5,1.5H218" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" /> 824 <path class="window" d="M215.75,908h3a1.5,1.5,0,0,0,1.5-1.5V902" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" /> 825 <path class="wheel wheel--front" d="M222.5,915.5a2.25,2.25,0,1,0-2.25-2.25A2.25,2.25,0,0,0,222.5,915.5Z" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" /> 826 <path class="wheel wheel--back" d="M234.5,915.5a2.25,2.25,0,1,0-2.25-2.25A2.25,2.25,0,0,0,234.5,915.5Z" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" /> 827 <path class="axis" d="M227,914h3" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" /> 828 </g> 829 </svg> 830 <span>@Translate("Translate_ProductPage_StockOnSea")</span> @displaySeaStock @Translate("Translate_Ecom_Piece") 831 </div> 832 </div> 833 } 834 835 break; 836 837 default: 838 if(labelCode.ToLower() != "skaffe" && labelCode.ToLower() != "relatordre") { 839 <a href="#" class="product-details__info-stock product-order-button"> 840 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 23.818"> 841 <g class="warehouse" transform="translate(-551.005 -159.082)"> 842 <path class="box box--top" d="M563.005,177.15h-5.25a.75.75,0,0,0-.75.75v4.5a.75.75,0,0,0,.75.75h4.5a.75.75,0,0,0,.75-.75Z" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" /> 843 <path class="box box--bottom-right" d="M568.255,177.15h-5.25v5.25a.75.75,0,0,0,.75.75h4.5a.75.75,0,0,0,.75-.75v-4.5A.75.75,0,0,0,568.255,177.15Z" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" /> 844 <path class="box box--bottom-left" d="M565.255,171.15h-4.5a.75.75,0,0,0-.75.75v5.25h6V171.9A.75.75,0,0,0,565.255,171.15Z" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" /> 845 <path class="building" d="M574.255,183.15v-15.6a1.5,1.5,0,0,0-.794-1.324l-9.75-5.2a1.5,1.5,0,0,0-1.411,0l-9.75,5.2a1.5,1.5,0,0,0-.795,1.324v15.6" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" /> 846 </g> 847 </svg> 848 849 @Translate("Translate_Product_Page_StockStatus") 850 851 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 19.006 11.031"> 852 <g class="arrow" transform="translate(441 901.014) rotate(180)"> 853 <path class="angle" d="M-17182.074-20447.988l4.809-4.809,4.809,4.809" transform="translate(20875.289 -16281.768) rotate(-90)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" /> 854 <line class="line" x2="17" transform="translate(423.5 895.5)" stroke-linecap="round" stroke-width="1" /> 855 </g> 856 </svg> 857 </a> 858 } 859 break; 860 } 861 862 <div class="product-details__info-delivery"> 863 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 16.5"> 864 <g class="truck" transform="translate(-215 -899.75)"> 865 <path class="back" d="M238.25,909.5V902a1.5,1.5,0,0,0-1.5-1.5h-12a1.5,1.5,0,0,0-1.5,1.5v6" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" /> 866 <path class="front" d="M223.25,908v-6h-3a4.5,4.5,0,0,0-4.5,4.5v6a1.5,1.5,0,0,0,1.5,1.5H218" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" /> 867 <path class="window" d="M215.75,908h3a1.5,1.5,0,0,0,1.5-1.5V902" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" /> 868 <path class="wheel wheel--front" d="M222.5,915.5a2.25,2.25,0,1,0-2.25-2.25A2.25,2.25,0,0,0,222.5,915.5Z" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" /> 869 <path class="wheel wheel--back" d="M234.5,915.5a2.25,2.25,0,1,0-2.25-2.25A2.25,2.25,0,0,0,234.5,915.5Z" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" /> 870 <path class="axis" d="M227,914h3" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" /> 871 </g> 872 </svg> 873 874 @if(labelCode.ToLower() == "skaffe" || labelCode.ToLower() == "relatordre") { 875 @Translate("Translate_Product_Page_DeliveryInformation")<text> </text> @GetString("Ecom:Product:Field.Leveringstid") 876 } else { 877 @Translate("Translate_Product_Page_DeliveryInformation") 878 } 879 880 <span class="tooltip"> 881 <span class="tooltip__icon"> 882 @if (System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/info.svg"))) 883 { 884 @System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/info.svg")) 885 } 886 </span> 887 <span class="tooltip__text tooltip__text--left"> 888 @if(labelCode.ToLower() == "skaffe" || labelCode.ToLower() == "relatordre") { 889 <p>@Translate("Translate_ProductPage_DeliverInfo_Skaffe")</p> 890 } else { 891 <p>@Translate("Translate_ProductPage_DeliveryInfo")</p> 892 } 893 </span> 894 </span> 895 </div> 896 897 898 <a class="product-details__info-reseller" href="https://keflico.com/find-forhandler"> 899 <svg width="800px" height="800px" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg" stroke-width="3" stroke="#000000" fill="none"> 900 <path d="M52,27.18V52.76a2.92,2.92,0,0,1-3,2.84H15a2.92,2.92,0,0,1-3-2.84V27.17"></path> 901 <polyline points="26.26 55.52 26.26 38.45 37.84 38.45 37.84 55.52"></polyline> 902 <path d="M8.44,19.18s-1.1,7.76,6.45,8.94a7.17,7.17,0,0,0,6.1-2A7.43,7.43,0,0,0,32,26a7.4,7.4,0,0,0,5,2.49,11.82,11.82,0,0,0,5.9-2.15,6.66,6.66,0,0,0,4.67,2.15,8,8,0,0,0,7.93-9.3L50.78,9.05a1,1,0,0,0-.94-.65H14a1,1,0,0,0-.94.66Z"></path> 903 <line x1="8.44" y1="19.18" x2="55.54" y2="19.18"></line> 904 <line x1="21.04" y1="19.18" x2="21.04" y2="8.4"></line> 905 <line x1="32.05" y1="19.18" x2="32.05" y2="8.4"></line> 906 <line x1="43.01" y1="19.18" x2="43.01" y2="8.4"></line> 907 </svg> 908 909 @Translate("Translate_Product_Page_Reseller") 910 911 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 19.006 11.031"> 912 <g class="arrow" transform="translate(441 901.014) rotate(180)"> 913 <path class="angle" d="M-17182.074-20447.988l4.809-4.809,4.809,4.809" transform="translate(20875.289 -16281.768) rotate(-90)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" /> 914 <line class="line" x2="17" transform="translate(423.5 895.5)" stroke-linecap="round" stroke-width="1" /> 915 </g> 916 </svg> 917 </a> 918 919 @if (!string.IsNullOrEmpty(configuratorUrl)) 920 { 921 <a class="product-details__info-configurator" href="@configuratorUrl"> 922 <svg width="800px" height="800px" viewBox="0 0 32 32" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="svg820" version="1.1"> 923 <defs id="defs814"> 924 <linearGradient gradientTransform="matrix(1.25 0 0 1.2 -484.714 468.561)" gradientUnits="userSpaceOnUse" y2="520.79797" x2="401.57144" y1="535.79797" x1="401.57144" id="linearGradient4358" xlink:href="#linearGradient4424"></linearGradient> 925 <linearGradient id="linearGradient4424"> 926 <stop style="stop-color:#60a5e7;stop-opacity:0" offset="0" id="stop4426"></stop> 927 <stop style="stop-color:#a6f3fb;stop-opacity:.25773194" offset="1" id="stop4428"></stop> 928 </linearGradient> 929 </defs> 930 <g transform="translate(0 -1090.52)" id="layer1"> 931 <path id="rect2370" transform="translate(0 1090.52)" d="M2 4v24h28V4zm2 2h24v20H4z" style="opacity:1;vector-effect:none;fill:#373737;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:3.20000005;stroke-opacity:1"></path> 932 <path id="path2381" d="M22.424 1100.096a1.996 1.996 0 0 0-2.829 0l-.707.707-7.778 7.778 2.828 2.829 7.779-7.778.707-.708a1.996 1.996 0 0 0 0-2.828zm-12.021 9.192-1.414 4.243 4.242-1.414z" style="fill:#373737;fill-opacity:1;stroke:none;stroke-width:1.26491106px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"></path> 933 </g> 934 </svg> 935 936 @Translate("Translate_Product_Page_Configurator") 937 938 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 19.006 11.031"> 939 <g class="arrow" transform="translate(441 901.014) rotate(180)"> 940 <path class="angle" d="M-17182.074-20447.988l4.809-4.809,4.809,4.809" transform="translate(20875.289 -16281.768) rotate(-90)" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" /> 941 <line class="line" x2="17" transform="translate(423.5 895.5)" stroke-linecap="round" stroke-width="1" /> 942 </g> 943 </svg> 944 </a> 945 } 946 <button id="downloadPdfButton" class="product-details__info-download-pdf"> 947 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"> 948 <g class="download-icon" transform="translate(2 2)"> 949 <path class="arrow" d="M10 0 L10 16 M5 11 L10 16 L15 11" 950 fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> 951 <path class="line" d="M0 20 L20 20" 952 fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/> 953 </g> 954 </svg> 955 Download PDF 956 </button> 957 </div> 958 </div> 959 960 <script> 961 document.addEventListener('DOMContentLoaded', function() { 962 var downloadButton = document.getElementById('downloadPdfButton'); 963 if (downloadButton) { 964 downloadButton.addEventListener('click', function(e) { 965 e.preventDefault(); // Prevent the default action 966 967 // Get the product number and name 968 var productNumber = '@productId'; 969 var productName = '@productName'; 970 971 // Function to replace Danish characters 972 function replaceDanishChars(str) { 973 return str 974 .replace(/æ/g, 'ae') 975 .replace(/ø/g, 'oe') 976 .replace(/å/g, 'aa') 977 .replace(/Æ/g, 'Ae') 978 .replace(/Ø/g, 'Oe') 979 .replace(/Å/g, 'Aa'); 980 } 981 982 // Clean up the product name for use in a filename 983 var cleanProductName = replaceDanishChars(productName) 984 .replace(/[^\w\s-]/g, '') // Remove special characters 985 .trim() // Remove leading and trailing spaces 986 .replace(/\s+/g, '-') // Replace spaces with hyphens 987 .toLowerCase(); // Convert to lowercase 988 989 // Capitalize the first letter of cleanProductName 990 cleanProductName = cleanProductName.charAt(0).toUpperCase() + cleanProductName.slice(1); 991 992 // Construct the filename with _Keflico at the end 993 var filename = `${productNumber}_${cleanProductName}_Keflico.pdf`; 994 995 // Encode the filename for use in a URL 996 var encodedFilename = encodeURIComponent(filename); 997 998 // Navigate to the new URL to trigger the PDF download 999 window.location.href = `/Default.aspx?ID=1243&ProductID=${productNumber}&PDF=True&filename=${encodedFilename}&topBottomMargin=10`; 1000 }); 1001 } 1002 }); 1003 </script> 1004 </article> 1005 <article class="module module-sand product-description"> 1006 <div class="tabs"> 1007 <div class="tabs__nav"> 1008 <ul role="tablist" class="tabs__list" data-action="tabs"> 1009 <li role="none" class="tabs__item"> 1010 <a href="#description" class="tab tab--active" role="tab" id="description-tab" aria-controls="description" aria-selected="true"> 1011 <span class="tabs__item__text--web">@Translate("Translate_Product_Page_ProductDescription")</span> 1012 <span class="tabs__item__text--mobile">@Translate("Translate_Product_Page_ProductDescription_Short")</span> 1013 </a> 1014 </li> 1015 <li role="none" class="tabs__item"> 1016 <a href="#technical" class="tab" role="tab" id="technical-tab" aria-controls="technical" aria-selected="false"> 1017 <span class="tabs__item__text--web">@Translate("Translate_Product_Page_TechnicalSpecifications")</span> 1018 <span class="tabs__item__text--mobile">@Translate("Translate_Product_Page_TechnicalSpecifications_Short")</span> 1019 </a> 1020 </li> 1021 @if (hasNewDownloads) 1022 { 1023 <li role="none" class="tabs__item"> 1024 <a href="#documents" class="tab" role="tab" id="documents-tab" aria-controls="documents" aria-selected="false"> 1025 <span class="tabs__item__text--web">@Translate("Translate_Product_Page_Documents")</span> 1026 <span class="tabs__item__text--mobile">@Translate("Translate_Product_Page_Documents_Short")</span> 1027 </a> 1028 </li> 1029 } 1030 <li role="none" class="tabs__item"> 1031 <a href="#more-info" class="tab" role="tab" id="more-info-tab" aria-controls="more-info" aria-selected="false"> 1032 <span class="tabs__item__text--web">@Translate("Translate_Product_Page_MoreInformation")</span> 1033 <span class="tabs__item__text--mobile">@Translate("Translate_Product_Page_MoreInformation_Short")</span> 1034 </a> 1035 </li> 1036 </ul> 1037 1038 </div> 1039 <div id="description" class="tab__content tab__content--active" role="tabpanel" aria-hidden="false" aria-labelledby="description-tab"> 1040 <h2>@Translate("Translate_Product_Page_ProductDescription")</h2> 1041 <div class="tab__content-wrapper"> 1042 <div class="rich-text"> 1043 <div class="large-text">@GetString("Ecom:Product.LongDescription")</div> 1044 @GetString("Ecom:Product:Field.ProductDescriptionShortLongText.Value") 1045 </div> 1046 1047 @if (hasDownloads) 1048 { 1049 <div class="tab__content-sidebar"> 1050 <strong>@Translate("Translate__Product_Page_Downloads")</strong> 1051 <ul class="tab__content-list"> 1052 @foreach (var fileCat in GetLoop("ImageCategories")) 1053 { 1054 if (fileCat.GetString("Category.SystemName") != "Images") 1055 { 1056 foreach (var file in fileCat.GetLoop("Category.Images")) 1057 { 1058 string fileLink = file.GetString("Ecom:Product:Detail.Image.Clean"); 1059 string fileName = file.GetString("Ecom:Product:Detail.Name"); 1060 1061 if (String.IsNullOrWhiteSpace(fileName)) 1062 { 1063 fileName = Path.GetFileNameWithoutExtension(fileLink); 1064 } 1065 1066 <li> 1067 <a class="swap-link" href="@fileLink" data-link="@fileLink" target="_blank"> 1068 @if (System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/file.svg"))) 1069 { 1070 @System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/file.svg")) 1071 } 1072 @fileName.Replace("-", " ").Replace("_", " ") 1073 </a> 1074 </li> 1075 } 1076 } 1077 } 1078 1079 </ul> 1080 </div> 1081 } 1082 </div> 1083 </div> 1084 <div id="technical" class="tab__content technical-specs" role="tabpanel" aria-hidden="false" aria-labelledby="technical-tab"> 1085 <div class="rich-text"> 1086 <h2>@Translate("Translate_Product_Page_TechnicalSpecifications")</h2> 1087 1088 @{ 1089 CategoryFieldViewModel specs = productViewmodel.FieldDisplayGroups.Values.Where(x => x.Id.ToLower() == "technicalspecifications").FirstOrDefault(); 1090 CategoryFieldViewModel specsWithInfo = productViewmodel.FieldDisplayGroups.Values.Where(x => x.Id.ToLower() == "technicalspecificationswithinfo").FirstOrDefault(); 1091 } 1092 1093 @if (specs != null) 1094 { 1095 <ul class="product-description__technical-list"> 1096 @foreach (var field in specs.Fields.Values) 1097 { 1098 if (field.Type.ToLower() == "list") 1099 { 1100 List<FieldOptionValueViewModel> fieldValue = (List<FieldOptionValueViewModel>)field.Value; 1101 int i = 0; 1102 1103 if (fieldValue.First().Value.ToString() != "-1" && fieldValue.Where(x => x.Name.ToLower() == "ingen").Count() == 0) 1104 { 1105 <li class="product-description__technical-list-item"> 1106 <div class="key">@field.Name</div> 1107 <div class="value"> 1108 <span class="line"> 1109 @foreach (FieldOptionValueViewModel info in fieldValue) 1110 { 1111 if (i > 0) 1112 { 1113 @(", " + info.Name) 1114 } 1115 else 1116 { 1117 @info.Name 1118 } 1119 i++; 1120 } 1121 </span> 1122 </div> 1123 </li> 1124 } 1125 } 1126 else 1127 { 1128 if (field.Value.ToString() != "0" && field.Value.ToString().ToLower() != "ingen") 1129 { 1130 <li class="product-description__technical-list-item"> 1131 @if (field.Name.ToLower() == "number") 1132 { 1133 <div class="key">@Translate("Translate_General_ProductNumber")</div> 1134 } 1135 else if (field.Name.ToLower() == "weight") 1136 { 1137 <div class="key">@Translate("Translate_General_Weight")</div> 1138 } 1139 else 1140 { 1141 <div class="key">@field.Name</div> 1142 } 1143 <div class="value"> 1144 <span class="line">@field.Value</span> 1145 </div> 1146 </li> 1147 } 1148 } 1149 } 1150 </ul> 1151 } 1152 @if (specsWithInfo != null) 1153 { 1154 <ul class="product-description__technical-list"> 1155 @foreach (var field in specsWithInfo.Fields.Values) 1156 { 1157 if (field.Type.ToLower() == "list") 1158 { 1159 List<FieldOptionValueViewModel> fieldValue = (List<FieldOptionValueViewModel>)field.Value; 1160 int i = 0; 1161 1162 if (fieldValue.First().Value.ToString() != "-1" && fieldValue.Where(x => x.Name.ToLower() == "ingen").Count() == 0) 1163 { 1164 <li class="product-description__technical-list-item"> 1165 <div class="key">@field.Name</div> 1166 <div class="value"> 1167 <span class="line with-toolip"> 1168 @foreach (FieldOptionValueViewModel info in fieldValue) 1169 { 1170 if (i > 0) 1171 { 1172 @(", " + info.Name) 1173 } 1174 else 1175 { 1176 @info.Name 1177 } 1178 i++; 1179 } 1180 <span class="tooltip"> 1181 <span class="tooltip__icon"> 1182 @if (System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/info.svg"))) 1183 { 1184 @System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/info.svg")) 1185 } 1186 </span> 1187 <span class="tooltip__text tooltip__text--left"> 1188 <p>@Translate("Translate_Product_Spec_Info_" + field.SystemName)</p> 1189 </span> 1190 </span> 1191 </span> 1192 </div> 1193 </li> 1194 } 1195 } 1196 else 1197 { 1198 if (field.Value.ToString() != "0" && field.Value.ToString().ToLower() != "ingen") 1199 { 1200 <li class="product-description__technical-list-item"> 1201 <div class="key">@field.Name</div> 1202 <div class="value"> 1203 <span class="line with-tooltip"> 1204 @if (field.SystemName.ToLower() == "productdensity") 1205 { 1206 @field.Value.ToString().Replace(",", ".") 1207 } 1208 else 1209 { 1210 @field.Value 1211 } 1212 <span class="tooltip"> 1213 <span class="tooltip__icon"> 1214 @if (System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/info.svg"))) 1215 { 1216 @System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/info.svg")) 1217 } 1218 </span> 1219 <span class="tooltip__text tooltip__text--left"> 1220 <p>@Translate("Translate_Product_Spec_Info_" + field.SystemName)</p> 1221 </span> 1222 </span> 1223 </span> 1224 </div> 1225 </li> 1226 } 1227 } 1228 } 1229 </ul> 1230 } 1231 </div> 1232 </div> 1233 @if (hasNewDownloads) 1234 { 1235 <div id="documents" class="tab__content documents" role="tabpanel" aria-hidden="false" aria-labelledby="documents-tab"> 1236 <div class="rich-text"> 1237 <h2>@Translate("Translate_Product_Page_Documents")</h2> 1238 1239 <ul class="tab__content-list product-description__documents-list"> 1240 @foreach (var fileCat in GetLoop("ImageCategories")) 1241 { 1242 if (fileCat.GetString("Category.SystemName").StartsWith("docView_") && fileCat.GetLoop("Category.Images").Count() > 0) 1243 { 1244 <li class="product-description__documents-list-item"> 1245 <p class="product-description__documents-list-item-title">@fileCat.GetString("Category.Name")</p> 1246 @foreach (var file in fileCat.GetLoop("Category.Images")) 1247 { 1248 string fileLink = file.GetString("Ecom:Product:Detail.Image.Clean"); 1249 string fileName = file.GetString("Ecom:Product:Detail.Name"); 1250 1251 if (String.IsNullOrWhiteSpace(fileName)) 1252 { 1253 fileName = Path.GetFileNameWithoutExtension(fileLink); 1254 } 1255 1256 if (!String.IsNullOrEmpty(fileLink)) 1257 { 1258 <a class="swap-link" href="@fileLink" data-link="@fileLink" target="_blank"> 1259 @GetFileIcon(fileLink) 1260 @fileName.Replace("-", " ").Replace("_", " ") 1261 </a> 1262 } 1263 } 1264 </li> 1265 } 1266 } 1267 </ul> 1268 </div> 1269 </div> 1270 } 1271 1272 <div id="more-info" class="tab__content more-info-content" role="tabpanel" aria-hidden="false" aria-labelledby="more-info-tab"> 1273 <div class="rich-text"> 1274 <h2>@Translate("Translate_Product_Page_MoreInformation")</h2> 1275 @{ 1276 CategoryFieldViewModel moreInfo = productViewmodel.FieldDisplayGroups.Values.Where(x => x.Id.ToLower() == "yderlig_information").FirstOrDefault(); 1277 1278 if (moreInfo != null && moreInfo.Fields != null) 1279 { 1280 var groups = moreInfo.Fields.Values; 1281 1282 foreach (var group in groups) 1283 { 1284 <strong>@Translate("Translate_ProductPage_" + group.SystemName)</strong> 1285 @group.Value 1286 } 1287 } 1288 } 1289 </div> 1290 </div> 1291 1292 </article> 1293 1294 <div id="related-products"> 1295 <article v-if="relatedProducts && relatedProducts.length > 0 && relatedList.length > 0" class="module module-sand-light related-products"> 1296 <div class="rich-text"> 1297 <h2 v-html="relatedGroups.find(x => x.Id == 'RELGRP2').Name"></h2> 1298 </div> 1299 <div class="card-swiper swiper" data-action="async-swiper"> 1300 <div class="swiper-wrapper"> 1301 <div v-for="product in relatedList" :key="product.Id" class="card-swiper__card swiper-slide"> 1302 <picture v-if="product.DefaultImage.Value != ''" class="card-swiper__card-media"> 1303 <source :srcset="productImage(product.DefaultImage.Value, 'lg')" media="(min-width: 1536px)"> 1304 <source :srcset="productImage(product.DefaultImage.Value, 'md')" media="(min-width: 992px)"> 1305 <source :srcset="productImage(product.DefaultImage.Value, 'sm')" media="(min-width: 768px)"> 1306 <img :src="productImage(product.DefaultImage.Value, 'default')" :alt="product.Name"> 1307 </picture> 1308 <div v-else class="card__picture card__picture--dummie"></div> 1309 <div class="card-swiper__card-info"> 1310 <div class="card-swiper__card-preline">@Translate("Translate_Product_Page_ProductNumber"): {{ product.Number }}</div> 1311 <h4 class="card-swiper__card-headline">{{ product.Name }}</h4> 1312 <div class="card-swiper__card-teaser">{{ product.ProductFields.Name2.Value }}</div> 1313 <a class="card-swiper__card-link" :href="'/@(EcomPage)&ProductID=' + product.Id">@Translate("Translate_Product_Page_ProductLink")</a> 1314 </div> 1315 </div> 1316 </div> 1317 <div class="swiper-pagination"></div> 1318 </div> 1319 </article> 1320 <article v-if="relatedProducts && relatedProducts.length > 0 && accessoriesList.length > 0" class="module accessories-products" :class="{ 'module-sand': relatedList.length > 0, 'module-sand-light': relatedList.length == 0}"> 1321 <div class="rich-text"> 1322 <h2 v-html="relatedGroups.find(x => x.Id == 'RELGRP1').Name"></h2> 1323 </div> 1324 <div class="card-swiper swiper" data-action="async-swiper"> 1325 <div class="swiper-wrapper"> 1326 <div v-for="product in accessoriesList" :key="product.Id" class="card-swiper__card swiper-slide"> 1327 <picture v-if="product.DefaultImage.Value != ''" class="card__picture"> 1328 <source :srcset="productImage(product.DefaultImage.Value, 'lg')" media="(min-width: 1536px)"> 1329 <source :srcset="productImage(product.DefaultImage.Value, 'md')" media="(min-width: 992px)"> 1330 <source :srcset="productImage(product.DefaultImage.Value, 'sm')" media="(min-width: 768px)"> 1331 <img :src="productImage(product.DefaultImage.Value, 'default')" :alt="product.Name"> 1332 </picture> 1333 <div v-else class="card__picture card__picture--dummie"></div> 1334 <div class="card-swiper__card-info"> 1335 <div class="card-swiper__card-preline">@Translate("Translate_Product_Page_ProductNumber"): {{ product.Number }}</div> 1336 <h4 class="card-swiper__card-headline">{{ product.Name }}</h4> 1337 <div class="card-swiper__card-teaser">{{ product.ProductFields.Name2.Value }}</div> 1338 <a class="card-swiper__card-link" :href="'/@(EcomPage)&ProductID=' + product.Id">@Translate("Translate_Product_Page_ProductLink")</a> 1339 </div> 1340 </div> 1341 </div> 1342 <div class="swiper-pagination"></div> 1343 </div> 1344 </article> 1345 @RenderItemList(new { 1346 ItemType = "Case", 1347 ListSourceType = "SelfArea", 1348 ItemFieldsList = "Headline,MainImage,Types,WoodTypes", 1349 ListTemplate = "itempublisher/list/productInspiration.cshtml", 1350 ListOrderBy = "Sort", 1351 ListPageSize = 100, 1352 Filter = BuildFilterString(primaryGroup) 1353 }) 1354 </div> 1355 1356 @RenderSnippet("EnquireProductForm") 1357 1358 <div class="product-floating-bar"> 1359 <div class="product-floating-bar__text">@productName @GetString("Ecom:Product:Field.Name2")</div> 1360 @if(totalStock > 0 && isloggedin && !enquireProduct) { 1361 if(primaryGroup == "group1" || primaryGroup == "group32" || primaryGroup == "group73") { 1362 <a class="btn btn-secondary product-floating-bar__button product-order-button">@Translate("Translate_Product_Page_OrderButton")</a> 1363 } else { 1364 <a href="#main" class="btn btn-secondary product-floating-bar__button">@Translate("Translate_Product_Page_OrderButton")</a> 1365 } 1366 } else { 1367 <a data-action="open-content" data-target="#enquireForm" class="btn btn-secondary product-floating-bar__button">@Translate("Translate_Product_Page_EnquireButton")</a> 1368 } 1369 </div> 1370 1371 @SnippetStart("JavaScripts") 1372 <script type="module" async> 1373 import Swiper from 'https://cdn.jsdelivr.net/npm/swiper@8/swiper-bundle.esm.browser.min.js'; 1374 1375 new Vue({ 1376 el: "#related-products", 1377 name: "Related Products", 1378 data() { 1379 return { 1380 relatedGroups: null, 1381 relatedProducts: null, 1382 } 1383 }, 1384 computed: { 1385 relatedList() { 1386 let list = []; 1387 1388 if(this.relatedProducts && this.relatedProducts.length > 0) { 1389 this.relatedProducts.forEach(product => { 1390 if(product.Active && Object.keys(product.PrimaryOrDefaultGroup).length > 0) { 1391 let group = this.relatedGroups.find(x => x.Id == "RELGRP2"); 1392 1393 if(group && group.Products.find(x => x.ProductId == product.Id)) { 1394 list.push(product); 1395 } 1396 } 1397 }) 1398 } 1399 1400 return list; 1401 }, 1402 accessoriesList() { 1403 let list = []; 1404 1405 if(this.relatedProducts && this.relatedProducts.length > 0) { 1406 this.relatedProducts.forEach(product => { 1407 if(product.Active && Object.keys(product.PrimaryOrDefaultGroup).length > 0) { 1408 let group = this.relatedGroups.find(x => x.Id == "RELGRP1"); 1409 1410 if(group && group.Products.find(x => x.ProductId == product.Id)) { 1411 list.push(product); 1412 } 1413 } 1414 }) 1415 } 1416 1417 return list; 1418 } 1419 }, 1420 async mounted() { 1421 await fetch(`/dwapi/ecommerce/products/@(productNumber)`) 1422 .then(response => response.json()) 1423 .then(response => { 1424 this.relatedGroups = response.RelatedGroups; 1425 }) 1426 1427 await fetch(`/dwapi/ecommerce/products/@(productNumber)/related?ShopId=@(Pageview.Area.EcomShopId)`) 1428 .then(response => response.json()) 1429 .then(response => { 1430 if(response.TotalProductsCount > 0) { 1431 this.relatedProducts = response.Products; 1432 } 1433 }) 1434 .catch(error => { 1435 console.log(error) 1436 }) 1437 1438 const productsSliders = document.querySelectorAll('[data-action="async-swiper"]'); 1439 1440 productsSliders.forEach(swiperContainer => { 1441 const productSlider = new Swiper(swiperContainer, { 1442 pagination: { 1443 el: '.swiper-pagination', 1444 type: 'progressbar' 1445 }, 1446 slidesPerView: 'auto', // Slide sizes are controlled with css - not here 1447 speed: 500, 1448 parallax: true, 1449 centeredSlides: false, 1450 }); 1451 }); 1452 }, 1453 methods: { 1454 productImage(path, size) { 1455 let imagePath = "/admin/public/getimage.ashx?Image=" + encodeURIComponent(path); 1456 1457 switch(size) { 1458 case 'lg': 1459 imagePath += '&Width=416&Height=416&Crop=0&Compression=100'; 1460 break; 1461 case 'md': 1462 imagePath += '&Width=310&Height=310&Crop=0&Compression=100'; 1463 break; 1464 case 'sm': 1465 imagePath += '&Width=&230Height=230&Crop=0&Compression=100'; 1466 break; 1467 default: 1468 imagePath += '&Width=560&Height=560&Crop=0&Compression=100'; 1469 break; 1470 } 1471 1472 return imagePath; 1473 } 1474 } 1475 }) 1476 </script> 1477 1478 @SnippetEnd("Javascripts") 1479 1480 @if(productLayout != "group32" && productLayout != "group73" && productLayout != "group1") { 1481 @SnippetStart("JavaScripts") 1482 <script> 1483 const orderButton = document.getElementById("product-order-button"); 1484 1485 if(orderButton) { 1486 const form = orderButton.closest('form'); 1487 1488 orderButton.addEventListener('click', (event) => { 1489 event.preventDefault(); 1490 1491 const formData = new FormData(form); 1492 const qty = parseInt(formData.get('Quantity1')) 1493 1494 const price = @GetString("Ecom:Product.Discount.Price.PriceWithoutVAT.Value").Replace(",", "."); 1495 const halfPrice = @GetString("Ecom:Product:Field.ProductPriceHalfParcel").Replace(",", ""); 1496 const fullPrice = @GetString("Ecom:Product:Field.ProductPriceCompleteParcel").Replace(",", ""); 1497 1498 const halfParcel = @halfParcelAmount; 1499 const fullParcel = @completeParcelAmount; 1500 1501 const salesUnit = "@salesUnit"; 1502 const productLength = @GetString("Ecom:Product:Field.ProductLengthSale.Value.Raw"); 1503 const lengthUnit = "@GetString("Ecom:Product:Field.ProductLengthUnitCode.Value")"; 1504 1505 let value = 0; 1506 1507 addToValue(qty) 1508 1509 function addToValue(remainingQty) { 1510 if(salesUnit == "m") { 1511 value += remainingQty * (productLength/1000) * price; 1512 } else { 1513 value += remainingQty * price; 1514 } 1515 } 1516 1517 dataLayer.push({ ecommerce: null }); // Clear the previous ecommerce object. 1518 dataLayer.push({ 1519 event: "add_to_cart", 1520 ecommerce: { 1521 currency: "@GetString("Ecom:Product.Currency.Code")", 1522 value: value, 1523 items: [ 1524 { 1525 item_id: "@productNumber", 1526 item_name: "@productName", 1527 quantity: qty 1528 1529 } 1530 ] 1531 } 1532 }); 1533 form.submit() 1534 }); 1535 } 1536 </script> 1537 @SnippetEnd("Javascripts") 1538 } 1539 1540 @if(productLayout == "group32" || productLayout == "group73" || productLayout == "group1") { 1541 <div id="orderFlowApp" class="product-modal" :class="{ 'not-logged-in': !isLoggedIn, 'upsell js-slide-in' : showAccessories || showStep1 }"> 1542 <div v-if="showAccessories" class="product-modal__content product-modal__upsell-section"> 1543 <div class="product-modal__content-top"> 1544 <a href="/" class="navigation__logo"> 1545 @if (System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/keflico_logo.svg"))) 1546 { 1547 <text>@System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/keflico_logo.svg"))</text> 1548 } 1549 </a> 1550 <a href="@CartPage" class="navigation__cart"> 1551 <svg xmlns="http://www.w3.org/2000/svg" width="21.773" height="19.513" viewBox="0 0 21.773 19.513"> 1552 <g transform="translate(0.75 0.75)"> 1553 <path d="M122.747,269.657h9.076a1.359,1.359,0,0,0,1.342-1.148l1.28-5.631a.994.994,0,0,0-.982-1.148h-13.3" transform="translate(-114.186 -258.966)" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/> 1554 <path d="M88.321,247h2.551a.748.748,0,0,1,.724.563l1.973,8.555" transform="translate(-88.321 -247)" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/> 1555 <path d="M115.7,293.281l1.193,4.686h.043" transform="translate(-110.564 -284.597)" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/> 1556 <path d="M125.924,329.157a1.433,1.433,0,1,1-1.433-1.433A1.433,1.433,0,0,1,125.924,329.157Z" transform="translate(-116.54 -312.578)" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/> 1557 <path d="M169.05,329.157a1.433,1.433,0,1,1-1.433-1.433A1.433,1.433,0,0,1,169.05,329.157Z" transform="translate(-151.574 -312.578)" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/> 1558 <line x2="11.102" transform="translate(6.374 13.37)" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/> 1559 </g> 1560 </svg> 1561 <span class="cart-qty" data-count="@cartCount">@cartCount</span> 1562 </a> 1563 <a href="#" class="navigation__return product-modal__back-link" @@click="showAccessories = false"> 1564 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20.006 12.445"> 1565 <g transform="translate(-421.494 -889.275)"> 1566 <path d="M-17182.074-20447.988l4.809-4.809,4.809,4.809" transform="translate(20875.289 -16281.768) rotate(-90)" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/> 1567 <line x2="17" transform="translate(423.5 895.5)" fill="none" stroke="#000" stroke-linecap="round" stroke-width="2" /> 1568 </g> 1569 </svg> 1570 </a> 1571 <div v-if="accessoriesList.length > 0" class="breadcrumbs breadcrumbs--no-seperator"> 1572 <ul class="breadcrumbs__list"> 1573 <li class="breadcrumbs__item">1. Vælg produkter</li> 1574 <li class="breadcrumbs__item active">2. Vælg tilbehør</li> 1575 </ul> 1576 </div> 1577 </div> 1578 <div class="upsell-section__top"> 1579 <h1 class="upsell-section__title" v-html="'@Translate("Translate_OrderFlow_ProductsAdded")'.replace('{0}', '<span>' + productsAdded + '</span>')">Du har lagt <span>{{ productsAdded }}</span> varer i kurven</h1> 1580 <h2 class="upsell-section__subtitle">@Translate("Translate_OrderFlow_UpsellReminder")</h2> 1581 </div> 1582 <div class="upsell-section__card-list"> 1583 1584 <div v-for="(product, index) in accessoriesList" class="upsell-card stock-card" :class="{ active: currentMobileProduct == product.Number, dirty: getQty(product.Number) > 0 }" @@click="toggleBar(product.Number)"> 1585 <div class="counter-amount" v-if="getQty(product.Number) > 0">{{ getQty(product.Number) }}</div> 1586 <div class="upsell__content-info"> 1587 <div class="upsell__content-info-media"> 1588 <a :href="'/@(EcomPage)&ProductID=' + product.Number" target="_blank"> 1589 <img :src="'/admin/public/getimage.ashx?Image=' + product.DefaultImage.Value + '&width=175&height=175&Crop=0&Compression=100'" :alt="product.Name" loading="lazy"> 1590 </a> 1591 </div> 1592 <div class="upsell__content-info-container"> 1593 <div class="product-details__info-meta"> 1594 <ul class="product-details__info-meta-list"> 1595 <li>@Translate("Translate_Product_Page_ProductNumber") {{ product.Number }}</li> 1596 @if(!string.IsNullOrWhiteSpace(GetString("Ecom:Product:Field.ProductDbNumber.Value"))) { 1597 <li>@GetString("Ecom:Product:Field.ProductDbNumber.Name") {{ product.EAN }}</li> 1598 } 1599 </ul> 1600 </div> 1601 <div class="product-details__info-title">{{ product.Name }}</div> 1602 <div class="product-details__info-size">{{ product.ProductFields.Name2.Value }}</div> 1603 <div class="product-details__info-quantity"> 1604 <div class="info-quantity" v-if="product.ProductFields.ProductNumberPerPackage.Value && product.ProductFields.ProductNumberPerPackage.Value > 0">{{ product.ProductFields.ProductNumberPerPackage.Value }} @Translate("Translate_General_Pieces")</div> 1605 <div class="info-price" v-if="product.Price.Price">{{ prettyPrice(product.Price.Price) }} @priceCurrencySymbol</div> 1606 </div> 1607 <div class="product-details__info-actions" v-if="product.Price.Price && product.Price.Price > 0 && !product.VariantInfo.VariantInfo"> 1608 <vue-counter :ref="'accCounter' + product.Number" :min="0" @@valueupdate="updateAccButton($event, product.Number)"></vue-counter> 1609 <a href="#" class="confirm disabled" :ref="'confirmBtn' + product.Number" @@click="addAcc($event, product.Number)"> 1610 <svg v-if="pickedAcc.find(x => x.id == product.Number)" enable-background="new 0 0 24 24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> 1611 <path fill="currentColor" d="m19.6025 12.6348c-.5586-.085-1.0547.2979-1.1348.8438-.2012 1.3711-.834 2.6221-1.8301 3.6182-2.5352 2.5352-6.6572 2.5332-9.1914 0-2.5337-2.5342-2.5337-6.6577 0-9.1914.9531-.9526 2.1563-1.5737 3.5029-1.7998.5791-.1099 1.2017-.1289 1.8477-.0557.887.1021 1.7126.3964 2.466.8285l-1.3019.2223c-.5439.0933-.9102.6099-.8164 1.1543.083.4873.5059.8315.9844.8315.0557 0 .1123-.0044.1699-.0142l3.4902-.5967c.2607-.0449.4941-.1914.6475-.4082.1533-.2163.2139-.4849.1689-.7466l-.5977-3.4897c-.0918-.5439-.6016-.9082-1.1543-.8169-.5439.0933-.9102.6104-.8164 1.1548l.1573.9185c-.9679-.543-2.0356-.8943-3.17-1.0249-.8496-.0967-1.6738-.0698-2.4282.0747-1.7368.291-3.3149 1.105-4.564 2.354-3.3135 3.3135-3.3135 8.7051 0 12.0195 1.6567 1.6572 3.8335 2.4854 6.0098 2.4854 2.1768 0 4.3525-.8281 6.0098-2.4854 1.3018-1.3018 2.1299-2.9414 2.3945-4.7412.0802-.5469-.2978-1.0548-.8437-1.1348z"/> 1612 </svg> 1613 <svg v-else xmlns="http://www.w3.org/2000/svg" viewBox="0 0 21.773 19.513"> 1614 <g transform="translate(-87.571 -246.25)"> 1615 <g transform="translate(88.321 247)"> 1616 <path d="M122.747,269.657h9.076a1.359,1.359,0,0,0,1.342-1.148l1.28-5.631a.994.994,0,0,0-.982-1.148h-13.3" transform="translate(-114.186 -258.966)" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/> 1617 <path d="M88.321,247h2.551a.748.748,0,0,1,.724.563l1.973,8.555" transform="translate(-88.321 -247)" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/> 1618 <path d="M115.7,293.281l1.193,4.686h.043" transform="translate(-110.564 -284.597)" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/> 1619 <path d="M125.924,329.157a1.433,1.433,0,1,1-1.433-1.433A1.433,1.433,0,0,1,125.924,329.157Z" transform="translate(-116.54 -312.578)" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/> 1620 <path d="M169.05,329.157a1.433,1.433,0,1,1-1.433-1.433A1.433,1.433,0,0,1,169.05,329.157Z" transform="translate(-151.574 -312.578)" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/> 1621 <line x2="11.102" transform="translate(6.374 13.37)" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/> 1622 </g> 1623 </g> 1624 </svg> 1625 </a> 1626 </div> 1627 </div> 1628 </div> 1629 </div> 1630 </div> 1631 <div class="notification-bar"> 1632 <div class="notification-bar__text"> 1633 @Translate("Translate_OrderFlow_HelpText") 1634 <a href="#product-inquire-form" @@click.prevent="openForm" id="product-orderflow-inquire-button" data-action="open-content" data-target="#enquireForm">@Translate("Translate_Product_Page_EnquireButton")</a> 1635 </div> 1636 </div> 1637 <div class="product-modal__content-bottom"></div> 1638 </div> 1639 <div v-if="!showAccessories" class="product-modal__content"> 1640 <div class="product-modal__content-top"> 1641 <a href="/" class="navigation__logo"> 1642 @if (System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/keflico_logo.svg"))) 1643 { 1644 <text>@System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/keflico_logo.svg"))</text> 1645 } 1646 </a> 1647 <a href="@CartPage" class="navigation__cart"> 1648 <svg xmlns="http://www.w3.org/2000/svg" width="21.773" height="19.513" viewBox="0 0 21.773 19.513"> 1649 <g transform="translate(0.75 0.75)"> 1650 <path d="M122.747,269.657h9.076a1.359,1.359,0,0,0,1.342-1.148l1.28-5.631a.994.994,0,0,0-.982-1.148h-13.3" transform="translate(-114.186 -258.966)" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/> 1651 <path d="M88.321,247h2.551a.748.748,0,0,1,.724.563l1.973,8.555" transform="translate(-88.321 -247)" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/> 1652 <path d="M115.7,293.281l1.193,4.686h.043" transform="translate(-110.564 -284.597)" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/> 1653 <path d="M125.924,329.157a1.433,1.433,0,1,1-1.433-1.433A1.433,1.433,0,0,1,125.924,329.157Z" transform="translate(-116.54 -312.578)" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/> 1654 <path d="M169.05,329.157a1.433,1.433,0,1,1-1.433-1.433A1.433,1.433,0,0,1,169.05,329.157Z" transform="translate(-151.574 -312.578)" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/> 1655 <line x2="11.102" transform="translate(6.374 13.37)" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"/> 1656 </g> 1657 </svg> 1658 <span class="cart-qty" data-count="@cartCount">@cartCount</span> 1659 </a> 1660 <a href="#" class="navigation__return product-modal__back-link" @@click="showAccessories = false"> 1661 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20.006 12.445"> 1662 <g transform="translate(-421.494 -889.275)"> 1663 <path d="M-17182.074-20447.988l4.809-4.809,4.809,4.809" transform="translate(20875.289 -16281.768) rotate(-90)" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/> 1664 <line x2="17" transform="translate(423.5 895.5)" fill="none" stroke="#000" stroke-linecap="round" stroke-width="2" /> 1665 </g> 1666 </svg> 1667 </a> 1668 <div v-if="accessoriesList.length > 0" class="breadcrumbs breadcrumbs--no-seperator"> 1669 <ul class="breadcrumbs__list"> 1670 <li class="breadcrumbs__item active">1. Vælg produkter</li> 1671 <li class="breadcrumbs__item">2. Vælg tilbehør</li> 1672 </ul> 1673 </div> 1674 </div> 1675 <div class="product-modal__content-info"> 1676 <div class="product-modal__content-info-media"> 1677 <picture v-if="mainProduct.image"> 1678 <img :src="mainProduct.image" :alt="mainProduct.name" loading="lazy"> 1679 </picture> 1680 </div> 1681 <div class="product-modal__content-info-container"> 1682 <div class="product-details__info-meta"> 1683 <ul class="product-details__info-meta-list"> 1684 <li>{{ mainProduct.number }}</li> 1685 @if(!string.IsNullOrWhiteSpace(GetString("Ecom:Product:Field.ProductDbNumber.Value"))) { 1686 <li>{{ mainProduct.dbNumber }}</li> 1687 } 1688 </ul> 1689 </div> 1690 <div class="product-details__info-title">{{ mainProduct.name }}</div> 1691 <div class="product-details__info-size"> 1692 @if(primaryGroup == "group1") { 1693 <text>{{ mainProduct.size }}</text> 1694 } else { 1695 <div class="product-details__info-size-thickness"> 1696 <strong>@Translate("Translate_OrderFlow_Thickness")</strong> 1697 {{ mainProduct.thickness }} {{ thicknessUnit }} 1698 </div> 1699 <div class="product-details__info-size-width"> 1700 <strong>@Translate("Translate_OrderFlow_Width")</strong> 1701 {{ mainProduct.width }} {{ widthUnit }} 1702 </div> 1703 } 1704 </div> 1705 </div> 1706 </div> 1707 <div class="product-modal__content-product-stock"> 1708 @if(primaryGroup == "group1") { 1709 <div class="tabs"> 1710 <div v-if="bundles.length > 0" class="tabs__nav"> 1711 <ul role="tablist" class="tabs__list" data-action="tabs"> 1712 <li role="none" class="tabs__item"> 1713 @Translate("Translate_OrderFlow_Choose_ProductType") 1714 </li> 1715 <li role="none" class="tabs__item"> 1716 <a href="#helbundt" @@click.prevent="showBundles = true;" class="tab" :class="{ 'tab--active': showBundles }" role="tab" id="helbundt-tab" aria-controls="helbundt" aria-selected="true"> 1717 <span>@Translate("Translate_OrderFlow_Bundle")</span> 1718 </a> 1719 </li> 1720 @if(!isBundleOnly) { 1721 <li role="none" class="tabs__item"> 1722 <a href="#anbrud" @@click.prevent="showBundles = false;" class="tab" :class="{ 'tab--active': !showBundles }" role="tab" id="anbrud-tab" aria-controls="anbrud" aria-selected="false"> 1723 <span>@Translate("Translate_OrderFlow_Pieces")</span> 1724 </a> 1725 </li> 1726 } 1727 </ul> 1728 </div> 1729 <div id="helbundt" v-if="bundles.length > 0" class="tab__content" :class="{ 'tab__content--active': showBundles }" role="tabpanel" aria-hidden="false" aria-labelledby="helbundt-tab"> 1730 <div class="product-modal__stock"> 1731 <div class="product-modal__stock-line product-modal__stock-line--header bundle-header"> 1732 <div class="product-modal__stock-cell mobile-cell filler"></div> 1733 <div class="product-modal__stock-cell">@Translate("Translate_OrderFlow_BundleNo")</div> 1734 <div class="product-modal__stock-cell desktop-cell">@Translate("Translate_OrderFlow_Thickness")</div> 1735 <div class="product-modal__stock-cell desktop-cell">@Translate("Translate_OrderFlow_Width")</div> 1736 <div class="product-modal__stock-cell desktop-cell">@Translate("Translate_OrderFlow_Length")</div> 1737 <div v-if="!enquireProduct" class="product-modal__stock-cell desktop-cell">@Translate("Translate_OrderFlow_InStock")</div> 1738 <div v-if="!enquireProduct" class="product-modal__stock-cell"> 1739 @Translate("Translate_OrderFlow_OnWayHome"): 1740 <span v-html="onTheWayHome"></span> 1741 </div> 1742 <div v-if="isLoggedIn && !enquireProduct" class="product-modal__stock-cell product-modal__stock-cell--highlighted">@Translate("Translate_OrderFlow_ChooseAmount")</div> 1743 </div> 1744 <div v-if="!loadingBundles" v-for="bundle in sortedBundles" ref="bundle-line" :key="bundle.bundleNo" :class="{ active: currentMobileProduct == bundle.bundleNo, dirty: getQty(bundle.bundleNo) > 0, expanded: isExpanded(bundle.bundleNo) }" class="product-modal__stock-line stock-card stock-bundle-card" @@click="toggleBar(bundle.bundleNo)"> 1745 <div class="stock-bundle__header"> 1746 <div class="product-modal__stock-cell mobile-cell"> 1747 <div class="cell-radio counter-amount bundle-amount" v-html="getQty(bundle.bundleNo) > 0 ? getQty(bundle.bundleNo) : ''" :data-id="bundle.bundleNo"></div> 1748 </div> 1749 <div class="product-modal__stock-cell"> 1750 <span class="bundle-toggle" @@click="toggleBundle(bundle.bundleNo)"> 1751 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12.446 7.223"> 1752 <path d="M0,0,4.809,4.809,9.617,0" transform="translate(11.031 5.809) rotate(180)" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/> 1753 </svg> 1754 </span> 1755 {{ bundle.bundleNo }} 1756 </div> 1757 <div class="product-modal__stock-cell mobile-cell"></div> 1758 <div class="product-modal__stock-cell mobile-cell"></div> 1759 </div> 1760 <div class="stock-bundle__body"> 1761 <div class="stock-bundle__body-columns"> 1762 <div class="stock-bundle__cell"> 1763 @Translate("Translate_OrderFlow_Dimensions") 1764 </div> 1765 <div class="stock-bundle__cell"> 1766 @Translate("Translate_OrderFlow_InStock") 1767 </div> 1768 </div> 1769 <div v-for="(product, index) in bundle.productsInBundle" class="stock-bundle__stick"> 1770 <div class="stock-bundle__cell mobile-cell"> 1771 <div class="cell-stack"> 1772 @Translate("Translate_OrderFlow_Thickness_Short") {{ product.thickness }} {{ thicknessUnit }} 1773 </div> 1774 <div class="cell-stack"> 1775 @Translate("Translate_OrderFlow_Width_Short") {{ product.width }} {{ widthUnit }} 1776 </div> 1777 <div class="cell-stack"> 1778 @Translate("Translate_OrderFlow_Length_Short") {{ product.length.replace(",", "") }} {{ lenghtUnit }} 1779 </div> 1780 </div> 1781 <div class="stock-bundle__cell desktop-cell">{{ product.thickness }} {{ thicknessUnit }}</div> 1782 <div class="stock-bundle__cell desktop-cell">{{ product.width }} {{ widthUnit }}</div> 1783 <div class="stock-bundle__cell desktop-cell">{{ product.length.replace(",", "") }} {{ lenghtUnit }}</div> 1784 <div v-if="!enquireProduct" class="stock-bundle__cell">{{ product.stock.units > 500 ? '+500' : product.stock.units }} @Translate("Translate_General_Pieces")</div> 1785 <div v-if="!enquireProduct" class="stock-bundle__cell desktop-cell"></div> 1786 <div v-if="isLoggedIn && !enquireProduct" class="stock-bundle__cell product-modal__stock-cell--highlighted desktop-cell"> 1787 <vue-counter v-if="index == 0 && isLoggedIn && !enquireProduct" ref="counter" :min="0" :max="1" @@valueupdate="addBundleToTempCart($event, bundle.bundleNo)" /> 1788 </div> 1789 </div> 1790 </div> 1791 </div> 1792 <div v-if="loadingBundles" class="bundle-loading"> 1793 <span class="loader"></span> 1794 </div> 1795 </div> 1796 </div> 1797 @if(!isBundleOnly) { 1798 <div id="anbrud" class="tab__content" :class="{ 'tab__content--active': !showBundles }" role="tabpanel" aria-hidden="false" aria-labelledby="anbrud-tab"> 1799 <div class="product-modal__stock"> 1800 <div class="product-modal__stock-line product-modal__stock-line--header"> 1801 <div class="product-modal__stock-cell filler mobile-cell" v-if="isLoggedIn && !enquireProduct"></div> 1802 <div class="product-modal__stock-cell mobile-cell">@Translate("Translate_OrderFlow_Dimension")</div> 1803 <div class="product-modal__stock-cell desktop-cell">@Translate("Translate_OrderFlow_Thickness")</div> 1804 <div class="product-modal__stock-cell desktop-cell">@Translate("Translate_OrderFlow_Width")</div> 1805 <div class="product-modal__stock-cell desktop-cell">@Translate("Translate_OrderFlow_Length")</div> 1806 <div v-if="!enquireProduct" class="product-modal__stock-cell">@Translate("Translate_OrderFlow_InStock")</div> 1807 <div v-if="!enquireProduct" class="product-modal__stock-cell"> 1808 @Translate("Translate_OrderFlow_OnWayHome"): 1809 <span v-html="onTheWayHome"></span> 1810 </div> 1811 <div v-if="isLoggedIn && !enquireProduct" class="product-modal__stock-cell product-modal__stock-cell--highlighted">@Translate("Translate_OrderFlow_ChooseAmount")</div> 1812 </div> 1813 <div v-for="(variant, index) in sortedVariants" v-if="variant.stock.warehouse > 0" class="product-modal__stock-line stock-card" :class="{ active: currentMobileProduct == variant.id, dirty: getQty(variant.id) > 0 }" @@click="toggleBar(variant.id)" :key="index"> 1814 <div class="product-modal__stock-cell quantity" v-if="isLoggedIn && !enquireProduct"> 1815 <div class="cell-radio counter-amount" :data-id="variant.id" v-html="getQty(variant.id) > 0 ? getQty(variant.id) : ''"></div> 1816 </div> 1817 <div class="product-modal__stock-cell cell-stack"> 1818 <span class="stack">@Translate("Translate_OrderFlow_Thickness_Short") {{ variant.size.thickness }} {{ thicknessUnit }}</span> 1819 <span class="stack">@Translate("Translate_OrderFlow_Width_Short") {{ variant.size.width }} {{ widthUnit }}</span> 1820 <span class="stack">@Translate("Translate_OrderFlow_Length_Short") {{ variant.size.length }} {{ lenghtUnit }}</span> 1821 </div> 1822 <div class="product-modal__stock-cell desktop-cell">{{ variant.size.thickness }} {{ thicknessUnit }}</div> 1823 <div class="product-modal__stock-cell desktop-cell">{{ variant.size.width }} {{ widthUnit }}</div> 1824 <div class="product-modal__stock-cell desktop-cell">{{ variant.size.length }} {{ lenghtUnit }}</div> 1825 <div v-if="!enquireProduct" class="product-modal__stock-cell">{{ calculateStockLevel(variant.stock.warehouse) }} @Translate("Translate_General_Pieces") </div> 1826 <div v-if="!enquireProduct" class="product-modal__stock-cell"></div> 1827 <div v-if="isLoggedIn && !enquireProduct" class="product-modal__stock-cell product-modal__stock-cell--highlighted" :class="{'out-of-stock': variant.stock.warehouse + variant.stock.pieces == 0 || enquireProduct}"> 1828 <vue-counter v-if="variant.stock.warehouse + variant.stock.purchase > 0 && isLoggedIn && !enquireProduct" ref="counter" :min="0" @@valueupdate="addToTempCart($event, variant.id)" /> 1829 </div> 1830 </div> 1831 </div> 1832 </div> 1833 } 1834 </div> 1835 } else { 1836 <div class="product-modal__stock"> 1837 <div class="product-modal__stock-line product-modal__stock-line--header product-modal__stock-line--terrace"> 1838 <div v-if="isLoggedIn && !enquireProduct" class="product-modal__stock-cell filler mobile-cell"></div> 1839 <div class="product-modal__stock-cell">@Translate("Translate_OrderFlow_Length")</div> 1840 <div class="product-modal__stock-cell">@Translate("Translate_OrderFlow_InStock")</div> 1841 <div class="product-modal__stock-cell">@Translate("Translate_OrderFlow_OnWayHome")</div> 1842 <div v-if="isLoggedIn && !enquireProduct" class="product-modal__stock-cell product-modal__stock-cell--highlighted">@Translate("Translate_OrderFlow_ChooseAmount")</div> 1843 </div> 1844 <div v-for="(variant, index) in sortedVariants" class="product-modal__stock-line stock-card" v-on="variant.stock.pieces > 0 || variant.stock.warehouse > 0 || variant.stock.sea > 0 ? { click: () => toggleBar(variant.id) } : {}" :class="{ 'out-of-stock': variant.stock.pieces == 0 && variant.stock.warehouse == 0 && variant.stock.sea == 0, dirty: getQty(variant.id) > 0, active: variant.id == currentMobileProduct }" :key="index"> 1845 <div v-if="isLoggedIn && !enquireProduct" class="product-modal__stock-cell quantity"> 1846 <div class="cell-radio counter-amount" :data-id="variant.id" v-html="getQty(variant.id) > 0 ? getQty(variant.id) : ''"></div> 1847 </div> 1848 <div class="product-modal__stock-cell">{{ variant.size.length }} {{ lenghtUnit }}</div> 1849 <div class="product-modal__stock-cell">{{ calculateStockLevel(variant.stock.warehouse) }}</div> 1850 @if(primaryGroup == "group73") { 1851 <div class="product-modal__stock-cell">{{ variant.stock.purchase > 0 ? "@Translate("Translate_General_Yes")" : "@Translate("Translate_General_No")" }}</div> 1852 } else { 1853 <div class="product-modal__stock-cell">{{ calculateStockLevel(variant.stock.sea) }}</div> 1854 } 1855 1856 @if(primaryGroup == "group32") { 1857 <div v-if="isLoggedIn && !enquireProduct" class="product-modal__stock-cell product-modal__stock-cell--highlighted" :class="{'out-of-stock': variant.stock.warehouse + variant.stock.sea == 0 || enquireProduct}"> 1858 <vue-counter v-if="variant.stock.warehouse + variant.stock.sea > 0 && isLoggedIn && !enquireProduct" ref="counter" :min="0" @@valueupdate="addToTempCart($event, variant.id)" /> 1859 </div> 1860 } else { 1861 <div v-if="isLoggedIn && !enquireProduct" class="product-modal__stock-cell product-modal__stock-cell--highlighted" :class="{'out-of-stock': variant.stock.warehouse + variant.stock.pieces == 0 || enquireProduct}"> 1862 <vue-counter v-if="variant.stock.warehouse + variant.stock.purchase > 0 && isLoggedIn && !enquireProduct" ref="counter" :min="0" @@valueupdate="addToTempCart($event, variant.id)" /> 1863 </div> 1864 } 1865 </div> 1866 </div> 1867 } 1868 </div> 1869 <div class="notification-bar"> 1870 <div class="notification-bar__text"> 1871 @Translate("Translate_OrderFlow_HelpText") 1872 <a href="#product-inquire-form" id="product-orderflow-inquire-button" data-action="open-content" data-target="#enquireForm">@Translate("Translate_Product_Page_EnquireButton")</a> 1873 </div> 1874 </div> 1875 <div class="product-modal__content-bottom"></div> 1876 </div> 1877 <div class="product-modal__side"> 1878 <div class="product-modal__side-top"> 1879 <a href="#" class="product-modal__back-link" @@click="showAccessories = false"> 1880 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20.006 12.445"> 1881 <g transform="translate(-421.494 -889.275)"> 1882 <path d="M-17182.074-20447.988l4.809-4.809,4.809,4.809" transform="translate(20875.289 -16281.768) rotate(-90)" fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/> 1883 <line x2="17" transform="translate(423.5 895.5)" fill="none" stroke="#fff" stroke-linecap="round" stroke-width="2" /> 1884 </g> 1885 </svg> 1886 @Translate("Translate_ProductFlow_Back") 1887 </a> 1888 <div class="product-modal__basket-icon"> 1889 <span class="icon"></span> 1890 <span class="badge"></span> 1891 </div> 1892 </div> 1893 <div v-if="isLoggedIn && !enquireProduct" class="product-modal__side-basket" :class="{ 'popup--active': showMobileBasket }"> 1894 <div v-if="pickedVariants.length > 0" class="side-basket__product"> 1895 <div class="side-basket__product-head"> 1896 <div class="product-name">{{ mainProduct.name }}</div> 1897 <div class="product-price"> 1898 @if(primaryGroup == "group1") { 1899 <span v-if="!loadingPrice">{{ prettyPrice(priceObject.unitPrice) }} @priceCurrencySymbol / {{ mainProduct.prices.unit.label }}</span> 1900 <span v-if="loadingPrice" class="loader"></span> 1901 } else { 1902 <span v-if="!loadingPrice">{{ prettyPrice(priceObject.unitPrice) }} @priceCurrencySymbol / @Translate("Translate_General_RunningMeters")</span> 1903 <span v-if="loadingPrice" class="loader"></span> 1904 } 1905 </div> 1906 <div class="product-toggle" @@click="toggleState"> 1907 <span class="close">@Translate("Translate_General_Close")</span> 1908 <span class="open">@Translate("Translate_General_Open")</span> 1909 </div> 1910 </div> 1911 <div v-for="(line, index) in sortedPickedVariants" class="side-basket__product-variant"> 1912 @if(primaryGroup == "group1") { 1913 <template v-if="line.bundle"> 1914 <div class="size size__header"> 1915 <strong>@Translate("Translate_OrderFlow_BundleNo") {{ line.bundleNo }}</strong> 1916 </div> 1917 <template v-for="variant in line.productsInBundle"> 1918 <div class="size"> 1919 <template v-if="lenghtUnit == 'mm'"> 1920 {{ variant.thickness.replace(".", ",") }} x {{ variant.width }} x {{ variant.length.replace(",", "") }}mm 1921 </template> 1922 <template v-else> 1923 {{ variant.thickness.replace(".", ",") }}{{ thicknessUnit }} x {{ variant.width }}{{ widthUnit }} x {{ variant.length.replace(",", "") }} {{ lenghtUnit }} 1924 </template> 1925 </div> 1926 <div class="quantity">{{ prettyNumber(variant.stock.units) }} @Translate("Translate_General_Pieces")</div> 1927 </template> 1928 </template> 1929 <template v-else> 1930 <div class="size size__header"> 1931 <strong>@Translate("Translate_OrderFlow_Pieces")</strong> 1932 </div> 1933 <div class="size">{{ line.thickness }} x {{ line.width }} x {{ line.length }}mm</div> 1934 <div class="quantity">{{ prettyNumber(line.qty) }} @Translate("Translate_General_Pieces")</div> 1935 </template> 1936 } else { 1937 <div class="size">{{ mainProduct.thickness }} x {{ mainProduct.width }} x {{ line.length }}mm</div> 1938 <div class="quantity">{{ prettyNumber(line.qty) }} @Translate("Translate_General_Pieces")</div> 1939 } 1940 </div> 1941 <div class="side-basket__product-total"> 1942 <div class="product-meters"> 1943 @Translate("Translate_General_InTotal") 1944 <span v-if="mainProduct.prices.unit.label == 'm²' || mainProduct.prices.unit.label == 'm'">{{ prettyNumber(calculateMeters()) }} {{ mainProduct.prices.unit.label }}</span> 1945 <span v-else>{{ prettyNumber(calculatePieces()) }} @Translate("Translate_General_Pieces")</span> 1946 </div> 1947 <div class="product-square-meters"> 1948 @Translate("Translate_General_TranslatesTo") 1949 <span v-if="mainProduct.prices.unit.label == 'm²' || mainProduct.prices.unit.label == 'm'">{{ prettyNumber(calculateSquareMeters()) }} m<sup>2</sup></span> 1950 <span v-else-if="mainProduct.prices.unit.label == 'm³'">{{ prettyNumber(calculateCubicMeters(), 3) }} m<sup>3</sup></span> 1951 <span v-else-if="mainProduct.prices.unit.label == 'kbf'">{{ prettyNumber(calculateCubicFeet()) }} kbf</span> 1952 </div> 1953 </div> 1954 </div> 1955 <div v-for="product in pickedAcc" class="side-basket__product"> 1956 <div class="side-basket__product-head"> 1957 <div class="product-name">{{ product.name }}</div> 1958 <div class="product-price">{{ prettyPrice(product.price.unitPrice) }}</div> 1959 <div class="product-toggle" @@click="toggleState"> 1960 <span class="close">@Translate("Translate_General_Close")</span> 1961 <span class="open">@Translate("Translate_General_Open")</span> 1962 </div> 1963 </div> 1964 <div class="side-basket__product-variant"> 1965 <div class="size">{{ product.name2 }}</div> 1966 <div class="quantity">{{ product.qty }} @Translate("Translate_General_Pieces")</div> 1967 </div> 1968 </div> 1969 <div class="side-basket__summary"> 1970 <div class="price-raw"> 1971 @Translate("Translate_General_PriceWithoutVat") 1972 <span v-if="!loadingPrice">{{ prettyPrice(priceObject.totalEx) }} @priceCurrencySymbol</span> 1973 <span v-if="loadingPrice" class="loader"></span> 1974 </div> 1975 <div class="vat"> 1976 @Translate("Translate_General_Vat") 1977 <span v-if="!loadingPrice">{{ prettyPrice(priceObject.vat) }} @priceCurrencySymbol</span> 1978 <span v-if="loadingPrice" class="loader"></span> 1979 </div> 1980 <div class="price-vat"> 1981 @Translate("Translate_General_PriceWithVat") 1982 <span v-if="!loadingPrice">{{ prettyPrice(priceObject.totalInc) }} @priceCurrencySymbol</span> 1983 <span v-if="loadingPrice" class="loader"></span> 1984 </div> 1985 </div> 1986 1987 <div v-if="isLoggedIn && !enquireProduct" class="product-modal__floating-cart"> 1988 <div class="floating-cart__bar" :class="{ 'active-bar': showMobileActionBar }"> 1989 <div v-if="showMobileActionControls" class="product-modal__stock-control floating-cart__stock-control counter"> 1990 <button id="amount-subtract" @@click="currentMobileQty > 0 ? currentMobileQty-- : currentMobileQty = 0" class="substract"><span>−</span></button> 1991 <input id="amount-input" @@keyup="editMobileQty" class="amount" pattern="[0-9.]+" type="tel" data-min="0" min="0" :value="currentMobileQty"> 1992 <button id="amount-add" @@click="currentMobileQty++" class="add"><span>+</span></button> 1993 </div> 1994 <div v-if="!showMobileActionControls" @@click="showMobileBasket = !showMobileBasket" class="floating-cart__toggle cart-toggle"> 1995 <span v-if="!showMobileBasket" class="cart-toggle--open">Se kurv</span> 1996 <span v-if="showMobileBasket" class="cart-toggle--close">Luk kurv</span> 1997 </div> 1998 <div class="floating-cart__btn-wrapper"> 1999 <button v-if="currentActiveMobileButton == 'add'" class="btn btn-secondary floating-cart__btn btn--add" :class="{ disabled: currentMobileQty == 0 }" @@click="updateMobileBasket">Tilføj til kurv</button> 2000 <button v-if="currentActiveMobileButton == 'update'" class="btn btn-secondary floating-cart__btn btn--update" :class="{ disabled: (currentMobileQty == 0 && currentActiveMobileButton == 'add') || currentMobileQty == getQty(currentMobileProduct) }" @@click="updateMobileBasket">Opdatér kurv</button> 2001 <button v-if="currentActiveMobileButton == 'next'" class="btn btn-secondary floating-cart__btn btn--next" @@click="addToBasket"> 2002 <template v-if="!loading">Gå videre</template> 2003 <span v-if="loading" class="loader"></span> 2004 </button> 2005 <button v-if="currentActiveMobileButton == 'order' && !showAccessories" class="btn btn-secondary floating-cart__btn btn--order" @@click="addToBasket"> 2006 <template v-if="!loading">Gå til bestilling</template> 2007 <span v-if="loading" class="loader"></span> 2008 </button> 2009 <button v-if="currentActiveMobileButton == 'order' && showAccessories" class="btn btn-secondary floating-cart__btn btn--order" @@click="addAccToBasket"> 2010 <template v-if="!loading">Gå til bestilling</template> 2011 <span v-if="loading" class="loader"></span> 2012 </button> 2013 </div> 2014 </div> 2015 </div> 2016 2017 <div class="side-basket__actions"> 2018 <template v-if="!showAccessories"> 2019 <button type="button" @@click="resetBasket" class="btn btn-link btn-link--underlined" :class="{ disabled: pickedVariants.length == 0 }">@Translate("Translate_General_EmptyCart")</button> 2020 <button type="button" :class="{ disabled: pickedVariants.length == 0 }" @@click="addToBasket" class="btn btn-secondary"> 2021 <template v-if="!loading">@Translate("Translate_General_AddToCart")</template> 2022 <span v-if="loading" class="loader"></span> 2023 </button> 2024 </template> 2025 <template v-else> 2026 <a href="@CartPage" class="btn btn-link btn-link--underlined">@Translate("Translate_General_GoToCheckout")</a> 2027 <button type="button" @@click="addAccToBasket" class="btn btn-secondary" :class="{ disabled: pickedAcc.length == 0}"> 2028 <template v-if="!loading">@Translate("Translate_OrderFlow_AddAccessories")</template> 2029 <span v-if="loading" class="loader"></span> 2030 </button> 2031 </template> 2032 </div> 2033 </div> 2034 </div> 2035 </div> 2036 2037 2038 @SnippetStart("JavaScripts") 2039 <script> 2040 dataLayer.push({ ecommerce: null }); // Clear the previous ecommerce object. 2041 dataLayer.push({ 2042 event: "view_item", 2043 ecommerce: { 2044 items: [ 2045 { 2046 item_id: "@productNumber", 2047 item_name: "@productName", 2048 } 2049 ] 2050 } 2051 }); 2052 2053 </script> 2054 <script async> 2055 const vueCounter = { 2056 name: "VueCounter", 2057 props: ['min', 'max'], 2058 data: () => { 2059 return { 2060 value: 0, 2061 hasError: false, 2062 } 2063 }, 2064 methods: { 2065 substract() { 2066 if(this.min || this.min === 0) { 2067 if(this.value > this.min) { 2068 this.value-- 2069 } else { 2070 this.handleError(); 2071 } 2072 } else { 2073 this.value-- 2074 } 2075 }, 2076 add() { 2077 if(this.max) { 2078 if(this.value < this.max) { 2079 this.value++ 2080 } else { 2081 this.handleError(); 2082 } 2083 } else { 2084 this.value++ 2085 } 2086 }, 2087 handleError() { 2088 this.hasError = true; 2089 setTimeout(() => { 2090 this.hasError = false; 2091 }, 1000); 2092 } 2093 }, 2094 watch: { 2095 value(newValue, oldValue) { 2096 this.$emit('valueupdate', newValue) 2097 } 2098 }, 2099 template: `<div class="vue-counter" :class="hasError ? 'counter--error' : ''" > 2100 <a class="counter__sub" @@click="substract">-</a> 2101 <input class="counter__value" type="tel" v-model="value" :disabled="value == max ? true : false"> 2102 <a class="counter__add" @@click="add">+</a> 2103 </div>` 2104 } 2105 2106 new Vue({ 2107 el: '#orderFlowApp', 2108 name: 'Bestillings flow', 2109 components: { 2110 'vue-counter': vueCounter 2111 }, 2112 computed: { 2113 lenghtUnit() { 2114 return this.sizeUnitValues[this.mainProduct.sizeUnits.length]; 2115 }, 2116 widthUnit() { 2117 return this.sizeUnitValues[this.mainProduct.sizeUnits.width]; 2118 }, 2119 thicknessUnit() { 2120 return this.sizeUnitValues[this.mainProduct.sizeUnits.thickness]; 2121 }, 2122 sortedVariants() { 2123 return this.variants.sort((a,b) => { 2124 if (a.length !== b.length) { 2125 return a.length - b.length; 2126 } else if (a.width !== b.width) { 2127 return a.width - b.width; 2128 } else { 2129 return a.thickness - b.thickness; 2130 } 2131 }).filter(x => x.size.length > 0); 2132 }, 2133 sortedBundles() { 2134 let newBundleList = []; 2135 2136 if(this.bundles.length > 0) { 2137 this.bundles.forEach(bundle => { 2138 const index = newBundleList.findIndex(x => x.bundleNo == bundle.bundleNo); 2139 2140 if(parseFloat(bundle.stock.warehouse) > 0) { 2141 if(index > -1) { 2142 newBundleList[index].productsInBundle.push( 2143 { 2144 length: bundle.length, 2145 width: bundle.width, 2146 thickness: bundle.thickness, 2147 stock: bundle.stock 2148 } 2149 ) 2150 } else { 2151 this.toggleBundles.push({ 2152 bundle: bundle.bundleNo, 2153 expanded: true, 2154 }); 2155 newBundleList.push( 2156 { 2157 bundleNo: bundle.bundleNo, 2158 productsInBundle: [ 2159 { 2160 length: bundle.length, 2161 width: bundle.width, 2162 thickness: bundle.thickness, 2163 stock: bundle.stock 2164 } 2165 ] 2166 } 2167 ) 2168 } 2169 } 2170 }) 2171 } 2172 2173 return newBundleList; 2174 }, 2175 sortedPickedVariants() { 2176 return this.pickedVariants.sort((x,y) => x.bundle - y.bundle); 2177 }, 2178 ga4Products() { 2179 let list = []; 2180 2181 this.sortedPickedVariants.forEach(product => { 2182 let productObject = {}; 2183 2184 if(product.bundle) { 2185 productObject.item_name = this.mainProduct.name; 2186 productObject.item_id = product.bundleNo; 2187 productObject.productsInBundle = product.productsInBundle; 2188 } else { 2189 productObject.item_id = product.id, 2190 productObject.item_name = this.mainProduct.name, 2191 productObject.item_variant = product.variantId, 2192 productObject.quantity = product.qty, 2193 productObject.price = this.priceObject.unitPrice 2194 } 2195 2196 list.push(productObject) 2197 }) 2198 2199 return list; 2200 }, 2201 onTheWayHome() { 2202 if(this.variants.filter(x => x.stock.pieces > 0).length > 0) { 2203 return "@Translate("Translate_General_Yes")"; 2204 } 2205 2206 return "@Translate("Translate_General_No")"; 2207 }, 2208 accessoriesList() { 2209 let list = []; 2210 2211 if(this.relatedProducts && this.relatedProducts.length > 0) { 2212 this.relatedProducts.forEach(product => { 2213 let group = this.relatedGroups.find(x => x.Id == "RELGRP1"); 2214 2215 if(group && group.Products.find(x => x.ProductId == product.Id)) { 2216 list.push(product); 2217 } 2218 }) 2219 } 2220 2221 return list; 2222 } 2223 }, 2224 mounted() { 2225 this.getVariants(@(productNumber)) 2226 @if(primaryGroup == "group1") { 2227 <text> 2228 this.lookUpBundle(@(productNumber)); 2229 </text> 2230 } 2231 2232 this.getAccessories(); 2233 2234 if(!this.enquireProduct && this.isLoggedIn) { 2235 this.orderButtonSpinner = setTimeout(() => { 2236 document.querySelector('#product-order-button .loader').style.display = "inline-block"; 2237 }, 3000); 2238 } else { 2239 document.querySelector('#product-order-button .product-order-form-button').style.display = "block"; 2240 } 2241 }, 2242 data() { 2243 return { 2244 isLoggedIn: @isloggedin.ToString().ToLower(), 2245 enquireProduct: @enquireProduct.ToString().ToLower(), 2246 lang: document.querySelector('html').getAttribute('data-lang'), 2247 loading: false, 2248 loadingPrice: false, 2249 loadingBundles: false, 2250 loadingVariants: false, 2251 orderLoader: true, 2252 orderButtonSpinner: null, 2253 timeOut: null, 2254 priceObject: { 2255 unitPrice: 0, 2256 totalEx: 0, 2257 vat: 0, 2258 totalInc: 0, 2259 corePrice: 0 2260 }, 2261 customerNumber: '@GetGlobalValue("Global:Extranet.CustomerNumber")', 2262 sizeUnitValues: { 2263 'ZOLL/00': '@Translate("Translate_Product_SizeUnit_Inch")', 2264 'ZOLL/01': '@Translate("Translate_Product_SizeUnit_Inch")', 2265 'FUß/00': '@Translate("Translate_Product_SizeUnit_Foot")', 2266 'FUß/01': '@Translate("Translate_Product_SizeUnit_Foot")', 2267 'MM/00': '@Translate("Translate_Product_SizeUnit_Millimeter")', 2268 'MM/01': '@Translate("Translate_Product_SizeUnit_Millimeter")' 2269 }, 2270 mainProduct: { 2271 name: '@productName', 2272 id: @productNumber, 2273 number: '@Translate("Translate_Product_Page_ProductNumber"): @productNumber', 2274 dbNumber: '@GetString("Ecom:Product:Field.ProductDbNumber.Name"): @GetString("Ecom:Product:Field.ProductDbNumber.Value")', 2275 width: '@GetString("Ecom:Product:Field.ProductWidthSale.Value.Raw")', 2276 thickness: '@GetString("Ecom:Product:Field.ProductThicknessSale.Value.Raw")', 2277 image: '@GetString("Ecom:Product.ImageDefault.Clean")', 2278 size: @Json.Encode(GetString("Ecom:Product:Field.Name2")), 2279 prices: { 2280 unit: { 2281 code: "@salesUnitCode", 2282 label: "@salesUnit" 2283 }, 2284 standard: @standardPriceJS, 2285 above100: @above100PriceJS, 2286 bundle: @bundlePriceJS 2287 }, 2288 sizeUnits: { 2289 length: '@GetString("Ecom:Product:Field.ProductLengthUnitCode.Value")', 2290 width: '@GetString("Ecom:Product:Field.ProductWidthUnitCode.Value")', 2291 thickness: '@GetString("Ecom:Product:Field.ProductThicknessUnitCode.Value")', 2292 } 2293 }, 2294 relatedGroups: null, 2295 relatedProducts: null, 2296 variants: [], 2297 showAccessories: false, 2298 showStep1: false, 2299 showBundles: false, 2300 bundles: [], 2301 pickedVariants: [], 2302 productsAdded: 0, 2303 pickedAcc: [], 2304 currentMobileProduct: '', 2305 showMobileBasket: false, 2306 showMobileActionBar: false, 2307 showMobileActionControls: false, 2308 currentActiveMobileButton: 'none', 2309 currentMobileQty: 0, 2310 toggleBundles: [], 2311 } 2312 }, 2313 methods: { 2314 doesCookieExist(cookieName) { 2315 const cookies = document.cookie.split('; '); 2316 const cookieExists = cookies.some(cookie => cookie.startsWith(cookieName + '=')); 2317 return cookieExists; 2318 }, 2319 setCookie(name, value, days) { 2320 let expires = ""; 2321 if (days) { 2322 const date = new Date(); 2323 date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); 2324 expires = "; expires=" + date.toUTCString(); 2325 } 2326 document.cookie = name + "=" + (value || "") + expires + "; path=/"; 2327 }, 2328 deleteCookie(name) { 2329 document.cookie = name + '=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;'; 2330 }, 2331 async getAccessories() { 2332 await fetch(`/dwapi/ecommerce/products/@(productNumber)`) 2333 .then(response => response.json()) 2334 .then(response => { 2335 this.relatedGroups = response.RelatedGroups; 2336 }) 2337 2338 await fetch(`/dwapi/ecommerce/products/@(productNumber)/related`) 2339 .then(response => response.json()) 2340 .then(response => { 2341 if(response.TotalProductsCount > 0) { 2342 this.relatedProducts = response.Products; 2343 } 2344 }) 2345 .catch(error => { 2346 console.log(error) 2347 }) 2348 }, 2349 getVariants: async function(productNo, url) { 2350 this.loadingVariants = true; 2351 let requestUrl = `@(VariantsLookup)&ICC_itemId=${productNo}`; 2352 2353 if(url && url != "") { 2354 requestUrl = url; 2355 } 2356 2357 if(!this.isLoggedIn) { 2358 if(requestUrl.indexOf('username') < 0) { 2359 requestUrl += '&username=marketing@keflico.com&password=Keflico100%'; 2360 } 2361 2362 if (!this.doesCookieExist('tempLogin')) { 2363 this.setCookie('tempLogin', true, 1); 2364 } 2365 } 2366 2367 fetch(requestUrl, { 2368 credentials: "same-origin" 2369 }) 2370 .then(response => response.json()) 2371 .then(response => { 2372 if(response.variants && response.variants.length > 0) { 2373 this.variants = this.variants.concat(response.variants); 2374 2375 this.orderLoader = false; 2376 2377 if(response.nextPage != "") { 2378 this.getVariants(productNo, response.nextPage); 2379 } else { 2380 this.loadingVariants = false; 2381 2382 if(!this.isLoggedIn) { 2383 fetch('/Admin/Public/ExtranetLogoff.aspx'); 2384 } 2385 } 2386 } else { 2387 this.loadingVariants = false; 2388 2389 if(!this.loadingBundles) { 2390 clearTimeout(this.orderButtonSpinner); 2391 document.querySelector('#product-order-button .product-order-form-button').style.display = "block"; 2392 document.querySelector('#product-order-button .loader').style.display = "none"; 2393 } 2394 } 2395 }) 2396 }, 2397 lookUpBundle: async function(productNo, url) { 2398 this.loadingBundles = true; 2399 let requestUrl = `@(BundleLookup)&ICC_itemId=${productNo}`; 2400 2401 if(url && url != "") { 2402 requestUrl = url; 2403 } 2404 2405 if(!this.isLoggedIn) { 2406 if(requestUrl.indexOf('username') < 0) { 2407 requestUrl += '&username=marketing@keflico.com&password=Keflico100%'; 2408 } 2409 2410 if (!this.doesCookieExist('tempLogin')) { 2411 this.setCookie('tempLogin', true, 1); 2412 } 2413 } 2414 2415 fetch(requestUrl, { 2416 credentials: "same-origin" 2417 }) 2418 .then(response => response.json()) 2419 .then(response => { 2420 if(response.bundles && response.bundles.length > 0) { 2421 2422 if(response.currentPage = 1) { 2423 this.showBundles = true; 2424 } 2425 2426 this.orderLoader = false; 2427 } else { 2428 if(!this.loadingVariants) { 2429 clearTimeout(this.orderButtonSpinner); 2430 document.querySelector('#product-order-button .product-order-form-button').style.display = "block"; 2431 document.querySelector('#product-order-button .loader').style.display = "none"; 2432 } 2433 } 2434 2435 this.bundles = this.bundles.concat(response.bundles); 2436 2437 if(response.nextPage != "") { 2438 this.lookUpBundle(productNo, response.nextPage); 2439 } else { 2440 this.loadingBundles = false; 2441 2442 if(!this.isLoggedIn) { 2443 fetch('/Admin/Public/ExtranetLogoff.aspx'); 2444 } 2445 } 2446 }) 2447 }, 2448 tempPriceUpdate() { 2449 let totalAccPrice = 0; 2450 2451 this.pickedAcc.forEach(acc => { 2452 totalAccPrice += parseFloat(acc.price.exVat.replace(',', '')) 2453 }) 2454 2455 this.priceObject.totalEx = parseFloat(this.priceObject.corePrice) + totalAccPrice; 2456 this.priceObject.vat = parseFloat(this.priceObject.totalEx) * 0.25; 2457 this.priceObject.totalInc = parseFloat(this.priceObject.totalEx) * 1.25; 2458 }, 2459 priceLookUp: async function() { 2460 let x = 1; 2461 let y = 1; 2462 let queryString = "&ICC_userId=" + this.customerNumber + "&ICC_itemId=" + this.mainProduct.id; 2463 2464 this.pickedVariants.forEach(variant => { 2465 if(variant.bundle) { 2466 queryString += "&ICC_bundle" + y + "=" + variant.bundleNo; 2467 2468 y++; 2469 } else { 2470 queryString += "&ICC_variant" + x + "=" + variant.id; 2471 queryString += "&ICC_quantity" + x + "=" + variant.qty; 2472 2473 x++; 2474 } 2475 }) 2476 2477 fetch(`@(PriceLookup)${queryString}`) 2478 .then(response => response.json()) 2479 .then(response => { 2480 this.priceObject.corePrice = parseFloat(response.totalPriceWithoutVat.replace(",", "")); 2481 this.priceObject.unitPrice = response.unitPrice; 2482 this.priceObject.totalEx = response.totalPriceWithoutVat; 2483 this.priceObject.vat = response.vat; 2484 this.priceObject.totalInc = response.totalPriceWithVat; 2485 2486 this.loadingPrice = false; 2487 }) 2488 }, 2489 toggleBundle(bundleNo) { 2490 this.toggleBundles.find(x => x.bundle == bundleNo).expanded = !this.toggleBundles.find(x => x.bundle == bundleNo).expanded; 2491 }, 2492 isExpanded(bundleNo) { 2493 return this.toggleBundles.find(x => x.bundle == bundleNo).expanded; 2494 }, 2495 getQty(variantId) { 2496 let product = this.pickedVariants.find(x => x.id == variantId || x.bundleNo == variantId); 2497 let acc = this.pickedAcc.find(x => x.id == variantId); 2498 2499 if(product || acc) { 2500 if(product) { 2501 if(product.bundle) { 2502 return 1; 2503 } 2504 2505 return product.qty; 2506 } else { 2507 return acc.qty; 2508 } 2509 } else { 2510 return 0; 2511 } 2512 }, 2513 toggleBar(productId) { 2514 let product = this.accessoriesList.find(x => x.Id == productId); // product is acc 2515 2516 if((product && product.Price.Price && product.Price.Price > 0 && !product.VariantInfo.VariantInfo) || !product) { 2517 if(this.currentMobileProduct != productId) { 2518 this.currentMobileProduct = productId; 2519 this.showMobileActionBar = true; 2520 this.showMobileActionControls = true; 2521 2522 if(this.pickedVariants.find(x => x.id == productId)) { 2523 this.currentActiveMobileButton = 'update'; 2524 this.currentMobileQty = this.pickedVariants.find(x => x.id == productId).qty; 2525 } else if(this.pickedAcc.find(x => x.id == productId)) { 2526 this.currentActiveMobileButton = 'update'; 2527 this.currentMobileQty = this.pickedAcc.find(x => x.id == productId).qty; 2528 } else { 2529 this.currentActiveMobileButton = 'add'; 2530 this.currentMobileQty = 0; 2531 } 2532 } else { 2533 this.currentMobileProduct = ''; 2534 this.showMobileActionControls = false; 2535 2536 if(this.pickedVariants.length == 0) { 2537 this.showMobileActionBar = false; 2538 } 2539 2540 if(this.showAccessories || this.accessoriesList.length == 0) { 2541 this.currentActiveMobileButton = 'order'; 2542 } else { 2543 this.currentActiveMobileButton = 'next'; 2544 } 2545 } 2546 } 2547 }, 2548 addToTempCart(amount, id) { 2549 this.loadingPrice = true; 2550 clearTimeout(this.timeOut); 2551 2552 if(this.pickedVariants.filter(x => x.id == id).length > 0) { 2553 if(amount > 0) { 2554 this.pickedVariants.find(x => x.id == id).qty = amount; 2555 } else { 2556 const index = this.pickedVariants.findIndex(x => x.id == id); 2557 this.pickedVariants.splice(index, 1); 2558 } 2559 } else { 2560 if(amount > 0) { 2561 const data = this.sortedVariants.find(x => x.id == id); 2562 2563 this.pickedVariants.push({ 2564 bundle: false, 2565 id: id, 2566 qty: parseInt(amount), 2567 length: data.size.length, 2568 width: data.size.width, 2569 thickness: data.size.thickness, 2570 variantId: data.id 2571 }); 2572 } 2573 } 2574 2575 if(this.pickedVariants.length > 0) { 2576 this.timeOut = setTimeout(() => { 2577 this.priceLookUp(); 2578 }, 1000); 2579 } else { 2580 this.priceObject.totalEx = 0; 2581 this.priceObject.totalInc = 0; 2582 this.priceObject.vat = 0; 2583 this.priceObject.unitPrice = 0; 2584 2585 this.loadingPrice = false; 2586 } 2587 }, 2588 editMobileQty($event) { 2589 this.currentMobileQty = $event.target.value 2590 }, 2591 updateMobileBasket() { 2592 let productToUpdate = this.sortedVariants.find(x => x.id == this.currentMobileProduct); 2593 2594 if(!productToUpdate) { 2595 productToUpdate = this.sortedBundles.find(x => x.bundleNo == this.currentMobileProduct); 2596 } 2597 2598 if(productToUpdate) { 2599 if(productToUpdate.bundleNo) { 2600 this.addBundleToTempCart(1, this.currentMobileProduct); 2601 } else { 2602 this.addToTempCart(this.currentMobileQty, this.currentMobileProduct); 2603 } 2604 2605 this.showMobileActionControls = false; 2606 this.currentMobileProduct = ''; 2607 2608 if(this.accessoriesList.length == 0) { 2609 this.currentActiveMobileButton = 'order'; 2610 } else { 2611 this.currentActiveMobileButton = 'next'; 2612 } 2613 } else { 2614 productToUpdate = this.accessoriesList.find(x => x.id == this.currentMobileProduct); 2615 2616 this.addAcc(this.currentMobileQty, this.currentMobileProduct); 2617 2618 this.showMobileActionControls = false; 2619 this.currentMobileProduct = ''; 2620 this.currentActiveMobileButton = 'order'; 2621 } 2622 }, 2623 addBundleToTempCart(amount, bundleNo) { 2624 this.loadingPrice = true; 2625 clearTimeout(this.timeOut); 2626 2627 if(amount > 0) { 2628 this.pickedVariants.push({ 2629 bundle: true, 2630 bundleNo: bundleNo, 2631 productsInBundle: this.sortedBundles.filter(x => x.bundleNo == bundleNo)[0].productsInBundle 2632 }) 2633 } else { 2634 const index = this.pickedVariants.findIndex(x => x.bundleNo == bundleNo); 2635 this.pickedVariants.splice(index, 1); 2636 } 2637 2638 if(this.pickedVariants.length > 0) { 2639 this.timeOut = setTimeout(() => { 2640 this.priceLookUp(); 2641 }, 1000); 2642 } else { 2643 this.priceObject.totalEx = 0; 2644 this.priceObject.totalInc = 0; 2645 this.priceObject.vat = 0; 2646 this.priceObject.unitPrice = 0; 2647 2648 this.loadingPrice = false; 2649 } 2650 }, 2651 updateAccButton(amount, productNumber) { 2652 if((amount > 0 && (!this.pickedAcc.find(x => x.id == productNumber) || amount != this.pickedAcc.find(x => x.id == productNumber).qty)) || (this.pickedAcc.find(x => x.id == productNumber) && amount != this.pickedAcc.find(x => x.id == productNumber).qty)) { 2653 this.$refs['confirmBtn' + productNumber][0].classList.remove('disabled') 2654 } else { 2655 this.$refs['confirmBtn' + productNumber][0].classList.add('disabled') 2656 } 2657 }, 2658 addAcc(event, productNumber) { 2659 let product = this.pickedAcc.find(x => x.id == productNumber); 2660 let qty = typeof event == 'number' ? event : this.$refs['accCounter' + productNumber][0].value; 2661 2662 let queryString = `&ICC_userId=${this.customerNumber}&ICC_itemId=${productNumber}&ICC_quantity1=`; 2663 2664 if(product) { 2665 if(qty > 0) { 2666 product.qty = qty; 2667 queryString += product.qty; 2668 } else { 2669 this.pickedAcc.splice(this.pickedAcc.findIndex(x => x.id == product.id), 1); 2670 } 2671 } else { 2672 this.pickedAcc.push({ 2673 id: productNumber, 2674 name: this.accessoriesList.find(x => x.Number == productNumber).Name, 2675 name2: this.accessoriesList.find(x => x.Number == productNumber).ProductFields.Name2.Value, 2676 qty: qty, 2677 price: { 2678 exVat: 0, 2679 vat: 0, 2680 withVat: 0, 2681 unitPrice: 0 2682 } 2683 }) 2684 2685 queryString += qty; 2686 } 2687 2688 if(qty > 0) { 2689 fetch(`/Default.aspx?ID=1115${queryString}`) 2690 .then(response => response.json()) 2691 .then(response => { 2692 if(product) { 2693 product.price.exVat = response.totalPriceWithoutVat; 2694 product.price.vat = response.vat; 2695 product.price.withVat = response.totalPriceWithVat; 2696 product.price.unitPrice = response.unitPrice; 2697 } else { 2698 const newProduct = this.pickedAcc.at(-1); 2699 2700 newProduct.price.exVat = response.totalPriceWithoutVat; 2701 newProduct.price.vat = response.vat; 2702 newProduct.price.withVat = response.totalPriceWithVat; 2703 newProduct.price.unitPrice = response.unitPrice; 2704 } 2705 2706 this.tempPriceUpdate(); 2707 }) 2708 } else { 2709 this.tempPriceUpdate(); 2710 } 2711 2712 this.$refs['confirmBtn' + productNumber][0].classList.add('disabled'); 2713 }, 2714 prettyNumber(number, minDigits) { 2715 return parseFloat(number).toLocaleString(this.lang, { minimumFractionDigits: minDigits ? minDigits : 0 }) 2716 }, 2717 prettyPrice(price) { 2718 let rawPrice = price; 2719 2720 if(typeof price == "string" && (price.split(".").length - 1 > 1 || (price.indexOf(".") == 1 && price.length > 4) || (price.indexOf(".") == 2 && price.length >= 6) || (price.indexOf(".") == 3 && price.length > 6))) { 2721 // Price is over 1000 in danish format 2722 2723 rawPrice = rawPrice.replaceAll(".", ""); 2724 rawPrice = rawPrice.replaceAll(",", "."); 2725 } else if(typeof price == "string" && (price.split(",").length - 1 > 1 || (price.indexOf(",") == 1 && price.length > 4) || (price.indexOf(",") == 2 && price.length >= 6) || (price.indexOf(",") == 3 && price.length > 6))) { 2726 // Price is over 1000 in english format 2727 2728 rawPrice = rawPrice.replaceAll(",", ""); 2729 } 2730 2731 rawPrice = parseFloat(rawPrice); 2732 return rawPrice.toLocaleString(this.lang, { minimumFractionDigits: 2, maximumFractionDigits: 2 } ) 2733 }, 2734 calculateStockLevel(stock) { 2735 if(this.isLoggedIn && stock >= 0) { 2736 return stock > 500 ? '+500' : stock; 2737 } else { 2738 return stock > 100 ? '+100' : stock; 2739 } 2740 2741 return 0; 2742 }, 2743 toggleState($event) { 2744 $event.target.closest('.side-basket__product').classList.toggle('closed'); 2745 }, 2746 openForm(e) { 2747 document.querySelector('.product-modal').classList.remove('js-slide-in'); 2748 2749 const toggleTrigger = e.currentTarget; 2750 const target = document.querySelector(toggleTrigger.getAttribute('data-target')); 2751 2752 if (target) { 2753 disableScrollLock() 2754 history.back(); 2755 2756 if (!target.classList.contains('js-open')) { 2757 toggleTrigger.classList.add('js-open'); 2758 target.classList.add('js-open'); 2759 target.style.height = `${target.scrollHeight}px`; 2760 2761 if (toggleTrigger.getAttribute('data-action-scroll') != 'no-scroll') { 2762 setTimeout(function() { 2763 target.scrollIntoView({behavior: 'smooth'}); 2764 },300); 2765 } 2766 2767 if (target.classList.contains('dialog')) { 2768 document.querySelector('body').style.overflow = 'hidden'; 2769 } 2770 } else { 2771 toggleTrigger.classList.remove('js-open'); 2772 target.classList.remove('js-open'); 2773 target.style.height = null; 2774 2775 if (target.classList.contains('dialog')) { 2776 document.querySelector('body').style.overflow = null; 2777 } 2778 } 2779 } 2780 }, 2781 calculateMeters() { 2782 let meters = 0; 2783 2784 this.pickedVariants.forEach(variant => { 2785 let length = variant['length']; 2786 2787 if(this.mainProduct.sizeUnits.length.indexOf('FUß') > -1) { 2788 length = length * 304.8; 2789 } 2790 2791 let variantMeters = parseFloat(length) * variant.qty / 1000; 2792 meters += variantMeters; 2793 }) 2794 2795 return parseFloat(meters).toFixed(3); 2796 }, 2797 calculatePieces() { 2798 let pieces = 0; 2799 2800 this.pickedVariants.forEach(variant => { 2801 if(variant.bundle) { 2802 variant.productsInBundle.forEach(product => { 2803 pieces += parseInt(product.stock.units); 2804 }) 2805 } else { 2806 pieces += parseInt(variant.qty); 2807 } 2808 }); 2809 2810 return pieces; 2811 }, 2812 calculateSquareMeters() { 2813 return parseFloat(this.calculateMeters() * (this.mainProduct.width / 1000)).toFixed(3); 2814 }, 2815 calculateCubicMeters() { 2816 let cubicMeters = 0; 2817 2818 this.pickedVariants.forEach(variant => { 2819 let variantMeters = 0; 2820 2821 let lengthMultiplier = 1; 2822 let widthMultiplier = 1; 2823 let thicknessMultiplier = 1; 2824 2825 if(this.mainProduct.sizeUnits.length.indexOf('FUß') > -1) { 2826 lengthMultiplier = 304.79999025; 2827 } 2828 2829 if(this.mainProduct.sizeUnits.width.indexOf('ZOLL') > -1) { 2830 widthMultiplier = 25.39998628; 2831 } 2832 2833 if(this.mainProduct.sizeUnits.thickness.indexOf('ZOLL') > -1) { 2834 thicknessMultiplier = 25.39998628 2835 } 2836 2837 if(variant.bundle) { 2838 variant.productsInBundle.forEach(product => { 2839 variantMeters += (parseFloat(product.length.replace(",", "") * lengthMultiplier / 1000) * parseFloat(product.thickness * thicknessMultiplier / 1000) * parseFloat(product.width * widthMultiplier) / 1000) * parseInt(product.stock.units); 2840 }) 2841 } else { 2842 variantMeters += (parseFloat(variant['length'] / 1000) * parseFloat(variant['thickness'] / 1000) * parseFloat(variant['width']) / 1000) * variant.qty; 2843 } 2844 2845 cubicMeters += variantMeters; 2846 }) 2847 2848 return cubicMeters; 2849 }, 2850 calculateCubicFeet() { 2851 let cubicFeet = 0; 2852 2853 this.pickedVariants.forEach(variant => { 2854 let variantMeters = 0; 2855 2856 let lengthMultiplier = 1; 2857 let widthMultiplier = 1; 2858 let thicknessMultiplier = 1; 2859 2860 if(this.mainProduct.sizeUnits.length.indexOf('FUß') > -1) { 2861 lengthMultiplier = 304.79999025; 2862 } 2863 2864 if(this.mainProduct.sizeUnits.width.indexOf('ZOLL') > -1) { 2865 widthMultiplier = 25.39998628; 2866 } 2867 2868 if(this.mainProduct.sizeUnits.thickness.indexOf('ZOLL') > -1) { 2869 thicknessMultiplier = 25.39998628 2870 } 2871 2872 if(variant.bundle) { 2873 variant.productsInBundle.forEach(product => { 2874 let lengthMM = product.length.replace(",", "") * lengthMultiplier; 2875 let lengthM = lengthMM / 1000; 2876 let widthMM = product.width * widthMultiplier; 2877 let widthM = widthMM / 1000; 2878 let thicknessMM = product.thickness * thicknessMultiplier; 2879 let thicknessM = thicknessMM / 1000; 2880 2881 variantMeters += Number(parseFloat(lengthM * widthM * thicknessM * 35.32 * product.stock.units)) 2882 }) 2883 } else { 2884 variantMeters += ((parseFloat(variant['length'] * lengthMultiplier / 1000) * parseFloat(variant['thickness'] * thicknessMultiplier / 1000) * parseFloat(variant['width'] * widthMultiplier / 1000)) * variant.qty); 2885 } 2886 2887 cubicFeet += Number(variantMeters); 2888 }) 2889 2890 return Number(cubicFeet).toFixed(2); 2891 }, 2892 calculateTotalQTY() { 2893 let qty = 0; 2894 2895 this.pickedVariants.forEach(variant => { 2896 qty += variant.qty; 2897 }); 2898 2899 return qty; 2900 }, 2901 resetBasket() { 2902 this.showAccessories = false; 2903 this.pickedVariants = []; 2904 this.showStep1 = true; 2905 this.pickedAcc = []; 2906 this.priceObject.unitPrice = 0; 2907 this.priceObject.totalEx = 0; 2908 this.priceObject.vat = 0; 2909 this.priceObject.totalInc = 0; 2910 this.priceObject.corePrice = 0; 2911 2912 Array.from(this.$refs.counter).forEach(counter => { 2913 counter.value = 0; 2914 }); 2915 }, 2916 async addToBasket() { 2917 this.loading = true; 2918 var params = new FormData(); 2919 2920 params.append('CartCmd', "addMulti") 2921 2922 this.pickedVariants.forEach((variant, index) => { 2923 var productLoopCounter = index + 1; 2924 2925 if(variant.bundle) { 2926 params.append('ProductLoopCounter' + productLoopCounter, productLoopCounter); 2927 params.append('ProductID' + productLoopCounter, this.mainProduct.id); 2928 params.append('Quantity' + productLoopCounter, 1); 2929 params.append('EcomOrderLineFieldInput_BundleNo' + productLoopCounter, variant.bundleNo); 2930 } else { 2931 params.append('ProductLoopCounter' + productLoopCounter, productLoopCounter); 2932 params.append('ProductID' + productLoopCounter, this.mainProduct.id); 2933 params.append('VariantID' + productLoopCounter, variant.variantId); 2934 params.append('Quantity' + productLoopCounter, parseInt(variant.qty)); 2935 } 2936 }) 2937 const config = { 2938 method: 'POST', 2939 body: params 2940 } 2941 2942 this.productsAdded = this.pickedVariants.length; 2943 2944 const response = await fetch('@formAction' + '&redirect=false', config) 2945 2946 if (response.ok) { 2947 dataLayer.push({ ecommerce: null }); // Clear the previous ecommerce object. 2948 dataLayer.push({ 2949 event: "add_to_cart", 2950 ecommerce: { 2951 currency: "@GetString("Ecom:Product.Currency.Code")", 2952 value: this.priceObject.totalEx, 2953 items: this.ga4Products 2954 } 2955 }); 2956 2957 if(this.accessoriesList.length > 0) { 2958 this.showAccessories = true; 2959 this.loading = false; 2960 this.currentActiveMobileButton = 'order'; 2961 } else { 2962 window.location.href = "@formAction"; 2963 } 2964 2965 showStep1 = false; 2966 } else { 2967 console.log(response) 2968 } 2969 }, 2970 async addAccToBasket() { 2971 this.loading = true; 2972 var params = new FormData(); 2973 2974 params.append('CartCmd', "addMulti") 2975 2976 this.pickedAcc.forEach((variant, index) => { 2977 var productLoopCounter = index + 1; 2978 2979 params.append('ProductLoopCounter' + productLoopCounter, productLoopCounter); 2980 params.append('ProductID' + productLoopCounter, variant.id); 2981 params.append('Quantity' + productLoopCounter, variant.qty); 2982 }) 2983 const config = { 2984 method: 'POST', 2985 body: params 2986 } 2987 2988 const response = await fetch('@formAction' + '&redirect=false', config) 2989 2990 if (response.ok) { 2991 window.location.href = "@formAction"; 2992 } else { 2993 console.log(response) 2994 } 2995 } 2996 }, 2997 watch: { 2998 orderLoader(newValue, oldValue) { 2999 if(!newValue && !this.enquireProduct && this.isLoggedIn) { 3000 clearTimeout(this.orderButtonSpinner); 3001 document.querySelector('#product-order-button .product-order-button').style.display = "block"; 3002 document.querySelector('#product-order-button .loader').style.display = "none"; 3003 } 3004 } 3005 } 3006 }); 3007 </script> 3008 @SnippetEnd("JavaScripts") 3009 } 3010 3011 @functions { 3012 private string GetFileIcon(string fileUrl) 3013 { 3014 string extension = Path.GetExtension(fileUrl)?.ToLower(); 3015 3016 if (string.IsNullOrEmpty(extension)) 3017 return System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/file.svg")); 3018 3019 switch (extension) 3020 { 3021 case ".pdf": 3022 return System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/file.svg")); 3023 case ".jpg": 3024 case ".jpeg": 3025 case ".png": 3026 case ".gif": 3027 case ".webp": 3028 return @System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/image.svg")); 3029 default: 3030 return System.IO.File.ReadAllText(System.Web.HttpContext.Current.Server.MapPath("/files/templates/designs/keflico/assets/svg/product/file.svg")); 3031 } 3032 } 3033 3034 public List<string> GetFilters(string GroupId) 3035 { 3036 List<string> filters = new List<string>(); 3037 3038 switch (GroupId) 3039 { 3040 case "group1": 3041 filters.Add("10"); 3042 filters.Add("11"); 3043 break; 3044 case "group32": 3045 filters.Add("17"); 3046 break; 3047 case "group52": 3048 filters.Add("12"); 3049 filters.Add("13"); 3050 filters.Add("14"); 3051 filters.Add("16"); 3052 break; 3053 case "group53": 3054 filters.Add("14"); 3055 break; 3056 case "group56": 3057 filters.Add("16"); 3058 break; 3059 case "group61": 3060 case "group67": 3061 filters.Add("12"); 3062 break; 3063 case "group63": 3064 filters.Add("13"); 3065 break; 3066 case "group73": 3067 filters.Add("18"); 3068 break; 3069 case "group129": 3070 filters.Add("6"); 3071 break; 3072 default: 3073 filters.Add(""); 3074 break; 3075 } 3076 3077 return filters; 3078 } 3079 3080 public string BuildFilterString(string group) { 3081 string filter = ""; 3082 List<string> ids = GetFilters(group); 3083 3084 if(group == "group126") { 3085 3086 } else if(group == "group129") { 3087 foreach(var id in ids) { 3088 filter += filter == "" ? "Types contains \""+id+"\"" : " or Types contains \""+id+"\""; 3089 } 3090 } else { 3091 foreach(var id in ids) { 3092 filter += filter == "" ? "WoodTypes contains \""+id+"\"" : " or WoodTypes contains \""+id+"\""; 3093 } 3094 } 3095 3096 return filter; 3097 } 3098 } 3099